Protocol: debug_assert!() Span to reflect a valid slice (#6806)

Also enforce this by #[non_exhaustive] span such that going forward we
cannot, in debug builds (1), construct invalid spans.

The motivation for this stems from #6431 where I've seen crashes due to
invalid slice indexing.

My hope is this will mitigate such senarios

1. https://github.com/nushell/nushell/pull/6431#issuecomment-1278147241

# Description

(description of your pull request here)

# Tests

Make sure you've done the following:

- [ ] Add tests that cover your changes, either in the command examples,
the crate/tests folder, or in the /tests folder.
- [ ] Try to think about corner cases and various ways how your changes
could break. Cover them with tests.
- [ ] If adding tests is not possible, please document in the PR body a
minimal example with steps on how to reproduce so one can verify your
change works.

Make sure you've run and fixed any issues with these commands:

- [x] `cargo fmt --all -- --check` to check standard code formatting
(`cargo fmt --all` applies these changes)
- [ ] `cargo clippy --workspace --features=extra -- -D warnings -D
clippy::unwrap_used -A clippy::needless_collect` to check that you're
using the standard code style
- [ ] `cargo test --workspace --features=extra` to check that all the
tests pass

# Documentation

- [ ] If your PR touches a user-facing nushell feature then make sure
that there is an entry in the documentation
(https://github.com/nushell/nushell.github.io) for the feature, and
update it if necessary.
This commit is contained in:
Daniel Buch Hansen
2022-12-03 10:44:12 +01:00
committed by GitHub
parent e6cf18ea43
commit 850ecf648a
36 changed files with 200 additions and 418 deletions

View File

@ -94,10 +94,7 @@ impl CommandCompletion {
value: String::from_utf8_lossy(&x.0).to_string(),
description: x.1,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
});
@ -108,10 +105,7 @@ impl CommandCompletion {
value: String::from_utf8_lossy(&x).to_string(),
description: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
});
@ -128,10 +122,7 @@ impl CommandCompletion {
value: x,
description: None,
extra: None,
span: reedline::Span {
start: span.start - offset,
end: span.end - offset,
},
span: reedline::Span::new(span.start - offset, span.end - offset),
append_whitespace: true,
});
@ -187,10 +178,7 @@ impl Completer for CommandCompletion {
let subcommands = if let Some(last) = last {
self.complete_commands(
working_set,
Span {
start: last.0.start,
end: pos,
},
Span::new(last.0.start, pos),
offset,
false,
options.match_algorithm,

View File

@ -101,14 +101,8 @@ impl NuCompleter {
Ok(pd) => {
let value = pd.into_value(span);
if let Value::List { vals, span: _ } = value {
let result = map_value_completions(
vals.iter(),
Span {
start: span.start,
end: span.end,
},
offset,
);
let result =
map_value_completions(vals.iter(), Span::new(span.start, span.end), offset);
return Some(result);
}
@ -165,15 +159,12 @@ impl NuCompleter {
// Create a new span
let new_span = if flat_idx == 0 {
Span {
start: flat.0.start,
end: flat.0.end - 1 - span_offset,
}
Span::new(flat.0.start, flat.0.end - 1 - span_offset)
} else {
Span {
start: flat.0.start - span_offset,
end: flat.0.end - 1 - span_offset,
}
Span::new(
flat.0.start - span_offset,
flat.0.end - 1 - span_offset,
)
};
// Parses the prefix. Completion should look up to the cursor position, not after.

View File

@ -52,13 +52,13 @@ impl Completer for CustomCompletion {
head: span,
arguments: vec![
Argument::Positional(Expression {
span: Span { start: 0, end: 0 },
span: Span::unknown(),
ty: Type::String,
expr: Expr::String(self.line.clone()),
custom_completion: None,
}),
Argument::Positional(Expression {
span: Span { start: 0, end: 0 },
span: Span::unknown(),
ty: Type::Int,
expr: Expr::Int(line_pos as i64),
custom_completion: None,

View File

@ -111,10 +111,7 @@ impl Completer for VariableCompletion {
&self.engine_state,
&self.stack,
nu_protocol::NU_VARIABLE_ID,
nu_protocol::Span {
start: current_span.start,
end: current_span.end,
},
nu_protocol::Span::new(current_span.start, current_span.end),
) {
for suggestion in
nested_suggestions(nuval, self.var_context.1.clone(), current_span)
@ -134,13 +131,7 @@ impl Completer for VariableCompletion {
// Completion other variable types
if let Some(var_id) = var_id {
// Extract the variable value from the stack
let var = self.stack.get_var(
var_id,
Span {
start: span.start,
end: span.end,
},
);
let var = self.stack.get_var(var_id, Span::new(span.start, span.end));
// If the value exists and it's of type Record
if let Ok(value) = var {
@ -281,7 +272,7 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
// Current sublevel value not found
return Value::Nothing {
span: Span { start: 0, end: 0 },
span: Span::unknown(),
};
}
_ => return val,

View File

@ -76,7 +76,7 @@ pub fn evaluate_repl(
"CMD_DURATION_MS".into(),
Value::String {
val: "0823".to_string(),
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
@ -84,7 +84,7 @@ pub fn evaluate_repl(
"LAST_EXIT_CODE".into(),
Value::Int {
val: 0,
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
@ -375,7 +375,7 @@ pub fn evaluate_repl(
"OLDPWD".into(),
Value::String {
val: cwd.clone(),
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
@ -385,7 +385,7 @@ pub fn evaluate_repl(
"PWD".into(),
Value::String {
val: path.clone(),
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
let cwd = Value::String { val: cwd, span };
@ -440,7 +440,7 @@ pub fn evaluate_repl(
"CMD_DURATION_MS".into(),
Value::String {
val: format!("{}", cmd_duration.as_millis()),
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
@ -997,7 +997,7 @@ fn run_ansi_sequence(seq: &str) -> Result<(), ShellError> {
return Err(ShellError::GenericError(
"Error writing ansi sequence".into(),
err.to_string(),
Some(Span { start: 0, end: 0 }),
Some(Span::unknown()),
None,
Vec::new(),
));
@ -1007,7 +1007,7 @@ fn run_ansi_sequence(seq: &str) -> Result<(), ShellError> {
ShellError::GenericError(
"Error flushing stdio".into(),
e.to_string(),
Some(Span { start: 0, end: 0 }),
Some(Span::unknown()),
None,
Vec::new(),
)

View File

@ -149,7 +149,7 @@ fn split_span_by_highlight_positions(
for pos in highlight_positions {
if start <= *pos && pos < &span.end {
if start < *pos {
result.push((Span { start, end: *pos }, false));
result.push((Span::new(start, *pos), false));
}
let span_str = &line[pos - global_span_offset..span.end - global_span_offset];
let end = span_str
@ -157,18 +157,12 @@ fn split_span_by_highlight_positions(
.next()
.map(|c| pos + get_char_length(c))
.unwrap_or(pos + 1);
result.push((Span { start: *pos, end }, true));
result.push((Span::new(*pos, end), true));
start = end;
}
}
if start < span.end {
result.push((
Span {
start,
end: span.end,
},
false,
));
result.push((Span::new(start, span.end), false));
}
result
}

View File

@ -291,7 +291,7 @@ fn set_last_exit_code(stack: &mut Stack, exit_code: i64) {
"LAST_EXIT_CODE".to_string(),
Value::Int {
val: exit_code,
span: Span { start: 0, end: 0 },
span: Span::unknown(),
},
);
}