forked from extern/nushell
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:
@ -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> {
|
||||
|
@ -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>) {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user