Use CommandType in more places (#12832)

# Description
Kind of a vague title, but this PR does two main things:
1. Rather than overriding functions like `Command::is_parser_keyword`,
this PR instead changes commands to override `Command::command_type`.
The `CommandType` returned by `Command::command_type` is then used to
automatically determine whether `Command::is_parser_keyword` and the
other `is_{type}` functions should return true. These changes allow us
to remove the `CommandType::Other` case and should also guarantee than
only one of the `is_{type}` functions on `Command` will return true.
2. Uses the new, reworked `Command::command_type` function in the `scope
commands` and `which` commands.


# User-Facing Changes
- Breaking change for `scope commands`: multiple columns (`is_builtin`,
`is_keyword`, `is_plugin`, etc.) have been merged into the `type`
column.
- Breaking change: the `which` command can now report `plugin` or
`keyword` instead of `built-in` in the `type` column. It may also now
report `external` instead of `custom` in the `type` column for known
`extern`s.
This commit is contained in:
Ian Manske 2024-05-18 23:37:31 +00:00 committed by GitHub
parent 580c60bb82
commit cc9f41e553
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
68 changed files with 224 additions and 217 deletions

View File

@ -42,7 +42,7 @@ For more information on input and keybindings, check:
&Keybindings.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -18,7 +18,7 @@ impl NuHelpCompleter {
//Vec<(Signature, Vec<Example>, bool, bool)> {
let mut commands = full_commands
.iter()
.filter(|(sig, _, _, _, _)| {
.filter(|(sig, _, _)| {
sig.name.to_folded_case().contains(&folded_line)
|| sig.usage.to_folded_case().contains(&folded_line)
|| sig
@ -29,7 +29,7 @@ impl NuHelpCompleter {
})
.collect::<Vec<_>>();
commands.sort_by(|(a, _, _, _, _), (b, _, _, _, _)| {
commands.sort_by(|(a, _, _), (b, _, _)| {
let a_distance = levenshtein_distance(line, &a.name);
let b_distance = levenshtein_distance(line, &b.name);
a_distance.cmp(&b_distance)
@ -37,7 +37,7 @@ impl NuHelpCompleter {
commands
.into_iter()
.map(|(sig, examples, _, _, _)| {
.map(|(sig, examples, _)| {
let mut long_desc = String::new();
let usage = &sig.usage;

View File

@ -35,7 +35,7 @@ impl Command for Dfr {
&Dfr.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for Bits {
&Bits.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -39,7 +39,7 @@ impl Command for Roll {
&Roll.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for Str {
&Str.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Alias;
@ -29,8 +30,8 @@ impl Command for Alias {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn search_terms(&self) -> Vec<&str> {

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Const;
@ -30,8 +31,8 @@ impl Command for Const {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn search_terms(&self) -> Vec<&str> {

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Def;
@ -28,8 +29,8 @@ impl Command for Def {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::{command_prelude::*, get_full_help};
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct ExportCommand;
@ -23,8 +24,8 @@ impl Command for ExportCommand {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(
@ -40,7 +41,7 @@ impl Command for ExportCommand {
&ExportCommand.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct ExportAlias;
@ -29,8 +30,8 @@ impl Command for ExportAlias {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn search_terms(&self) -> Vec<&str> {

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct ExportConst;
@ -30,8 +31,8 @@ impl Command for ExportConst {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct ExportDef;
@ -28,8 +29,8 @@ impl Command for ExportDef {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct ExportExtern;
@ -25,8 +26,8 @@ impl Command for ExportExtern {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct ExportModule;
@ -30,8 +31,8 @@ impl Command for ExportModule {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct ExportUse;
@ -29,8 +30,8 @@ impl Command for ExportUse {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Extern;
@ -25,8 +26,8 @@ impl Command for Extern {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct For;
@ -41,8 +42,8 @@ impl Command for For {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Hide;
@ -31,8 +32,8 @@ This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::{command_prelude::*, get_eval_block};
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Let;
@ -30,8 +31,8 @@ impl Command for Let {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn search_terms(&self) -> Vec<&str> {

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Module;
@ -30,8 +31,8 @@ impl Command for Module {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::{command_prelude::*, get_eval_block};
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Mut;
@ -30,8 +31,8 @@ impl Command for Mut {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn search_terms(&self) -> Vec<&str> {

View File

@ -1,4 +1,5 @@
use nu_engine::{command_prelude::*, get_full_help};
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Overlay;
@ -25,8 +26,8 @@ impl Command for Overlay {
You must use one of the following subcommands. Using this command as-is will only produce this help message."#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(
@ -42,7 +43,7 @@ impl Command for Overlay {
&[],
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct OverlayHide;
@ -35,8 +36,8 @@ impl Command for OverlayHide {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct OverlayNew;
@ -33,8 +34,8 @@ This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -2,7 +2,7 @@ use nu_engine::{
command_prelude::*, find_in_dirs_env, get_dirs_var_from_call, get_eval_block, redirect_env,
};
use nu_parser::trim_quotes_str;
use nu_protocol::ast::Expr;
use nu_protocol::{ast::Expr, engine::CommandType};
use std::path::Path;
@ -50,8 +50,8 @@ impl Command for OverlayUse {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Return;
@ -28,8 +29,8 @@ impl Command for Return {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::{command_prelude::*, get_full_help};
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Scope;
@ -19,8 +20,8 @@ impl Command for Scope {
"Commands for getting info about what is in scope."
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(
@ -36,7 +37,7 @@ impl Command for Scope {
&[],
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,7 +1,10 @@
use nu_engine::{
command_prelude::*, find_in_dirs_env, get_dirs_var_from_call, get_eval_block, redirect_env,
};
use nu_protocol::ast::{Expr, Expression};
use nu_protocol::{
ast::{Expr, Expression},
engine::CommandType,
};
#[derive(Clone)]
pub struct Use;
@ -40,8 +43,8 @@ This command is a parser keyword. For details, check:
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -43,7 +43,7 @@ impl Command for PluginCommand {
&PluginCommand.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct PluginUse;
@ -52,8 +53,8 @@ it was already previously registered with `plugin add`.
vec!["add", "register", "scope"]
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -1,4 +1,5 @@
use nu_engine::command_prelude::*;
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct Register;
@ -48,8 +49,8 @@ This command is a parser keyword. For details, check:
vec!["add"]
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -35,7 +35,7 @@ impl Command for Bytes {
&Bytes.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for Into {
&[],
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for View {
&View.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -55,7 +55,7 @@ impl Command for ViewSource {
}
}
// gets vector of positionals.
else if let Some(block_id) = decl.get_block_id() {
else if let Some(block_id) = decl.block_id() {
let block = engine_state.get_block(block_id);
if let Some(block_span) = block.span {
let contents = engine_state.get_span_contents(block_span);

View File

@ -35,7 +35,7 @@ impl Command for ConfigMeta {
&ConfigMeta.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -172,7 +172,7 @@ impl Command for Open {
match converter {
Some((converter_id, ext)) => {
let decl = engine_state.get_decl(converter_id);
let command_output = if let Some(block_id) = decl.get_block_id() {
let command_output = if let Some(block_id) = decl.block_id() {
let block = engine_state.get_block(block_id);
eval_block(engine_state, stack, block, stream)
} else {

View File

@ -393,7 +393,7 @@ fn convert_to_extension(
) -> Result<PipelineData, ShellError> {
if let Some(decl_id) = engine_state.find_decl(format!("to {extension}").as_bytes(), &[]) {
let decl = engine_state.get_decl(decl_id);
if let Some(block_id) = decl.get_block_id() {
if let Some(block_id) = decl.block_id() {
let block = engine_state.get_block(block_id);
let eval_block = get_eval_block(engine_state);
eval_block(engine_state, stack, block, input)

View File

@ -35,7 +35,7 @@ impl Command for From {
&From.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for To {
&To.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for Hash {
&Self.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,6 +1,7 @@
use crate::help::highlight_search_in_table;
use nu_color_config::StyleComputer;
use nu_engine::{command_prelude::*, get_full_help};
use nu_protocol::engine::CommandType;
#[derive(Clone)]
pub struct HelpCommands;
@ -90,9 +91,15 @@ pub fn help_commands(
let output = engine_state
.get_signatures_with_examples(false)
.iter()
.filter(|(signature, _, _, _, _)| signature.name == name)
.map(|(signature, examples, _, _, is_parser_keyword)| {
get_full_help(signature, examples, engine_state, stack, *is_parser_keyword)
.filter(|(signature, _, _)| signature.name == name)
.map(|(signature, examples, cmd_type)| {
get_full_help(
signature,
examples,
engine_state,
stack,
cmd_type == &CommandType::Keyword,
)
})
.collect::<Vec<String>>();

View File

@ -1,6 +1,7 @@
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::engine::CommandType;
#[derive(Clone)]
pub struct HelpExterns;
@ -110,9 +111,15 @@ pub fn help_externs(
let output = engine_state
.get_signatures_with_examples(false)
.iter()
.filter(|(signature, _, _, _, _)| signature.name == name)
.map(|(signature, examples, _, _, is_parser_keyword)| {
get_full_help(signature, examples, engine_state, stack, *is_parser_keyword)
.filter(|(signature, _, _)| signature.name == name)
.map(|(signature, examples, cmd_type)| {
get_full_help(
signature,
examples,
engine_state,
stack,
cmd_type == &CommandType::Keyword,
)
})
.collect::<Vec<String>>();

View File

@ -35,7 +35,7 @@ impl Command for MathCommand {
&MathCommand.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,4 +1,5 @@
use nu_engine::{command_prelude::*, get_eval_block_with_early_return};
use nu_protocol::engine::CommandType;
/// Source a file for environment variables.
#[derive(Clone)]
@ -29,8 +30,8 @@ impl Command for Source {
https://www.nushell.sh/book/thinking_in_nu.html"#
}
fn is_parser_keyword(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Keyword
}
fn run(

View File

@ -41,7 +41,7 @@ impl Command for Http {
&Http.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -39,7 +39,7 @@ impl Command for Url {
&Url.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -48,7 +48,7 @@ the path literal."#
&PathCommand.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -39,7 +39,7 @@ impl Command for RandomCommand {
&RandomCommand.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for Stor {
&Stor.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for Format {
&Format.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for SplitCommand {
&SplitCommand.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -35,7 +35,7 @@ impl Command for Str {
&Str.examples(),
engine_state,
stack,
self.is_parser_keyword(),
self.is_keyword(),
),
call.head,
)

View File

@ -1,5 +1,5 @@
use log::trace;
use nu_engine::{command_prelude::*, env};
use nu_protocol::engine::CommandType;
use std::{ffi::OsStr, path::Path};
#[derive(Clone)]
@ -51,14 +51,14 @@ impl Command for Which {
fn entry(
arg: impl Into<String>,
path: impl Into<String>,
cmd_type: impl Into<String>,
cmd_type: CommandType,
span: Span,
) -> Value {
Value::record(
record! {
"command" => Value::string(arg.into(), span),
"path" => Value::string(path.into(), span),
"type" => Value::string(cmd_type.into(), span),
"command" => Value::string(arg, span),
"path" => Value::string(path, span),
"type" => Value::string(cmd_type.to_string(), span),
},
span,
)
@ -66,17 +66,8 @@ fn entry(
fn get_entry_in_commands(engine_state: &EngineState, name: &str, span: Span) -> Option<Value> {
if let Some(decl_id) = engine_state.find_decl(name.as_bytes(), &[]) {
let cmd_type = if engine_state.get_decl(decl_id).is_custom_command() {
"custom"
} else if engine_state.get_decl(decl_id).is_alias() {
"alias"
} else {
"built-in"
};
trace!("Found command: {}", name);
Some(entry(name, "", cmd_type, span))
let decl = engine_state.get_decl(decl_id);
Some(entry(name, "", decl.command_type(), span))
} else {
None
}
@ -109,7 +100,7 @@ fn get_first_entry_in_path(
paths: impl AsRef<OsStr>,
) -> Option<Value> {
which::which_in(item, Some(paths), cwd)
.map(|path| entry(item, path.to_string_lossy().to_string(), "external", span))
.map(|path| entry(item, path.to_string_lossy(), CommandType::External, span))
.ok()
}
@ -132,7 +123,7 @@ fn get_all_entries_in_path(
) -> Vec<Value> {
which::which_in_all(&item, Some(paths), cwd)
.map(|iter| {
iter.map(|path| entry(item, path.to_string_lossy().to_string(), "external", span))
iter.map(|path| entry(item, path.to_string_lossy(), CommandType::External, span))
.collect()
})
.unwrap_or_default()

View File

@ -36,10 +36,10 @@ pub fn eval_call<D: DebugContext>(
&decl.examples(),
engine_state,
caller_stack,
decl.is_parser_keyword(),
decl.is_keyword(),
);
Ok(Value::string(full_help, call.head).into_pipeline_data())
} else if let Some(block_id) = decl.get_block_id() {
} else if let Some(block_id) = decl.block_id() {
let block = engine_state.get_block(block_id);
let mut callee_stack = caller_stack.gather_captures(engine_state, &block.captures);

View File

@ -111,13 +111,8 @@ impl<'e, 's> ScopeData<'e, 's> {
"signatures" => self.collect_signatures(&signature, span),
"usage" => Value::string(decl.usage(), span),
"examples" => Value::list(examples, span),
// we can only be a is_builtin or is_custom, not both
"is_builtin" => Value::bool(!decl.is_custom_command(), span),
"type" => Value::string(decl.command_type().to_string(), span),
"is_sub" => Value::bool(decl.is_sub(), span),
"is_plugin" => Value::bool(decl.is_plugin(), span),
"is_custom" => Value::bool(decl.is_custom_command(), span),
"is_keyword" => Value::bool(decl.is_parser_keyword(), span),
"is_extern" => Value::bool(decl.is_known_external(), span),
"creates_scope" => Value::bool(signature.creates_scope, span),
"extra_usage" => Value::string(decl.extra_usage(), span),
"search_terms" => Value::string(decl.search_terms().join(", "), span),

View File

@ -279,7 +279,7 @@ impl LanguageServer {
match id {
Id::Declaration(decl_id) => {
if let Some(block_id) = working_set.get_decl(decl_id).get_block_id() {
if let Some(block_id) = working_set.get_decl(decl_id).block_id() {
let block = working_set.get_block(block_id);
if let Some(span) = &block.span {
for cached_file in working_set.files() {

View File

@ -1,5 +1,8 @@
use nu_engine::command_prelude::*;
use nu_protocol::ast::{Argument, Expr, Expression};
use nu_protocol::{
ast::{Argument, Expr, Expression},
engine::CommandType,
};
#[derive(Clone)]
pub struct KnownExternal {
@ -22,12 +25,8 @@ impl Command for KnownExternal {
&self.usage
}
fn is_known_external(&self) -> bool {
true
}
fn is_builtin(&self) -> bool {
false
fn command_type(&self) -> CommandType {
CommandType::External
}
fn run(

View File

@ -1020,7 +1020,7 @@ pub fn parse_alias(
} => {
let cmd = working_set.get_decl(rhs_call.decl_id);
if cmd.is_parser_keyword()
if cmd.is_keyword()
&& !ALIASABLE_PARSER_KEYWORDS.contains(&cmd.name().as_bytes())
{
working_set.error(ParseError::CantAliasKeyword(

View File

@ -5966,7 +5966,7 @@ pub fn discover_captures_in_expr(
Expr::Bool(_) => {}
Expr::Call(call) => {
let decl = working_set.get_decl(call.decl_id);
if let Some(block_id) = decl.get_block_id() {
if let Some(block_id) = decl.block_id() {
match seen_blocks.get(&block_id) {
Some(capture_list) => {
// Push captures onto the outer closure that aren't created by that outer closure

View File

@ -1,6 +1,6 @@
use nu_engine::{command_prelude::*, get_eval_expression};
use nu_plugin_protocol::{CallInfo, EvaluatedCall};
use nu_protocol::{PluginIdentity, PluginSignature};
use nu_protocol::{engine::CommandType, PluginIdentity, PluginSignature};
use std::sync::Arc;
use crate::{GetPlugin, PluginExecutionCommandContext, PluginSource};
@ -116,8 +116,8 @@ impl Command for PluginDeclaration {
)
}
fn is_plugin(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Plugin
}
fn plugin_identity(&self) -> Option<&PluginIdentity> {

View File

@ -1,6 +1,6 @@
use crate::{
ast::{Call, Expression},
engine::{Command, EngineState, Stack},
engine::{Command, CommandType, EngineState, Stack},
PipelineData, ShellError, Signature,
};
@ -48,8 +48,8 @@ impl Command for Alias {
})
}
fn is_alias(&self) -> bool {
true
fn command_type(&self) -> CommandType {
CommandType::Alias
}
fn as_alias(&self) -> Option<&Alias> {

View File

@ -1,8 +1,8 @@
use crate::{ast::Call, Alias, BlockId, Example, OutDest, PipelineData, ShellError, Signature};
use super::{EngineState, Stack, StateWorkingSet};
use crate::{ast::Call, Alias, BlockId, Example, OutDest, PipelineData, ShellError, Signature};
use std::fmt::Display;
#[derive(Clone, Debug, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommandType {
Builtin,
Custom,
@ -10,7 +10,20 @@ pub enum CommandType {
External,
Alias,
Plugin,
Other,
}
impl Display for CommandType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let str = match self {
CommandType::Builtin => "built-in",
CommandType::Custom => "custom",
CommandType::Keyword => "keyword",
CommandType::External => "external",
CommandType::Alias => "alias",
CommandType::Plugin => "plugin",
};
write!(f, "{str}")
}
}
pub trait Command: Send + Sync + CommandClone {
@ -49,49 +62,29 @@ pub trait Command: Send + Sync + CommandClone {
Vec::new()
}
// This is a built-in command
fn is_builtin(&self) -> bool {
true
// Related terms to help with command search
fn search_terms(&self) -> Vec<&str> {
vec![]
}
// This is a signature for a known external command
fn is_known_external(&self) -> bool {
// Whether can run in const evaluation in the parser
fn is_const(&self) -> bool {
false
}
// This is an alias of another command
fn is_alias(&self) -> bool {
false
}
// Return reference to the command as Alias
fn as_alias(&self) -> Option<&Alias> {
None
}
// This is an enhanced method to determine if a command is custom command or not
// since extern "foo" [] and def "foo" [] behaves differently
fn is_custom_command(&self) -> bool {
if self.get_block_id().is_some() {
true
} else {
self.is_known_external()
}
}
// Is a sub command
fn is_sub(&self) -> bool {
self.name().contains(' ')
}
// Is a parser keyword (source, def, etc.)
fn is_parser_keyword(&self) -> bool {
false
// If command is a block i.e. def blah [] { }, get the block id
fn block_id(&self) -> Option<BlockId> {
None
}
/// Is a plugin command
fn is_plugin(&self) -> bool {
false
// Return reference to the command as Alias
fn as_alias(&self) -> Option<&Alias> {
None
}
/// The identity of the plugin, if this is a plugin command
@ -100,38 +93,32 @@ pub trait Command: Send + Sync + CommandClone {
None
}
// Whether can run in const evaluation in the parser
fn is_const(&self) -> bool {
false
}
// If command is a block i.e. def blah [] { }, get the block id
fn get_block_id(&self) -> Option<BlockId> {
None
}
// Related terms to help with command search
fn search_terms(&self) -> Vec<&str> {
vec![]
}
fn command_type(&self) -> CommandType {
match (
self.is_builtin(),
self.is_custom_command(),
self.is_parser_keyword(),
self.is_known_external(),
self.is_alias(),
self.is_plugin(),
) {
(true, false, false, false, false, false) => CommandType::Builtin,
(true, true, false, false, false, false) => CommandType::Custom,
(true, false, true, false, false, false) => CommandType::Keyword,
(false, true, false, true, false, false) => CommandType::External,
(_, _, _, _, true, _) => CommandType::Alias,
(true, false, false, false, false, true) => CommandType::Plugin,
_ => CommandType::Other,
}
CommandType::Builtin
}
fn is_builtin(&self) -> bool {
self.command_type() == CommandType::Builtin
}
fn is_custom(&self) -> bool {
self.command_type() == CommandType::Custom
}
fn is_keyword(&self) -> bool {
self.command_type() == CommandType::Keyword
}
fn is_known_external(&self) -> bool {
self.command_type() == CommandType::External
}
fn is_alias(&self) -> bool {
self.command_type() == CommandType::Alias
}
fn is_plugin(&self) -> bool {
self.command_type() == CommandType::Plugin
}
fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {

View File

@ -794,7 +794,7 @@ impl EngineState {
}
pub fn get_signature(&self, decl: &dyn Command) -> Signature {
if let Some(block_id) = decl.get_block_id() {
if let Some(block_id) = decl.block_id() {
*self.blocks[block_id].signature.clone()
} else {
decl.signature()
@ -814,26 +814,16 @@ impl EngineState {
/// Get signatures of all commands within scope.
///
/// In addition to signatures, it returns whether each command is:
/// a) a plugin
/// b) custom
/// In addition to signatures, it returns each command's examples and type.
pub fn get_signatures_with_examples(
&self,
include_hidden: bool,
) -> Vec<(Signature, Vec<Example>, bool, bool, bool)> {
) -> Vec<(Signature, Vec<Example>, CommandType)> {
self.get_decls_sorted(include_hidden)
.map(|(_, id)| {
let decl = self.get_decl(id);
let signature = self.get_signature(decl).update_from_command(decl);
(
signature,
decl.examples(),
decl.is_plugin(),
decl.get_block_id().is_some(),
decl.is_parser_keyword(),
)
(signature, decl.examples(), decl.command_type())
})
.collect()
}

View File

@ -550,7 +550,7 @@ impl PipelineData {
// to create the table value that will be printed in the terminal
if let Some(decl_id) = engine_state.table_decl_id {
let command = engine_state.get_decl(decl_id);
if command.get_block_id().is_some() {
if command.block_id().is_some() {
self.write_all_and_flush(engine_state, no_newline, to_stderr)
} else {
let call = Call::new(Span::new(0, 0));

View File

@ -1,6 +1,6 @@
use crate::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{Command, CommandType, EngineState, Stack},
BlockId, PipelineData, ShellError, SyntaxShape, Type, Value, VarId,
};
use serde::{Deserialize, Serialize};
@ -703,7 +703,11 @@ impl Command for BlockCommand {
})
}
fn get_block_id(&self) -> Option<BlockId> {
fn command_type(&self) -> CommandType {
CommandType::Custom
}
fn block_id(&self) -> Option<BlockId> {
Some(self.block_id)
}
}

View File

@ -145,7 +145,7 @@ pub fn goto_def(engine_state: &mut EngineState, file_path: &str, location: &Valu
match find_id(&mut working_set, file_path, &file, location) {
Some((Id::Declaration(decl_id), ..)) => {
let result = working_set.get_decl(decl_id);
if let Some(block_id) = result.get_block_id() {
if let Some(block_id) = result.block_id() {
let block = working_set.get_block(block_id);
if let Some(span) = &block.span {
for file in working_set.files() {