mirror of
https://github.com/nushell/nushell.git
synced 2025-04-12 07:18:19 +02:00
preserve variable capture spans in blocks (#15334)
Closes #15160 # User-Facing Changes Certain "variable not found" errors no longer highlight the surrounding block. Before: ```nushell do { match foo { _ => $in } } Error: nu:🐚:variable_not_found × Variable not found ╭─[entry #1:1:1] 1 │ ╭─▶ do { 2 │ │ match foo { 3 │ │ _ => $in 4 │ │ } 5 │ ├─▶ } · ╰──── variable not found ``` After: ```nushell Error: nu:🐚:variable_not_found × Variable not found ╭─[entry #1:3:10] 2 │ match foo { 3 │ _ => $in · ─┬─ · ╰── variable not found ```
This commit is contained in:
parent
7a6cfa24fc
commit
dd56c813f9
@ -642,17 +642,17 @@ impl Eval for EvalRuntime {
|
||||
.get_block(block_id)
|
||||
.captures
|
||||
.iter()
|
||||
.map(|&id| {
|
||||
.map(|(id, span)| {
|
||||
stack
|
||||
.get_var(id, span)
|
||||
.get_var(*id, *span)
|
||||
.or_else(|_| {
|
||||
engine_state
|
||||
.get_var(id)
|
||||
.get_var(*id)
|
||||
.const_val
|
||||
.clone()
|
||||
.ok_or(ShellError::VariableNotFoundAtRuntime { span })
|
||||
.ok_or(ShellError::VariableNotFoundAtRuntime { span: *span })
|
||||
})
|
||||
.map(|var| (id, var))
|
||||
.map(|var| (*id, var))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
|
@ -857,7 +857,7 @@ fn literal_value(
|
||||
let captures = block
|
||||
.captures
|
||||
.iter()
|
||||
.map(|var_id| get_var(ctx, *var_id, span).map(|val| (*var_id, val)))
|
||||
.map(|(var_id, span)| get_var(ctx, *var_id, *span).map(|val| (*var_id, val)))
|
||||
.collect::<Result<Vec<_>, ShellError>>()?;
|
||||
Value::closure(
|
||||
Closure {
|
||||
|
@ -6589,9 +6589,9 @@ pub fn discover_captures_in_expr(
|
||||
None => {
|
||||
let block = working_set.get_block(block_id);
|
||||
if !block.captures.is_empty() {
|
||||
for capture in &block.captures {
|
||||
for (capture, span) in &block.captures {
|
||||
if !seen.contains(capture) {
|
||||
output.push((*capture, call.head));
|
||||
output.push((*capture, *span));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -6905,8 +6905,7 @@ pub fn parse(
|
||||
&mut captures,
|
||||
) {
|
||||
Ok(_) => {
|
||||
Arc::make_mut(&mut output).captures =
|
||||
captures.into_iter().map(|(var_id, _)| var_id).collect();
|
||||
Arc::make_mut(&mut output).captures = captures;
|
||||
}
|
||||
Err(err) => working_set.error(err),
|
||||
}
|
||||
@ -6961,7 +6960,7 @@ pub fn parse(
|
||||
&& block_id.get() >= working_set.permanent_state.num_blocks()
|
||||
{
|
||||
let block = working_set.get_block_mut(block_id);
|
||||
block.captures = captures.into_iter().map(|(var_id, _)| var_id).collect();
|
||||
block.captures = captures;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub struct Block {
|
||||
pub signature: Box<Signature>,
|
||||
pub pipelines: Vec<Pipeline>,
|
||||
pub captures: Vec<VarId>,
|
||||
pub captures: Vec<(VarId, Span)>,
|
||||
pub redirect_env: bool,
|
||||
/// The block compiled to IR instructions. Not available for subexpressions.
|
||||
pub ir_block: Option<IrBlock>,
|
||||
|
@ -111,7 +111,10 @@ impl Expression {
|
||||
Expr::UnaryNot(expr) => expr.has_in_variable(working_set),
|
||||
Expr::Block(block_id) | Expr::Closure(block_id) => {
|
||||
let block = working_set.get_block(*block_id);
|
||||
block.captures.contains(&IN_VARIABLE_ID)
|
||||
block
|
||||
.captures
|
||||
.iter()
|
||||
.any(|(var_id, _)| var_id == &IN_VARIABLE_ID)
|
||||
|| block
|
||||
.pipelines
|
||||
.iter()
|
||||
|
@ -322,12 +322,12 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gather_captures(&self, engine_state: &EngineState, captures: &[VarId]) -> Stack {
|
||||
pub fn gather_captures(&self, engine_state: &EngineState, captures: &[(VarId, Span)]) -> Stack {
|
||||
let mut vars = Vec::with_capacity(captures.len());
|
||||
|
||||
let fake_span = Span::new(0, 0);
|
||||
|
||||
for capture in captures {
|
||||
for (capture, _) in captures {
|
||||
// Note: this assumes we have calculated captures correctly and that commands
|
||||
// that take in a var decl will manually set this into scope when running the blocks
|
||||
if let Ok(value) = self.get_var(*capture, fake_span) {
|
||||
|
Loading…
Reference in New Issue
Block a user