Add Span merging functions (#12511)

# Description
This PR adds a few functions to `Span` for merging spans together:
- `Span::append`: merges two spans that are known to be in order.
- `Span::concat`: returns a span that encompasses all the spans in a
slice. The spans must be in order.
- `Span::merge`: merges two spans (no order necessary).
- `Span::merge_many`: merges an iterator of spans into a single span (no
order necessary).

These are meant to replace the free-standing `nu_protocol::span`
function.

The spans in a `LiteCommand` (the `parts`) should always be in order
based on the lite parser and lexer. So, the parser code sees the most
usage of `Span::append` and `Span::concat` where the order is known. In
other code areas, `Span::merge` and `Span::merge_many` are used since
the order between spans is often not known.
This commit is contained in:
Ian Manske
2024-05-16 22:34:49 +00:00
committed by GitHub
parent 2a09dccc11
commit aec41f3df0
15 changed files with 305 additions and 241 deletions

View File

@ -2,7 +2,6 @@ use crate::help::{help_aliases, help_commands, help_modules};
use fancy_regex::Regex;
use nu_ansi_term::Style;
use nu_engine::command_prelude::*;
use nu_protocol::span;
use nu_utils::IgnoreCaseExt;
#[derive(Clone)]
@ -97,9 +96,8 @@ You can also learn more at https://www.nushell.sh/book/"#;
span: _,
}) = result
{
let rest_spans: Vec<Span> = rest.iter().map(|arg| arg.span).collect();
Err(ShellError::NotFound {
span: span(&rest_spans),
span: Span::merge_many(rest.iter().map(|s| s.span)),
})
} else {
result

View File

@ -1,7 +1,6 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, scope::ScopeData};
use nu_protocol::span;
#[derive(Clone)]
pub struct HelpAliases;
@ -110,13 +109,13 @@ pub fn help_aliases(
let Some(alias) = engine_state.find_decl(name.as_bytes(), &[]) else {
return Err(ShellError::AliasNotFound {
span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
span: Span::merge_many(rest.iter().map(|s| s.span)),
});
};
let Some(alias) = engine_state.get_decl(alias).as_alias() else {
return Err(ShellError::AliasNotFound {
span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
span: Span::merge_many(rest.iter().map(|s| s.span)),
});
};

View File

@ -1,7 +1,6 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, get_full_help};
use nu_protocol::span;
#[derive(Clone)]
pub struct HelpCommands;
@ -104,7 +103,7 @@ pub fn help_commands(
)
} else {
Err(ShellError::CommandNotFound {
span: span(&[rest[0].span, rest[rest.len() - 1].span]),
span: Span::merge_many(rest.iter().map(|s| s.span)),
})
}
}

View File

@ -1,7 +1,6 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, get_full_help, scope::ScopeData};
use nu_protocol::span;
#[derive(Clone)]
pub struct HelpExterns;
@ -124,7 +123,7 @@ pub fn help_externs(
)
} else {
Err(ShellError::CommandNotFound {
span: span(&[rest[0].span, rest[rest.len() - 1].span]),
span: Span::merge_many(rest.iter().map(|s| s.span)),
})
}
}

View File

@ -1,7 +1,7 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, scope::ScopeData};
use nu_protocol::{span, DeclId};
use nu_protocol::DeclId;
#[derive(Clone)]
pub struct HelpModules;
@ -117,7 +117,7 @@ pub fn help_modules(
let Some(module_id) = engine_state.find_module(name.as_bytes(), &[]) else {
return Err(ShellError::ModuleNotFoundAtRuntime {
mod_name: name,
span: span(&rest.iter().map(|r| r.span).collect::<Vec<Span>>()),
span: Span::merge_many(rest.iter().map(|s| s.span)),
});
};

View File

@ -1,5 +1,4 @@
use nu_engine::command_prelude::*;
use nu_protocol::span;
use std::io::IsTerminal as _;
#[derive(Clone)]
@ -57,12 +56,9 @@ impl Command for IsTerminal {
});
}
_ => {
let spans: Vec<_> = call.arguments.iter().map(|arg| arg.span()).collect();
let span = span(&spans);
return Err(ShellError::IncompatibleParametersSingle {
msg: "Only one stream may be checked".into(),
span,
span: Span::merge_many(call.arguments.iter().map(|arg| arg.span())),
});
}
};

View File

@ -1,5 +1,4 @@
use nu_engine::command_prelude::*;
use nu_protocol::span;
use std::process::{Command as CommandSys, Stdio};
#[derive(Clone)]
@ -96,7 +95,7 @@ impl Command for Kill {
})?
.span,
right_message: "signal".to_string(),
right_span: span(&[
right_span: Span::merge(
call.get_named_arg("signal")
.ok_or_else(|| ShellError::GenericError {
error: "Flag error".into(),
@ -107,7 +106,7 @@ impl Command for Kill {
})?
.span,
signal_span,
]),
),
});
}
cmd.arg("-9");