nu_protocol/engine/
command.rs

1use super::{EngineState, Stack, StateWorkingSet};
2use crate::{
3    engine::Call, Alias, BlockId, Example, OutDest, PipelineData, ShellError, Signature, Value,
4};
5use std::fmt::Display;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum CommandType {
9    Builtin,
10    Custom,
11    Keyword,
12    External,
13    Alias,
14    Plugin,
15}
16
17impl Display for CommandType {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        let str = match self {
20            CommandType::Builtin => "built-in",
21            CommandType::Custom => "custom",
22            CommandType::Keyword => "keyword",
23            CommandType::External => "external",
24            CommandType::Alias => "alias",
25            CommandType::Plugin => "plugin",
26        };
27        write!(f, "{str}")
28    }
29}
30
31pub trait Command: Send + Sync + CommandClone {
32    fn name(&self) -> &str;
33
34    fn signature(&self) -> Signature;
35
36    /// Short preferably single sentence description for the command.
37    ///
38    /// Will be shown with the completions etc.
39    fn description(&self) -> &str;
40
41    /// Longer documentation description, if necessary.
42    ///
43    /// Will be shown below `description`
44    fn extra_description(&self) -> &str {
45        ""
46    }
47
48    fn run(
49        &self,
50        engine_state: &EngineState,
51        stack: &mut Stack,
52        call: &Call,
53        input: PipelineData,
54    ) -> Result<PipelineData, ShellError>;
55
56    /// Used by the parser to run command at parse time
57    ///
58    /// If a command has `is_const()` set to true, it must also implement this method.
59    #[allow(unused_variables)]
60    fn run_const(
61        &self,
62        working_set: &StateWorkingSet,
63        call: &Call,
64        input: PipelineData,
65    ) -> Result<PipelineData, ShellError> {
66        Err(ShellError::MissingConstEvalImpl { span: call.head })
67    }
68
69    fn examples(&self) -> Vec<Example> {
70        Vec::new()
71    }
72
73    // Related terms to help with command search
74    fn search_terms(&self) -> Vec<&str> {
75        vec![]
76    }
77
78    fn attributes(&self) -> Vec<(String, Value)> {
79        vec![]
80    }
81
82    // Whether can run in const evaluation in the parser
83    fn is_const(&self) -> bool {
84        false
85    }
86
87    // Is a sub command
88    fn is_sub(&self) -> bool {
89        self.name().contains(' ')
90    }
91
92    // If command is a block i.e. def blah [] { }, get the block id
93    fn block_id(&self) -> Option<BlockId> {
94        None
95    }
96
97    // Return reference to the command as Alias
98    fn as_alias(&self) -> Option<&Alias> {
99        None
100    }
101
102    /// The identity of the plugin, if this is a plugin command
103    #[cfg(feature = "plugin")]
104    fn plugin_identity(&self) -> Option<&crate::PluginIdentity> {
105        None
106    }
107
108    fn command_type(&self) -> CommandType {
109        CommandType::Builtin
110    }
111
112    fn is_builtin(&self) -> bool {
113        self.command_type() == CommandType::Builtin
114    }
115
116    fn is_custom(&self) -> bool {
117        self.command_type() == CommandType::Custom
118    }
119
120    fn is_keyword(&self) -> bool {
121        self.command_type() == CommandType::Keyword
122    }
123
124    fn is_known_external(&self) -> bool {
125        self.command_type() == CommandType::External
126    }
127
128    fn is_alias(&self) -> bool {
129        self.command_type() == CommandType::Alias
130    }
131
132    fn is_plugin(&self) -> bool {
133        self.command_type() == CommandType::Plugin
134    }
135
136    fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
137        (None, None)
138    }
139
140    /// Return true if the AST nodes for the arguments are required for IR evaluation. This is
141    /// currently inefficient so is not generally done.
142    fn requires_ast_for_arguments(&self) -> bool {
143        false
144    }
145}
146
147pub trait CommandClone {
148    fn clone_box(&self) -> Box<dyn Command>;
149}
150
151impl<T> CommandClone for T
152where
153    T: 'static + Command + Clone,
154{
155    fn clone_box(&self) -> Box<dyn Command> {
156        Box::new(self.clone())
157    }
158}
159
160impl Clone for Box<dyn Command> {
161    fn clone(&self) -> Box<dyn Command> {
162        self.clone_box()
163    }
164}