Remove the Value::Block case (#12582)

# Description
`Value` describes the types of first-class values that users and scripts
can create, manipulate, pass around, and store. However, `Block`s are
not first-class values in the language, so this PR removes it from
`Value`. This removes some unnecessary code, and this change should be
invisible to the user except for the change to `scope modules` described
below.

# User-Facing Changes
Breaking change: the output of `scope modules` was changed so that
`env_block` is now `has_env_block` which is a boolean value instead of a
`Block`.

# After Submitting
Update the language guide possibly.
This commit is contained in:
Ian Manske
2024-04-21 05:03:33 +00:00
committed by GitHub
parent 5fd34320e9
commit 3b1d405b96
32 changed files with 171 additions and 352 deletions

View File

@ -7,8 +7,8 @@ use nu_engine::eval_block;
use nu_parser::{flatten_pipeline_element, parse, FlatShape};
use nu_protocol::{
debugger::WithoutDebug,
engine::{EngineState, Stack, StateWorkingSet},
BlockId, PipelineData, Span, Value,
engine::{Closure, EngineState, Stack, StateWorkingSet},
PipelineData, Span, Value,
};
use reedline::{Completer as ReedlineCompleter, Suggestion};
use std::{str, sync::Arc};
@ -63,15 +63,15 @@ impl NuCompleter {
fn external_completion(
&self,
block_id: BlockId,
closure: &Closure,
spans: &[String],
offset: usize,
span: Span,
) -> Option<Vec<SemanticSuggestion>> {
let block = self.engine_state.get_block(block_id);
let block = self.engine_state.get_block(closure.block_id);
let mut callee_stack = self
.stack
.gather_captures(&self.engine_state, &block.captures);
.captures_to_stack_preserve_out_dest(closure.captures.clone());
// Line
if let Some(pos_arg) = block.signature.required_positional.first() {
@ -210,13 +210,10 @@ impl NuCompleter {
// We got no results for internal completion
// now we can check if external completer is set and use it
if let Some(block_id) = config.external_completer {
if let Some(external_result) = self.external_completion(
block_id,
&spans,
fake_offset,
new_span,
) {
if let Some(closure) = config.external_completer.as_ref() {
if let Some(external_result) =
self.external_completion(closure, &spans, fake_offset, new_span)
{
return external_result;
}
}
@ -360,9 +357,9 @@ impl NuCompleter {
}
// Try to complete using an external completer (if set)
if let Some(block_id) = config.external_completer {
if let Some(closure) = config.external_completer.as_ref() {
if let Some(external_result) = self.external_completion(
block_id,
closure,
&spans,
fake_offset,
new_span,

View File

@ -59,24 +59,6 @@ fn get_prompt_string(
})
.ok()
}
Value::Block { val: block_id, .. } => {
let block = engine_state.get_block(block_id);
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
let ret_val = eval_subexpression(engine_state, stack, block, PipelineData::empty());
trace!(
"get_prompt_string (block) {}:{}:{}",
file!(),
line!(),
column!()
);
ret_val
.map_err(|err| {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &err);
})
.ok()
}
Value::String { .. } => Some(PipelineData::Value(v.clone(), None)),
_ => None,
})

View File

@ -1,8 +1,9 @@
pub mod support;
use nu_cli::NuCompleter;
use nu_engine::eval_block;
use nu_parser::parse;
use nu_protocol::engine::StateWorkingSet;
use nu_protocol::{debugger::WithoutDebug, engine::StateWorkingSet, PipelineData};
use reedline::{Completer, Suggestion};
use rstest::{fixture, rstest};
use std::path::PathBuf;
@ -177,7 +178,7 @@ fn dotnu_completions() {
#[ignore]
fn external_completer_trailing_space() {
// https://github.com/nushell/nushell/issues/6378
let block = "let external_completer = {|spans| $spans}";
let block = "{|spans| $spans}";
let input = "gh alias ".to_string();
let suggestions = run_external_completion(block, &input);
@ -847,12 +848,14 @@ fn alias_of_another_alias() {
match_suggestions(expected_paths, suggestions)
}
fn run_external_completion(block: &str, input: &str) -> Vec<Suggestion> {
fn run_external_completion(completer: &str, input: &str) -> Vec<Suggestion> {
let completer = format!("$env.config.completions.external.completer = {completer}");
// Create a new engine
let (dir, _, mut engine_state, mut stack) = new_engine();
let (_, delta) = {
let (block, delta) = {
let mut working_set = StateWorkingSet::new(&engine_state);
let block = parse(&mut working_set, None, block.as_bytes(), false);
let block = parse(&mut working_set, None, completer.as_bytes(), false);
assert!(working_set.parse_errors.is_empty());
(block, working_set.render())
@ -860,16 +863,13 @@ fn run_external_completion(block: &str, input: &str) -> Vec<Suggestion> {
assert!(engine_state.merge_delta(delta).is_ok());
assert!(
eval_block::<WithoutDebug>(&engine_state, &mut stack, &block, PipelineData::Empty).is_ok()
);
// Merge environment into the permanent state
assert!(engine_state.merge_env(&mut stack, &dir).is_ok());
let latest_block_id = engine_state.num_blocks() - 1;
// Change config adding the external completer
let mut config = engine_state.get_config().clone();
config.external_completer = Some(latest_block_id);
engine_state.set_config(config);
// Instantiate a new completer
let mut completer = NuCompleter::new(std::sync::Arc::new(engine_state), stack);