nu_command/help/
help_operators.rs

1use nu_engine::command_prelude::*;
2use nu_protocol::ast::{Assignment, Bits, Boolean, Comparison, Math, Operator};
3use strum::IntoEnumIterator;
4
5#[derive(Clone)]
6pub struct HelpOperators;
7
8impl Command for HelpOperators {
9    fn name(&self) -> &str {
10        "help operators"
11    }
12
13    fn description(&self) -> &str {
14        "Show help on nushell operators."
15    }
16
17    fn signature(&self) -> Signature {
18        Signature::build("help operators")
19            .category(Category::Core)
20            .input_output_types(vec![(Type::Nothing, Type::table())])
21            .allow_variants_without_examples(true)
22    }
23
24    fn run(
25        &self,
26        _engine_state: &EngineState,
27        _stack: &mut Stack,
28        call: &Call,
29        _input: PipelineData,
30    ) -> Result<PipelineData, ShellError> {
31        let head = call.head;
32        let mut operators = Assignment::iter()
33            .map(Operator::Assignment)
34            .chain(Comparison::iter().map(Operator::Comparison))
35            .chain(Math::iter().map(Operator::Math))
36            .chain(Bits::iter().map(Operator::Bits))
37            .chain(Boolean::iter().map(Operator::Boolean))
38            .map(|op| {
39                if op == Operator::Comparison(Comparison::RegexMatch) {
40                    Value::record(
41                        record! {
42                            "type" => Value::string(op_type(&op), head),
43                            "operator" => Value::string("=~, like", head),
44                            "name" => Value::string(name(&op), head),
45                            "description" => Value::string(description(&op), head),
46                            "precedence" => Value::int(op.precedence().into(), head),
47                        },
48                        head,
49                    )
50                } else if op == Operator::Comparison(Comparison::NotRegexMatch) {
51                    Value::record(
52                        record! {
53                            "type" => Value::string(op_type(&op), head),
54                            "operator" => Value::string("!~, not-like", head),
55                            "name" => Value::string(name(&op), head),
56                            "description" => Value::string(description(&op), head),
57                            "precedence" => Value::int(op.precedence().into(), head),
58                        },
59                        head,
60                    )
61                } else {
62                    Value::record(
63                        record! {
64                            "type" => Value::string(op_type(&op), head),
65                            "operator" => Value::string(op.to_string(), head),
66                            "name" => Value::string(name(&op), head),
67                            "description" => Value::string(description(&op), head),
68                            "precedence" => Value::int(op.precedence().into(), head),
69                        },
70                        head,
71                    )
72                }
73            })
74            .collect::<Vec<_>>();
75
76        operators.push(Value::record(
77            record! {
78                "type" => Value::string("Boolean", head),
79                "operator" => Value::string("not", head),
80                "name" => Value::string("Not", head),
81                "description" => Value::string("Negates a value or expression.", head),
82                "precedence" => Value::int(55, head),
83            },
84            head,
85        ));
86
87        Ok(Value::list(operators, head).into_pipeline_data())
88    }
89}
90
91fn op_type(operator: &Operator) -> &'static str {
92    match operator {
93        Operator::Comparison(_) => "Comparison",
94        Operator::Math(_) => "Math",
95        Operator::Boolean(_) => "Boolean",
96        Operator::Bits(_) => "Bitwise",
97        Operator::Assignment(_) => "Assignment",
98    }
99}
100
101fn name(operator: &Operator) -> String {
102    match operator {
103        Operator::Comparison(op) => format!("{op:?}"),
104        Operator::Math(op) => format!("{op:?}"),
105        Operator::Boolean(op) => format!("{op:?}"),
106        Operator::Bits(op) => format!("{op:?}"),
107        Operator::Assignment(op) => format!("{op:?}"),
108    }
109}
110
111fn description(operator: &Operator) -> &'static str {
112    match operator {
113        Operator::Comparison(Comparison::Equal) => "Checks if two values are equal.",
114        Operator::Comparison(Comparison::NotEqual) => "Checks if two values are not equal.",
115        Operator::Comparison(Comparison::LessThan) => "Checks if a value is less than another.",
116        Operator::Comparison(Comparison::GreaterThan) => {
117            "Checks if a value is greater than another."
118        }
119        Operator::Comparison(Comparison::LessThanOrEqual) => {
120            "Checks if a value is less than or equal to another."
121        }
122        Operator::Comparison(Comparison::GreaterThanOrEqual) => {
123            "Checks if a value is greater than or equal to another."
124        }
125        Operator::Comparison(Comparison::RegexMatch) => {
126            "Checks if a value matches a regular expression."
127        }
128        Operator::Comparison(Comparison::NotRegexMatch) => {
129            "Checks if a value does not match a regular expression."
130        }
131        Operator::Comparison(Comparison::In) => {
132            "Checks if a value is in a list, is part of a string, or is a key in a record."
133        }
134        Operator::Comparison(Comparison::NotIn) => {
135            "Checks if a value is not in a list, is not part of a string, or is not a key in a record."
136        }
137        Operator::Comparison(Comparison::Has) => {
138            "Checks if a list contains a value, a string contains another, or if a record has a key."
139        }
140        Operator::Comparison(Comparison::NotHas) => {
141            "Checks if a list does not contain a value, a string does not contain another, or if a record does not have a key."
142        }
143        Operator::Comparison(Comparison::StartsWith) => "Checks if a string starts with another.",
144        Operator::Comparison(Comparison::NotStartsWith) => {
145            "Checks if a string does not start with another."
146        }
147        Operator::Comparison(Comparison::EndsWith) => "Checks if a string ends with another.",
148        Operator::Comparison(Comparison::NotEndsWith) => {
149            "Checks if a string does not end with another."
150        }
151        Operator::Math(Math::Add) => "Adds two values.",
152        Operator::Math(Math::Subtract) => "Subtracts two values.",
153        Operator::Math(Math::Multiply) => "Multiplies two values.",
154        Operator::Math(Math::Divide) => "Divides two values.",
155        Operator::Math(Math::FloorDivide) => "Divides two values and floors the result.",
156        Operator::Math(Math::Modulo) => "Divides two values and returns the remainder.",
157        Operator::Math(Math::Pow) => "Raises one value to the power of another.",
158        Operator::Math(Math::Concatenate) => {
159            "Concatenates two lists, two strings, or two binary values."
160        }
161        Operator::Boolean(Boolean::Or) => "Checks if either value is true.",
162        Operator::Boolean(Boolean::Xor) => "Checks if one value is true and the other is false.",
163        Operator::Boolean(Boolean::And) => "Checks if both values are true.",
164        Operator::Bits(Bits::BitOr) => "Performs a bitwise OR on two values.",
165        Operator::Bits(Bits::BitXor) => "Performs a bitwise XOR on two values.",
166        Operator::Bits(Bits::BitAnd) => "Performs a bitwise AND on two values.",
167        Operator::Bits(Bits::ShiftLeft) => "Bitwise shifts a value left by another.",
168        Operator::Bits(Bits::ShiftRight) => "Bitwise shifts a value right by another.",
169        Operator::Assignment(Assignment::Assign) => "Assigns a value to a variable.",
170        Operator::Assignment(Assignment::AddAssign) => "Adds a value to a variable.",
171        Operator::Assignment(Assignment::SubtractAssign) => "Subtracts a value from a variable.",
172        Operator::Assignment(Assignment::MultiplyAssign) => "Multiplies a variable by a value.",
173        Operator::Assignment(Assignment::DivideAssign) => "Divides a variable by a value.",
174        Operator::Assignment(Assignment::ConcatenateAssign) => {
175            "Concatenates a list, a string, or a binary value to a variable of the same type."
176        }
177    }
178}
179
180#[cfg(test)]
181mod test {
182    #[test]
183    fn test_examples() {
184        use super::HelpOperators;
185        use crate::test_examples;
186        test_examples(HelpOperators {})
187    }
188}