nu_protocol/engine/
command.rs

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