add help operators command (#7254)

# Description

This PR adds a new command called `help operators`. The intention is to
make nushell's operators more discoverable.

Operations are evaluated in the precedence order (from highest to
lowest).

<img width="737" alt="Screenshot 2022-11-26 at 7 23 15 PM"
src="https://user-images.githubusercontent.com/343840/204115311-56765517-c36d-44d5-b303-43ffc0e980f6.png">

# User-Facing Changes



# Tests + Formatting

Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass

# After Submitting

If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
Darren Schroeder 2022-11-27 02:03:17 -06:00 committed by GitHub
parent c4d2b787aa
commit 2a8a628b72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 291 additions and 0 deletions

View file

@ -0,0 +1,288 @@
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Value,
};
#[derive(Clone)]
pub struct HelpOperators;
impl Command for HelpOperators {
fn name(&self) -> &str {
"help operators"
}
fn usage(&self) -> &str {
"Show help on nushell operators."
}
fn signature(&self) -> Signature {
Signature::build("help operators").category(Category::Core)
}
fn run(
&self,
engine_state: &EngineState,
_stack: &mut Stack,
call: &Call,
_input: PipelineData,
) -> Result<PipelineData, ShellError> {
let head = call.head;
let op_info = generate_operator_info();
let mut recs = vec![];
for op in op_info {
let mut cols = vec![];
let mut vals = vec![];
cols.push("type".into());
vals.push(Value::string(op.op_type, head));
cols.push("operator".into());
vals.push(Value::string(op.operator, head));
cols.push("name".into());
vals.push(Value::string(op.name, head));
cols.push("precedence".into());
vals.push(Value::int(op.precedence, head));
recs.push(Value::Record {
cols,
vals,
span: head,
})
}
Ok(recs
.into_iter()
.into_pipeline_data(engine_state.ctrlc.clone()))
}
}
struct OperatorInfo {
op_type: String,
operator: String,
name: String,
precedence: i64,
}
fn generate_operator_info() -> Vec<OperatorInfo> {
vec![
OperatorInfo {
op_type: "Assignment".into(),
operator: "=".into(),
name: "Assign".into(),
precedence: 10,
},
OperatorInfo {
op_type: "Assignment".into(),
operator: "+=".into(),
name: "PlusAssign".into(),
precedence: 10,
},
OperatorInfo {
op_type: "Assignment".into(),
operator: "-=".into(),
name: "MinusAssign".into(),
precedence: 10,
},
OperatorInfo {
op_type: "Assignment".into(),
operator: "*=".into(),
name: "MultiplyAssign".into(),
precedence: 10,
},
OperatorInfo {
op_type: "Assignment".into(),
operator: "/=".into(),
name: "DivideAssign".into(),
precedence: 10,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "==".into(),
name: "Equal".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "!=".into(),
name: "NotEqual".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "<".into(),
name: "LessThan".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "<=".into(),
name: "LessThanOrEqual".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: ">".into(),
name: "GreaterThan".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: ">=".into(),
name: "GreaterThanOrEqual".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "=~".into(),
name: "RegexMatch".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "!~".into(),
name: "NotRegexMatch".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "in".into(),
name: "In".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "not-in".into(),
name: "NotIn".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "starts-with".into(),
name: "StartsWith".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Comparison".into(),
operator: "ends-with".into(),
name: "EndsWith".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Math".into(),
operator: "+".into(),
name: "Plus".into(),
precedence: 90,
},
OperatorInfo {
op_type: "Math".into(),
operator: "++".into(),
name: "Append".into(),
precedence: 80,
},
OperatorInfo {
op_type: "Math".into(),
operator: "-".into(),
name: "Minus".into(),
precedence: 90,
},
OperatorInfo {
op_type: "Math".into(),
operator: "*".into(),
name: "Multiply".into(),
precedence: 95,
},
OperatorInfo {
op_type: "Math".into(),
operator: "/".into(),
name: "Divide".into(),
precedence: 95,
},
OperatorInfo {
op_type: "Math".into(),
operator: "//".into(),
name: "FloorDivision".into(),
precedence: 95,
},
OperatorInfo {
op_type: "Math".into(),
operator: "mod".into(),
name: "Modulo".into(),
precedence: 95,
},
OperatorInfo {
op_type: "Math".into(),
operator: "**".into(),
name: "Pow ".into(),
precedence: 100,
},
OperatorInfo {
op_type: "Bitwise".into(),
operator: "bit-or".into(),
name: "BitOr".into(),
precedence: 60,
},
OperatorInfo {
op_type: "Bitwise".into(),
operator: "bit-xor".into(),
name: "BitXor".into(),
precedence: 70,
},
OperatorInfo {
op_type: "Bitwise".into(),
operator: "bit-and".into(),
name: "BitAnd".into(),
precedence: 75,
},
OperatorInfo {
op_type: "Bitwise".into(),
operator: "bit-shl".into(),
name: "ShiftLeft".into(),
precedence: 85,
},
OperatorInfo {
op_type: "Bitwise".into(),
operator: "bit-shr".into(),
name: "ShiftRight".into(),
precedence: 85,
},
OperatorInfo {
op_type: "Boolean".into(),
operator: "&&".into(),
name: "And".into(),
precedence: 50,
},
OperatorInfo {
op_type: "Boolean".into(),
operator: "and".into(),
name: "And".into(),
precedence: 50,
},
OperatorInfo {
op_type: "Boolean".into(),
operator: "||".into(),
name: "Or".into(),
precedence: 40,
},
OperatorInfo {
op_type: "Boolean".into(),
operator: "or".into(),
name: "Or".into(),
precedence: 40,
},
OperatorInfo {
op_type: "Boolean".into(),
operator: "xor".into(),
name: "Xor".into(),
precedence: 45,
},
]
}
#[cfg(test)]
mod test {
#[test]
fn test_examples() {
use super::HelpOperators;
use crate::test_examples;
test_examples(HelpOperators {})
}
}

View file

@ -19,6 +19,7 @@ mod export_use;
mod extern_;
mod for_;
pub mod help;
mod help_operators;
mod hide;
mod hide_env;
mod if_;
@ -56,6 +57,7 @@ pub use export_use::ExportUse;
pub use extern_::Extern;
pub use for_::For;
pub use help::Help;
pub use help_operators::HelpOperators;
pub use hide::Hide;
pub use hide_env::HideEnv;
pub use if_::If;

View file

@ -49,6 +49,7 @@ pub fn create_default_context() -> EngineState {
Extern,
For,
Help,
HelpOperators,
Hide,
HideEnv,
If,