nu_command/help/
help_aliases.rs

1use crate::help::highlight_search_in_table;
2use nu_color_config::StyleComputer;
3use nu_engine::{command_prelude::*, scope::ScopeData};
4
5#[derive(Clone)]
6pub struct HelpAliases;
7
8impl Command for HelpAliases {
9    fn name(&self) -> &str {
10        "help aliases"
11    }
12
13    fn description(&self) -> &str {
14        "Show help on nushell aliases."
15    }
16
17    fn signature(&self) -> Signature {
18        Signature::build("help aliases")
19            .category(Category::Core)
20            .rest(
21                "rest",
22                SyntaxShape::String,
23                "The name of alias to get help on.",
24            )
25            .named(
26                "find",
27                SyntaxShape::String,
28                "string to find in alias names and descriptions",
29                Some('f'),
30            )
31            .input_output_types(vec![(Type::Nothing, Type::table())])
32            .allow_variants_without_examples(true)
33    }
34
35    fn examples(&self) -> Vec<Example> {
36        vec![
37            Example {
38                description: "show all aliases",
39                example: "help aliases",
40                result: None,
41            },
42            Example {
43                description: "show help for single alias",
44                example: "help aliases my-alias",
45                result: None,
46            },
47            Example {
48                description: "search for string in alias names and descriptions",
49                example: "help aliases --find my-alias",
50                result: None,
51            },
52        ]
53    }
54
55    fn run(
56        &self,
57        engine_state: &EngineState,
58        stack: &mut Stack,
59        call: &Call,
60        _input: PipelineData,
61    ) -> Result<PipelineData, ShellError> {
62        help_aliases(engine_state, stack, call)
63    }
64}
65
66pub fn help_aliases(
67    engine_state: &EngineState,
68    stack: &mut Stack,
69    call: &Call,
70) -> Result<PipelineData, ShellError> {
71    let head = call.head;
72    let find: Option<Spanned<String>> = call.get_flag(engine_state, stack, "find")?;
73    let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 0)?;
74
75    // 🚩The following two-lines are copied from filters/find.rs:
76    let style_computer = StyleComputer::from_config(engine_state, stack);
77    // Currently, search results all use the same style.
78    // Also note that this sample string is passed into user-written code (the closure that may or may not be
79    // defined for "string").
80    let string_style = style_computer.compute("string", &Value::string("search result", head));
81    let highlight_style =
82        style_computer.compute("search_result", &Value::string("search result", head));
83
84    if let Some(f) = find {
85        let all_cmds_vec = build_help_aliases(engine_state, stack, head);
86        let found_cmds_vec = highlight_search_in_table(
87            all_cmds_vec,
88            &f.item,
89            &["name", "description"],
90            &string_style,
91            &highlight_style,
92        )?;
93
94        return Ok(Value::list(found_cmds_vec, head).into_pipeline_data());
95    }
96
97    if rest.is_empty() {
98        let found_cmds_vec = build_help_aliases(engine_state, stack, head);
99        Ok(Value::list(found_cmds_vec, head).into_pipeline_data())
100    } else {
101        let mut name = String::new();
102
103        for r in &rest {
104            if !name.is_empty() {
105                name.push(' ');
106            }
107            name.push_str(&r.item);
108        }
109
110        let Some(alias) = engine_state.find_decl(name.as_bytes(), &[]) else {
111            return Err(ShellError::AliasNotFound {
112                span: Span::merge_many(rest.iter().map(|s| s.span)),
113            });
114        };
115
116        let Some(alias) = engine_state.get_decl(alias).as_alias() else {
117            return Err(ShellError::AliasNotFound {
118                span: Span::merge_many(rest.iter().map(|s| s.span)),
119            });
120        };
121
122        let alias_expansion =
123            String::from_utf8_lossy(engine_state.get_span_contents(alias.wrapped_call.span));
124        let description = alias.description();
125        let extra_desc = alias.extra_description();
126
127        // TODO: merge this into documentation.rs at some point
128        const G: &str = "\x1b[32m"; // green
129        const C: &str = "\x1b[36m"; // cyan
130        const RESET: &str = "\x1b[0m"; // reset
131
132        let mut long_desc = String::new();
133
134        long_desc.push_str(description);
135        long_desc.push_str("\n\n");
136
137        if !extra_desc.is_empty() {
138            long_desc.push_str(extra_desc);
139            long_desc.push_str("\n\n");
140        }
141
142        long_desc.push_str(&format!("{G}Alias{RESET}: {C}{name}{RESET}"));
143        long_desc.push_str("\n\n");
144        long_desc.push_str(&format!("{G}Expansion{RESET}:\n  {alias_expansion}"));
145
146        let config = stack.get_config(engine_state);
147        if !config.use_ansi_coloring.get(engine_state) {
148            long_desc = nu_utils::strip_ansi_string_likely(long_desc);
149        }
150
151        Ok(Value::string(long_desc, call.head).into_pipeline_data())
152    }
153}
154
155fn build_help_aliases(engine_state: &EngineState, stack: &Stack, span: Span) -> Vec<Value> {
156    let mut scope_data = ScopeData::new(engine_state, stack);
157    scope_data.populate_decls();
158
159    scope_data.collect_aliases(span)
160}
161
162#[cfg(test)]
163mod test {
164    #[test]
165    fn test_examples() {
166        use super::HelpAliases;
167        use crate::test_examples;
168        test_examples(HelpAliases {})
169    }
170}