nushell/crates/nu-engine/src/scope.rs

681 lines
23 KiB
Rust
Raw Normal View History

use nu_protocol::{
2023-03-10 18:14:55 +00:00
engine::{Command, EngineState, Stack, Visibility},
ShellError, Signature, Span, SyntaxShape, Type, Value,
};
2023-03-10 18:14:55 +00:00
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::HashMap;
pub fn create_scope(
engine_state: &EngineState,
stack: &Stack,
span: Span,
) -> Result<Value, ShellError> {
let mut scope_data = ScopeData::new(engine_state, stack);
2022-12-30 15:44:37 +00:00
scope_data.populate_all();
let mut cols = vec![];
let mut vals = vec![];
cols.push("vars".to_string());
vals.push(Value::List {
vals: scope_data.collect_vars(span),
span,
});
cols.push("commands".to_string());
vals.push(Value::List {
vals: scope_data.collect_commands(span),
span,
});
cols.push("aliases".to_string());
vals.push(Value::List {
2022-12-30 15:44:37 +00:00
vals: scope_data.collect_aliases(span),
span,
});
cols.push("modules".to_string());
vals.push(Value::List {
vals: scope_data.collect_modules(span),
span,
});
cols.push("engine_state".to_string());
vals.push(scope_data.collect_engine_state(span));
Ok(Value::Record { cols, vals, span })
}
2022-12-30 15:44:37 +00:00
pub struct ScopeData<'e, 's> {
engine_state: &'e EngineState,
stack: &'s Stack,
vars_map: HashMap<&'e Vec<u8>, &'e usize>,
Remove broken compile-time overload system (#9677) # Description This PR removes the compile-time overload system. Unfortunately, this system never worked correctly because in a gradual type system where types can be `Any`, you don't have enough information to correctly resolve function calls with overloads. These resolutions must be done at runtime, if they're supported. That said, there's a bit of work that needs to go into resolving input/output types (here overloads do not execute separate commands, but the same command and each overload explains how each output type corresponds to input types). This PR also removes the type scope, which would give incorrect answers in cases where multiple subexpressions were used in a pipeline. # User-Facing Changes Finishes removing compile-time overloads. These were only used in a few places in the code base, but it's possible it may impact user code. I'll mark this as breaking change so we can review. # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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. -->
2023-07-13 19:05:03 +00:00
decls_map: HashMap<&'e Vec<u8>, &'e usize>,
modules_map: HashMap<&'e Vec<u8>, &'e usize>,
visibility: Visibility,
}
impl<'e, 's> ScopeData<'e, 's> {
pub fn new(engine_state: &'e EngineState, stack: &'s Stack) -> Self {
Self {
engine_state,
stack,
vars_map: HashMap::new(),
decls_map: HashMap::new(),
modules_map: HashMap::new(),
visibility: Visibility::new(),
}
}
2022-12-30 15:44:37 +00:00
pub fn populate_all(&mut self) {
for overlay_frame in self.engine_state.active_overlays(&[]) {
self.vars_map.extend(&overlay_frame.vars);
self.decls_map.extend(&overlay_frame.decls);
self.modules_map.extend(&overlay_frame.modules);
self.visibility.merge_with(overlay_frame.visibility.clone());
}
}
2022-12-30 15:44:37 +00:00
pub fn populate_modules(&mut self) {
for overlay_frame in self.engine_state.active_overlays(&[]) {
self.modules_map.extend(&overlay_frame.modules);
}
}
pub fn collect_vars(&self, span: Span) -> Vec<Value> {
let mut vars = vec![];
for var in &self.vars_map {
let var_name = Value::string(String::from_utf8_lossy(var.0).to_string(), span);
let var_type = Value::string(self.engine_state.get_var(**var.1).ty.to_string(), span);
let var_value = if let Ok(val) = self.stack.get_var(**var.1, span) {
val
} else {
Value::nothing(span)
};
vars.push(Value::Record {
cols: vec!["name".to_string(), "type".to_string(), "value".to_string()],
vals: vec![var_name, var_type, var_value],
span,
})
}
vars
}
2022-12-30 15:44:37 +00:00
pub fn collect_commands(&self, span: Span) -> Vec<Value> {
let mut commands = vec![];
Remove broken compile-time overload system (#9677) # Description This PR removes the compile-time overload system. Unfortunately, this system never worked correctly because in a gradual type system where types can be `Any`, you don't have enough information to correctly resolve function calls with overloads. These resolutions must be done at runtime, if they're supported. That said, there's a bit of work that needs to go into resolving input/output types (here overloads do not execute separate commands, but the same command and each overload explains how each output type corresponds to input types). This PR also removes the type scope, which would give incorrect answers in cases where multiple subexpressions were used in a pipeline. # User-Facing Changes Finishes removing compile-time overloads. These were only used in a few places in the code base, but it's possible it may impact user code. I'll mark this as breaking change so we can review. # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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. -->
2023-07-13 19:05:03 +00:00
for (command_name, decl_id) in &self.decls_map {
if self.visibility.is_decl_id_visible(decl_id)
&& !self.engine_state.get_decl(**decl_id).is_alias()
{
let mut cols = vec![];
let mut vals = vec![];
let mut module_commands = vec![];
for module in &self.modules_map {
let module_name = String::from_utf8_lossy(module.0).to_string();
let module_id = self.engine_state.find_module(module.0, &[]);
if let Some(module_id) = module_id {
let module = self.engine_state.get_module(module_id);
if module.has_decl(command_name) {
module_commands.push(module_name);
}
}
}
cols.push("name".into());
vals.push(Value::String {
val: String::from_utf8_lossy(command_name).to_string(),
span,
});
cols.push("module_name".into());
vals.push(Value::string(module_commands.join(", "), span));
let decl = self.engine_state.get_decl(**decl_id);
let signature = decl.signature();
cols.push("category".to_string());
vals.push(Value::String {
val: signature.category.to_string(),
span,
});
cols.push("signatures".to_string());
vals.push(self.collect_signatures(&signature, span));
cols.push("usage".to_string());
vals.push(Value::String {
val: decl.usage().into(),
span,
});
cols.push("examples".to_string());
vals.push(Value::List {
vals: decl
.examples()
.into_iter()
.map(|x| Value::Record {
FEATURE: add the example results to the scope (#8319) Related to #8189. Should close #8302. Important to: - have a complete `$nu` structure with all available information - generate an accurate website, because the `make_docs.nu` script of `nushell.github.io` uses `$nu.scope.command` to generate the pages of https://nushell.sh/commands/ > **Note** > i was looking for "scope" in the source of `nushell` to augment `$nu.scope` and i found `crates/nu-engine/src/scope.rs` that defines `nu_engine::scope::create_scope` which lead me to `nu_engine::scope::ScopeData.collect_commands`. > i hope this is the right file :relieved: # Description this PR slightly modifies `nu_engine::scope::ScopeData.collect_commands`: - add the "result" column to `$nu.scope.commands.examples` - put the result of the example when a valid `Option(Value)` - put a `Value::Nothing` when the result is set to `None` in the source of the command # User-Facing Changes users can now access the results of all examples in ```bash $nu.scope.commands | where name == <command> | get examples.0.result ``` ## example... ### ...with a command that defines examples: `merge` ```bash >_ $nu.scope.commands | where name == merge | get examples.0 | reject description | table --expand ╭───┬────────────────────────────────────────────────────────┬───────────────────────────╮ │ # │ example │ result │ ├───┼────────────────────────────────────────────────────────┼───────────────────────────┤ │ 0 │ [a b c] | wrap name | merge ( [1 2 3] | wrap index ) │ ╭───┬──────╮ │ │ │ │ │ # │ name │ │ │ │ │ ├───┼──────┤ │ │ │ │ │ 1 │ a │ │ │ │ │ │ 2 │ b │ │ │ │ │ │ 3 │ c │ │ │ │ │ ╰───┴──────╯ │ │ 1 │ {a: 1, b: 2} | merge {c: 3} │ ╭───┬───╮ │ │ │ │ │ a │ 1 │ │ │ │ │ │ b │ 2 │ │ │ │ │ │ c │ 3 │ │ │ │ │ ╰───┴───╯ │ │ 2 │ [{columnA: A0 columnB: B0}] | merge [{columnA: 'A0*'}] │ ╭───┬─────────┬─────────╮ │ │ │ │ │ # │ columnA │ columnB │ │ │ │ │ ├───┼─────────┼─────────┤ │ │ │ │ │ 0 │ A0* │ B0 │ │ │ │ │ ╰───┴─────────┴─────────╯ │ ╰───┴────────────────────────────────────────────────────────┴───────────────────────────╯ ``` and we can check that these are "true" results and not just string, e.g. ```bash >_ $nu.scope.commands | where name == merge | get examples.0.result.0 | describe table<name: string, index: int> ``` ### ...with a command without any example: `open` ```bash >_ $nu.scope.commands | where name == open | get examples.0 | reject description | table --expand ╭───┬──────────────────────────────────────┬────────╮ │ # │ example │ result │ ├───┼──────────────────────────────────────┼────────┤ │ 0 │ open myfile.json │ │ │ 1 │ open myfile.json --raw │ │ │ 2 │ 'myfile.txt' | open │ │ │ 3 │ open myfile.txt --raw | decode utf-8 │ │ ╰───┴──────────────────────────────────────┴────────╯ ``` and same thing, we can check that there is `$nothing` in this last command ```bash >_ $nu.scope.commands | where name == open | get examples.0.result.0 | describe table<name: string, index: int> ``` # Tests + Formatting - :heavy_check_mark: `cargo fmt --all` - :heavy_check_mark: `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` - :heavy_check_mark: `cargo test --workspace` (~~currently running~~) # After Submitting the documentation would have to be regenerated!
2023-03-05 09:56:06 +00:00
cols: vec!["description".into(), "example".into(), "result".into()],
vals: vec![
Value::String {
val: x.description.to_string(),
span,
},
Value::String {
val: x.example.to_string(),
span,
},
FEATURE: add the example results to the scope (#8319) Related to #8189. Should close #8302. Important to: - have a complete `$nu` structure with all available information - generate an accurate website, because the `make_docs.nu` script of `nushell.github.io` uses `$nu.scope.command` to generate the pages of https://nushell.sh/commands/ > **Note** > i was looking for "scope" in the source of `nushell` to augment `$nu.scope` and i found `crates/nu-engine/src/scope.rs` that defines `nu_engine::scope::create_scope` which lead me to `nu_engine::scope::ScopeData.collect_commands`. > i hope this is the right file :relieved: # Description this PR slightly modifies `nu_engine::scope::ScopeData.collect_commands`: - add the "result" column to `$nu.scope.commands.examples` - put the result of the example when a valid `Option(Value)` - put a `Value::Nothing` when the result is set to `None` in the source of the command # User-Facing Changes users can now access the results of all examples in ```bash $nu.scope.commands | where name == <command> | get examples.0.result ``` ## example... ### ...with a command that defines examples: `merge` ```bash >_ $nu.scope.commands | where name == merge | get examples.0 | reject description | table --expand ╭───┬────────────────────────────────────────────────────────┬───────────────────────────╮ │ # │ example │ result │ ├───┼────────────────────────────────────────────────────────┼───────────────────────────┤ │ 0 │ [a b c] | wrap name | merge ( [1 2 3] | wrap index ) │ ╭───┬──────╮ │ │ │ │ │ # │ name │ │ │ │ │ ├───┼──────┤ │ │ │ │ │ 1 │ a │ │ │ │ │ │ 2 │ b │ │ │ │ │ │ 3 │ c │ │ │ │ │ ╰───┴──────╯ │ │ 1 │ {a: 1, b: 2} | merge {c: 3} │ ╭───┬───╮ │ │ │ │ │ a │ 1 │ │ │ │ │ │ b │ 2 │ │ │ │ │ │ c │ 3 │ │ │ │ │ ╰───┴───╯ │ │ 2 │ [{columnA: A0 columnB: B0}] | merge [{columnA: 'A0*'}] │ ╭───┬─────────┬─────────╮ │ │ │ │ │ # │ columnA │ columnB │ │ │ │ │ ├───┼─────────┼─────────┤ │ │ │ │ │ 0 │ A0* │ B0 │ │ │ │ │ ╰───┴─────────┴─────────╯ │ ╰───┴────────────────────────────────────────────────────────┴───────────────────────────╯ ``` and we can check that these are "true" results and not just string, e.g. ```bash >_ $nu.scope.commands | where name == merge | get examples.0.result.0 | describe table<name: string, index: int> ``` ### ...with a command without any example: `open` ```bash >_ $nu.scope.commands | where name == open | get examples.0 | reject description | table --expand ╭───┬──────────────────────────────────────┬────────╮ │ # │ example │ result │ ├───┼──────────────────────────────────────┼────────┤ │ 0 │ open myfile.json │ │ │ 1 │ open myfile.json --raw │ │ │ 2 │ 'myfile.txt' | open │ │ │ 3 │ open myfile.txt --raw | decode utf-8 │ │ ╰───┴──────────────────────────────────────┴────────╯ ``` and same thing, we can check that there is `$nothing` in this last command ```bash >_ $nu.scope.commands | where name == open | get examples.0.result.0 | describe table<name: string, index: int> ``` # Tests + Formatting - :heavy_check_mark: `cargo fmt --all` - :heavy_check_mark: `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` - :heavy_check_mark: `cargo test --workspace` (~~currently running~~) # After Submitting the documentation would have to be regenerated!
2023-03-05 09:56:06 +00:00
if let Some(result) = x.result {
result
} else {
Value::Nothing { span }
},
],
span,
})
.collect(),
span,
});
cols.push("is_builtin".to_string());
// we can only be a is_builtin or is_custom, not both
vals.push(Value::Bool {
val: !decl.is_custom_command(),
span,
});
cols.push("is_sub".to_string());
vals.push(Value::Bool {
val: decl.is_sub(),
span,
});
cols.push("is_plugin".to_string());
vals.push(Value::Bool {
val: decl.is_plugin().is_some(),
span,
});
cols.push("is_custom".to_string());
vals.push(Value::Bool {
val: decl.is_custom_command(),
span,
});
cols.push("is_keyword".into());
vals.push(Value::Bool {
val: decl.is_parser_keyword(),
span,
});
cols.push("is_extern".to_string());
vals.push(Value::Bool {
val: decl.is_known_external(),
span,
});
cols.push("creates_scope".to_string());
vals.push(Value::Bool {
val: signature.creates_scope,
span,
});
cols.push("extra_usage".to_string());
vals.push(Value::String {
val: decl.extra_usage().into(),
span,
});
let search_terms = decl.search_terms();
cols.push("search_terms".to_string());
vals.push(Value::String {
val: search_terms.join(", "),
span,
});
commands.push(Value::Record { cols, vals, span })
}
}
commands.sort_by(|a, b| match (a, b) {
(Value::Record { vals: rec_a, .. }, Value::Record { vals: rec_b, .. }) => {
// Comparing the first value from the record
// It is expected that the first value is the name of the column
// The names of the commands should be a value string
match (rec_a.get(0), rec_b.get(0)) {
(Some(val_a), Some(val_b)) => match (val_a, val_b) {
(Value::String { val: str_a, .. }, Value::String { val: str_b, .. }) => {
str_a.cmp(str_b)
}
_ => Ordering::Equal,
},
_ => Ordering::Equal,
}
}
_ => Ordering::Equal,
});
commands
}
fn collect_signatures(&self, signature: &Signature, span: Span) -> Value {
let mut sigs = signature
.input_output_types
.iter()
.map(|(input_type, output_type)| {
(
input_type.to_shape().to_string(),
Value::List {
vals: self.collect_signature_entries(
input_type,
output_type,
signature,
span,
),
span,
},
)
})
.collect::<Vec<(String, Value)>>();
allow custom commands to show up in `$nu.scope.commands` better (#8910) # Description This PR allows our custom commands to show up in `$nu.scope.commands` better. It still needs work because this PR hard code the input and output types as `Type::Any` but the reason they're being missed in the first place is that they are not assigned an input and output type. This allows things like this now. Note the `where is_custom == true` ![image](https://user-images.githubusercontent.com/343840/232523925-97eeef78-9722-4184-b60f-9d06f994c8e3.png) Another example. ![image](https://user-images.githubusercontent.com/343840/232525706-d4d088d8-6597-43ba-97c8-ab03c2c7408c.png) ![image](https://user-images.githubusercontent.com/343840/232525797-b7e9ded3-b299-489e-af33-7390f4291bfd.png) # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking 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 - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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. -->
2023-04-17 16:19:37 +00:00
// Until we allow custom commands to have input and output types, let's just
// make them Type::Any Type::Any so they can show up in our `scope commands`
allow custom commands to show up in `$nu.scope.commands` better (#8910) # Description This PR allows our custom commands to show up in `$nu.scope.commands` better. It still needs work because this PR hard code the input and output types as `Type::Any` but the reason they're being missed in the first place is that they are not assigned an input and output type. This allows things like this now. Note the `where is_custom == true` ![image](https://user-images.githubusercontent.com/343840/232523925-97eeef78-9722-4184-b60f-9d06f994c8e3.png) Another example. ![image](https://user-images.githubusercontent.com/343840/232525706-d4d088d8-6597-43ba-97c8-ab03c2c7408c.png) ![image](https://user-images.githubusercontent.com/343840/232525797-b7e9ded3-b299-489e-af33-7390f4291bfd.png) # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking 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 - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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. -->
2023-04-17 16:19:37 +00:00
// a little bit better. If sigs is empty, we're pretty sure that we're dealing
// with a custom command.
if sigs.is_empty() {
let any_type = &Type::Any;
sigs.push((
any_type.to_shape().to_string(),
Value::List {
vals: self.collect_signature_entries(any_type, any_type, signature, span),
span,
},
));
}
sigs.sort_unstable_by(|(k1, _), (k2, _)| k1.cmp(k2));
// For most commands, input types are not repeated in
// `input_output_types`, i.e. each input type has only one associated
// output type. Furthermore, we want this to always be true. However,
// there are currently some exceptions, such as `hash sha256` which
// takes in string but may output string or binary depending on the
// presence of the --binary flag. In such cases, the "special case"
// signature usually comes later in the input_output_types, so this will
// remove them from the record.
sigs.dedup_by(|(k1, _), (k2, _)| k1 == k2);
let (cols, vals) = sigs.into_iter().unzip();
Value::Record { cols, vals, span }
}
fn collect_signature_entries(
&self,
input_type: &Type,
output_type: &Type,
signature: &Signature,
span: Span,
) -> Vec<Value> {
let mut sig_records = vec![];
let sig_cols = vec![
"parameter_name".to_string(),
"parameter_type".to_string(),
"syntax_shape".to_string(),
"is_optional".to_string(),
"short_flag".to_string(),
"description".to_string(),
"custom_completion".to_string(),
Parameter defaults to $nu.scope.commands (#9152) (*third* try at posting this PR, #9104, like #9084, got polluted with unrelated commits. I'm never going to pull from the github feature branch again!) # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Show parameter defaults in scope command signature, where they're available for display by help. per https://github.com/nushell/nushell/issues/8928. I found unexpected ramifications in one completer (NuHelpCompleter) and plugins, which both use the flag-formatting routine from builtin help. For the moment I made the minimum necessary changes to get the mainline scenario to pass tests and run. But we should circle back on what to do with plugins and help completer.. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> 1. New `parameter_default` column to `signatures` table in `$nu.scope.commands` It is populated with whatever parameters can be defaulted: currently positional args and named flags. 2. Built in help (both `help <command>` and `<command> --help` will display the defaults 3. Help completer will display defaults for flags, but not for positionals. Example: A custom command with some default parameters: ``` 〉cat ~/work/dflts.nu # sample function to show defaults in help export def main [ arg1: string # mandatory positional arg2:string=abc # optional positional --switch # no default here --named:int # named flag, no default --other:string=def # flag --hard:record<foo:int bar:string, bas:bool> # default can be compound type = {foo:22, bar:"other worlds", bas:false} ] { {arg1: $arg1, arg2: $arg2, switch: $switch, named: $named, other: $other, hard: $hard, } } 〉use ~/work/dflts.nu 〉$nu.scope.commands | where name == 'dflts' | get signatures.0.any | reject short_flag description custom_completion ╭───┬────────────────┬────────────────┬──────────────────────────────────────────┬─────────────┬───────────────────────────╮ │ # │ parameter_name │ parameter_type │ syntax_shape │ is_optional │ parameter_default │ ├───┼────────────────┼────────────────┼──────────────────────────────────────────┼─────────────┼───────────────────────────┤ │ 0 │ │ input │ any │ false │ │ │ 1 │ arg1 │ positional │ string │ false │ │ │ 2 │ arg2 │ positional │ string │ true │ abc │ │ 3 │ switch │ switch │ │ true │ │ │ 4 │ named │ named │ int │ true │ │ │ 5 │ other │ named │ string │ true │ def │ │ 6 │ hard │ named │ record<foo: int, bar: string, bas: bool> │ true │ ╭───────┬───────────────╮ │ │ │ │ │ │ │ │ foo │ 22 │ │ │ │ │ │ │ │ │ bar │ other worlds │ │ │ │ │ │ │ │ │ bas │ false │ │ │ │ │ │ │ │ ╰───────┴───────────────╯ │ │ 7 │ │ output │ any │ false │ │ ╰───┴────────────────┴────────────────┴──────────────────────────────────────────┴─────────────┴───────────────────────────╯ 〉help dflts sample function to show defaults in help Usage: > dflts {flags} <arg1> (arg2) Flags: --switch - switch -- no default here --named <Int> - named flag, typed, but no default --other <String> - flag with default (default: 'def') --hard <Record([("foo", Int), ("bar", String), ("bas", Boolean)])> - default can be compound type (default: {foo: 22, bar: 'other worlds', bas: false}) -h, --help - Display the help message for this command Parameters: arg1 <string>: mandatory positional arg2 <string>: optional positional (optional, default: 'abc') ``` Compared to (relevant bits of) help output previously: ``` Flags: -h, --help - Display the help message for this command -, --switch - no default here -, --named <int> - named flag, no default -, --other <string> - flag -, --hard <record<foo: int, bar: string, bas: bool>> - default can be compound type Signatures: <any> | dflts <string> <string> -> <any> Parameters: arg1 <string>: mandatory positional (optional) arg2 <string>: optional positional ``` # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > [x] toolkit check pr > ``` --> # 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. -->
2023-05-11 18:59:56 +00:00
"parameter_default".to_string(),
];
// input
sig_records.push(Value::Record {
cols: sig_cols.clone(),
vals: vec![
Value::nothing(span),
Value::string("input", span),
Value::string(input_type.to_shape().to_string(), span),
Value::bool(false, span),
Value::nothing(span),
Value::nothing(span),
Value::nothing(span),
Parameter defaults to $nu.scope.commands (#9152) (*third* try at posting this PR, #9104, like #9084, got polluted with unrelated commits. I'm never going to pull from the github feature branch again!) # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Show parameter defaults in scope command signature, where they're available for display by help. per https://github.com/nushell/nushell/issues/8928. I found unexpected ramifications in one completer (NuHelpCompleter) and plugins, which both use the flag-formatting routine from builtin help. For the moment I made the minimum necessary changes to get the mainline scenario to pass tests and run. But we should circle back on what to do with plugins and help completer.. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> 1. New `parameter_default` column to `signatures` table in `$nu.scope.commands` It is populated with whatever parameters can be defaulted: currently positional args and named flags. 2. Built in help (both `help <command>` and `<command> --help` will display the defaults 3. Help completer will display defaults for flags, but not for positionals. Example: A custom command with some default parameters: ``` 〉cat ~/work/dflts.nu # sample function to show defaults in help export def main [ arg1: string # mandatory positional arg2:string=abc # optional positional --switch # no default here --named:int # named flag, no default --other:string=def # flag --hard:record<foo:int bar:string, bas:bool> # default can be compound type = {foo:22, bar:"other worlds", bas:false} ] { {arg1: $arg1, arg2: $arg2, switch: $switch, named: $named, other: $other, hard: $hard, } } 〉use ~/work/dflts.nu 〉$nu.scope.commands | where name == 'dflts' | get signatures.0.any | reject short_flag description custom_completion ╭───┬────────────────┬────────────────┬──────────────────────────────────────────┬─────────────┬───────────────────────────╮ │ # │ parameter_name │ parameter_type │ syntax_shape │ is_optional │ parameter_default │ ├───┼────────────────┼────────────────┼──────────────────────────────────────────┼─────────────┼───────────────────────────┤ │ 0 │ │ input │ any │ false │ │ │ 1 │ arg1 │ positional │ string │ false │ │ │ 2 │ arg2 │ positional │ string │ true │ abc │ │ 3 │ switch │ switch │ │ true │ │ │ 4 │ named │ named │ int │ true │ │ │ 5 │ other │ named │ string │ true │ def │ │ 6 │ hard │ named │ record<foo: int, bar: string, bas: bool> │ true │ ╭───────┬───────────────╮ │ │ │ │ │ │ │ │ foo │ 22 │ │ │ │ │ │ │ │ │ bar │ other worlds │ │ │ │ │ │ │ │ │ bas │ false │ │ │ │ │ │ │ │ ╰───────┴───────────────╯ │ │ 7 │ │ output │ any │ false │ │ ╰───┴────────────────┴────────────────┴──────────────────────────────────────────┴─────────────┴───────────────────────────╯ 〉help dflts sample function to show defaults in help Usage: > dflts {flags} <arg1> (arg2) Flags: --switch - switch -- no default here --named <Int> - named flag, typed, but no default --other <String> - flag with default (default: 'def') --hard <Record([("foo", Int), ("bar", String), ("bas", Boolean)])> - default can be compound type (default: {foo: 22, bar: 'other worlds', bas: false}) -h, --help - Display the help message for this command Parameters: arg1 <string>: mandatory positional arg2 <string>: optional positional (optional, default: 'abc') ``` Compared to (relevant bits of) help output previously: ``` Flags: -h, --help - Display the help message for this command -, --switch - no default here -, --named <int> - named flag, no default -, --other <string> - flag -, --hard <record<foo: int, bar: string, bas: bool>> - default can be compound type Signatures: <any> | dflts <string> <string> -> <any> Parameters: arg1 <string>: mandatory positional (optional) arg2 <string>: optional positional ``` # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > [x] toolkit check pr > ``` --> # 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. -->
2023-05-11 18:59:56 +00:00
Value::nothing(span),
],
span,
});
// required_positional
for req in &signature.required_positional {
let sig_vals = vec![
Value::string(&req.name, span),
Value::string("positional", span),
Value::string(req.shape.to_string(), span),
Value::bool(false, span),
Value::nothing(span),
Value::string(&req.desc, span),
Value::string(
extract_custom_completion_from_arg(self.engine_state, &req.shape),
span,
),
Parameter defaults to $nu.scope.commands (#9152) (*third* try at posting this PR, #9104, like #9084, got polluted with unrelated commits. I'm never going to pull from the github feature branch again!) # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Show parameter defaults in scope command signature, where they're available for display by help. per https://github.com/nushell/nushell/issues/8928. I found unexpected ramifications in one completer (NuHelpCompleter) and plugins, which both use the flag-formatting routine from builtin help. For the moment I made the minimum necessary changes to get the mainline scenario to pass tests and run. But we should circle back on what to do with plugins and help completer.. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> 1. New `parameter_default` column to `signatures` table in `$nu.scope.commands` It is populated with whatever parameters can be defaulted: currently positional args and named flags. 2. Built in help (both `help <command>` and `<command> --help` will display the defaults 3. Help completer will display defaults for flags, but not for positionals. Example: A custom command with some default parameters: ``` 〉cat ~/work/dflts.nu # sample function to show defaults in help export def main [ arg1: string # mandatory positional arg2:string=abc # optional positional --switch # no default here --named:int # named flag, no default --other:string=def # flag --hard:record<foo:int bar:string, bas:bool> # default can be compound type = {foo:22, bar:"other worlds", bas:false} ] { {arg1: $arg1, arg2: $arg2, switch: $switch, named: $named, other: $other, hard: $hard, } } 〉use ~/work/dflts.nu 〉$nu.scope.commands | where name == 'dflts' | get signatures.0.any | reject short_flag description custom_completion ╭───┬────────────────┬────────────────┬──────────────────────────────────────────┬─────────────┬───────────────────────────╮ │ # │ parameter_name │ parameter_type │ syntax_shape │ is_optional │ parameter_default │ ├───┼────────────────┼────────────────┼──────────────────────────────────────────┼─────────────┼───────────────────────────┤ │ 0 │ │ input │ any │ false │ │ │ 1 │ arg1 │ positional │ string │ false │ │ │ 2 │ arg2 │ positional │ string │ true │ abc │ │ 3 │ switch │ switch │ │ true │ │ │ 4 │ named │ named │ int │ true │ │ │ 5 │ other │ named │ string │ true │ def │ │ 6 │ hard │ named │ record<foo: int, bar: string, bas: bool> │ true │ ╭───────┬───────────────╮ │ │ │ │ │ │ │ │ foo │ 22 │ │ │ │ │ │ │ │ │ bar │ other worlds │ │ │ │ │ │ │ │ │ bas │ false │ │ │ │ │ │ │ │ ╰───────┴───────────────╯ │ │ 7 │ │ output │ any │ false │ │ ╰───┴────────────────┴────────────────┴──────────────────────────────────────────┴─────────────┴───────────────────────────╯ 〉help dflts sample function to show defaults in help Usage: > dflts {flags} <arg1> (arg2) Flags: --switch - switch -- no default here --named <Int> - named flag, typed, but no default --other <String> - flag with default (default: 'def') --hard <Record([("foo", Int), ("bar", String), ("bas", Boolean)])> - default can be compound type (default: {foo: 22, bar: 'other worlds', bas: false}) -h, --help - Display the help message for this command Parameters: arg1 <string>: mandatory positional arg2 <string>: optional positional (optional, default: 'abc') ``` Compared to (relevant bits of) help output previously: ``` Flags: -h, --help - Display the help message for this command -, --switch - no default here -, --named <int> - named flag, no default -, --other <string> - flag -, --hard <record<foo: int, bar: string, bas: bool>> - default can be compound type Signatures: <any> | dflts <string> <string> -> <any> Parameters: arg1 <string>: mandatory positional (optional) arg2 <string>: optional positional ``` # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > [x] toolkit check pr > ``` --> # 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. -->
2023-05-11 18:59:56 +00:00
Value::nothing(span),
];
sig_records.push(Value::Record {
cols: sig_cols.clone(),
vals: sig_vals,
span,
});
}
// optional_positional
for opt in &signature.optional_positional {
let sig_vals = vec![
Value::string(&opt.name, span),
Value::string("positional", span),
Value::string(opt.shape.to_string(), span),
Value::bool(true, span),
Value::nothing(span),
Value::string(&opt.desc, span),
Value::string(
extract_custom_completion_from_arg(self.engine_state, &opt.shape),
span,
),
Parameter defaults to $nu.scope.commands (#9152) (*third* try at posting this PR, #9104, like #9084, got polluted with unrelated commits. I'm never going to pull from the github feature branch again!) # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Show parameter defaults in scope command signature, where they're available for display by help. per https://github.com/nushell/nushell/issues/8928. I found unexpected ramifications in one completer (NuHelpCompleter) and plugins, which both use the flag-formatting routine from builtin help. For the moment I made the minimum necessary changes to get the mainline scenario to pass tests and run. But we should circle back on what to do with plugins and help completer.. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> 1. New `parameter_default` column to `signatures` table in `$nu.scope.commands` It is populated with whatever parameters can be defaulted: currently positional args and named flags. 2. Built in help (both `help <command>` and `<command> --help` will display the defaults 3. Help completer will display defaults for flags, but not for positionals. Example: A custom command with some default parameters: ``` 〉cat ~/work/dflts.nu # sample function to show defaults in help export def main [ arg1: string # mandatory positional arg2:string=abc # optional positional --switch # no default here --named:int # named flag, no default --other:string=def # flag --hard:record<foo:int bar:string, bas:bool> # default can be compound type = {foo:22, bar:"other worlds", bas:false} ] { {arg1: $arg1, arg2: $arg2, switch: $switch, named: $named, other: $other, hard: $hard, } } 〉use ~/work/dflts.nu 〉$nu.scope.commands | where name == 'dflts' | get signatures.0.any | reject short_flag description custom_completion ╭───┬────────────────┬────────────────┬──────────────────────────────────────────┬─────────────┬───────────────────────────╮ │ # │ parameter_name │ parameter_type │ syntax_shape │ is_optional │ parameter_default │ ├───┼────────────────┼────────────────┼──────────────────────────────────────────┼─────────────┼───────────────────────────┤ │ 0 │ │ input │ any │ false │ │ │ 1 │ arg1 │ positional │ string │ false │ │ │ 2 │ arg2 │ positional │ string │ true │ abc │ │ 3 │ switch │ switch │ │ true │ │ │ 4 │ named │ named │ int │ true │ │ │ 5 │ other │ named │ string │ true │ def │ │ 6 │ hard │ named │ record<foo: int, bar: string, bas: bool> │ true │ ╭───────┬───────────────╮ │ │ │ │ │ │ │ │ foo │ 22 │ │ │ │ │ │ │ │ │ bar │ other worlds │ │ │ │ │ │ │ │ │ bas │ false │ │ │ │ │ │ │ │ ╰───────┴───────────────╯ │ │ 7 │ │ output │ any │ false │ │ ╰───┴────────────────┴────────────────┴──────────────────────────────────────────┴─────────────┴───────────────────────────╯ 〉help dflts sample function to show defaults in help Usage: > dflts {flags} <arg1> (arg2) Flags: --switch - switch -- no default here --named <Int> - named flag, typed, but no default --other <String> - flag with default (default: 'def') --hard <Record([("foo", Int), ("bar", String), ("bas", Boolean)])> - default can be compound type (default: {foo: 22, bar: 'other worlds', bas: false}) -h, --help - Display the help message for this command Parameters: arg1 <string>: mandatory positional arg2 <string>: optional positional (optional, default: 'abc') ``` Compared to (relevant bits of) help output previously: ``` Flags: -h, --help - Display the help message for this command -, --switch - no default here -, --named <int> - named flag, no default -, --other <string> - flag -, --hard <record<foo: int, bar: string, bas: bool>> - default can be compound type Signatures: <any> | dflts <string> <string> -> <any> Parameters: arg1 <string>: mandatory positional (optional) arg2 <string>: optional positional ``` # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > [x] toolkit check pr > ``` --> # 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. -->
2023-05-11 18:59:56 +00:00
if let Some(val) = &opt.default_value {
val.clone()
} else {
Value::nothing(span)
},
];
sig_records.push(Value::Record {
cols: sig_cols.clone(),
vals: sig_vals,
span,
});
}
// rest_positional
if let Some(rest) = &signature.rest_positional {
let sig_vals = vec![
Value::string(if rest.name == "rest" { "" } else { &rest.name }, span),
Value::string("rest", span),
Value::string(rest.shape.to_string(), span),
Value::bool(true, span),
Value::nothing(span),
Value::string(&rest.desc, span),
Value::string(
extract_custom_completion_from_arg(self.engine_state, &rest.shape),
span,
),
Parameter defaults to $nu.scope.commands (#9152) (*third* try at posting this PR, #9104, like #9084, got polluted with unrelated commits. I'm never going to pull from the github feature branch again!) # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Show parameter defaults in scope command signature, where they're available for display by help. per https://github.com/nushell/nushell/issues/8928. I found unexpected ramifications in one completer (NuHelpCompleter) and plugins, which both use the flag-formatting routine from builtin help. For the moment I made the minimum necessary changes to get the mainline scenario to pass tests and run. But we should circle back on what to do with plugins and help completer.. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> 1. New `parameter_default` column to `signatures` table in `$nu.scope.commands` It is populated with whatever parameters can be defaulted: currently positional args and named flags. 2. Built in help (both `help <command>` and `<command> --help` will display the defaults 3. Help completer will display defaults for flags, but not for positionals. Example: A custom command with some default parameters: ``` 〉cat ~/work/dflts.nu # sample function to show defaults in help export def main [ arg1: string # mandatory positional arg2:string=abc # optional positional --switch # no default here --named:int # named flag, no default --other:string=def # flag --hard:record<foo:int bar:string, bas:bool> # default can be compound type = {foo:22, bar:"other worlds", bas:false} ] { {arg1: $arg1, arg2: $arg2, switch: $switch, named: $named, other: $other, hard: $hard, } } 〉use ~/work/dflts.nu 〉$nu.scope.commands | where name == 'dflts' | get signatures.0.any | reject short_flag description custom_completion ╭───┬────────────────┬────────────────┬──────────────────────────────────────────┬─────────────┬───────────────────────────╮ │ # │ parameter_name │ parameter_type │ syntax_shape │ is_optional │ parameter_default │ ├───┼────────────────┼────────────────┼──────────────────────────────────────────┼─────────────┼───────────────────────────┤ │ 0 │ │ input │ any │ false │ │ │ 1 │ arg1 │ positional │ string │ false │ │ │ 2 │ arg2 │ positional │ string │ true │ abc │ │ 3 │ switch │ switch │ │ true │ │ │ 4 │ named │ named │ int │ true │ │ │ 5 │ other │ named │ string │ true │ def │ │ 6 │ hard │ named │ record<foo: int, bar: string, bas: bool> │ true │ ╭───────┬───────────────╮ │ │ │ │ │ │ │ │ foo │ 22 │ │ │ │ │ │ │ │ │ bar │ other worlds │ │ │ │ │ │ │ │ │ bas │ false │ │ │ │ │ │ │ │ ╰───────┴───────────────╯ │ │ 7 │ │ output │ any │ false │ │ ╰───┴────────────────┴────────────────┴──────────────────────────────────────────┴─────────────┴───────────────────────────╯ 〉help dflts sample function to show defaults in help Usage: > dflts {flags} <arg1> (arg2) Flags: --switch - switch -- no default here --named <Int> - named flag, typed, but no default --other <String> - flag with default (default: 'def') --hard <Record([("foo", Int), ("bar", String), ("bas", Boolean)])> - default can be compound type (default: {foo: 22, bar: 'other worlds', bas: false}) -h, --help - Display the help message for this command Parameters: arg1 <string>: mandatory positional arg2 <string>: optional positional (optional, default: 'abc') ``` Compared to (relevant bits of) help output previously: ``` Flags: -h, --help - Display the help message for this command -, --switch - no default here -, --named <int> - named flag, no default -, --other <string> - flag -, --hard <record<foo: int, bar: string, bas: bool>> - default can be compound type Signatures: <any> | dflts <string> <string> -> <any> Parameters: arg1 <string>: mandatory positional (optional) arg2 <string>: optional positional ``` # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > [x] toolkit check pr > ``` --> # 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. -->
2023-05-11 18:59:56 +00:00
Value::nothing(span), // rest_positional does have default, but parser prohibits specifying it?!
];
sig_records.push(Value::Record {
cols: sig_cols.clone(),
vals: sig_vals,
span,
});
}
// named flags
for named in &signature.named {
let flag_type;
// Skip the help flag
if named.long == "help" {
continue;
}
let mut custom_completion_command_name: String = "".to_string();
let shape = if let Some(arg) = &named.arg {
flag_type = Value::string("named", span);
custom_completion_command_name =
extract_custom_completion_from_arg(self.engine_state, arg);
Value::string(arg.to_string(), span)
} else {
flag_type = Value::string("switch", span);
Value::nothing(span)
};
let short_flag = if let Some(c) = named.short {
Value::string(c, span)
} else {
Value::nothing(span)
};
let sig_vals = vec![
Value::string(&named.long, span),
flag_type,
shape,
Value::bool(!named.required, span),
short_flag,
Value::string(&named.desc, span),
Value::string(custom_completion_command_name, span),
Parameter defaults to $nu.scope.commands (#9152) (*third* try at posting this PR, #9104, like #9084, got polluted with unrelated commits. I'm never going to pull from the github feature branch again!) # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Show parameter defaults in scope command signature, where they're available for display by help. per https://github.com/nushell/nushell/issues/8928. I found unexpected ramifications in one completer (NuHelpCompleter) and plugins, which both use the flag-formatting routine from builtin help. For the moment I made the minimum necessary changes to get the mainline scenario to pass tests and run. But we should circle back on what to do with plugins and help completer.. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> 1. New `parameter_default` column to `signatures` table in `$nu.scope.commands` It is populated with whatever parameters can be defaulted: currently positional args and named flags. 2. Built in help (both `help <command>` and `<command> --help` will display the defaults 3. Help completer will display defaults for flags, but not for positionals. Example: A custom command with some default parameters: ``` 〉cat ~/work/dflts.nu # sample function to show defaults in help export def main [ arg1: string # mandatory positional arg2:string=abc # optional positional --switch # no default here --named:int # named flag, no default --other:string=def # flag --hard:record<foo:int bar:string, bas:bool> # default can be compound type = {foo:22, bar:"other worlds", bas:false} ] { {arg1: $arg1, arg2: $arg2, switch: $switch, named: $named, other: $other, hard: $hard, } } 〉use ~/work/dflts.nu 〉$nu.scope.commands | where name == 'dflts' | get signatures.0.any | reject short_flag description custom_completion ╭───┬────────────────┬────────────────┬──────────────────────────────────────────┬─────────────┬───────────────────────────╮ │ # │ parameter_name │ parameter_type │ syntax_shape │ is_optional │ parameter_default │ ├───┼────────────────┼────────────────┼──────────────────────────────────────────┼─────────────┼───────────────────────────┤ │ 0 │ │ input │ any │ false │ │ │ 1 │ arg1 │ positional │ string │ false │ │ │ 2 │ arg2 │ positional │ string │ true │ abc │ │ 3 │ switch │ switch │ │ true │ │ │ 4 │ named │ named │ int │ true │ │ │ 5 │ other │ named │ string │ true │ def │ │ 6 │ hard │ named │ record<foo: int, bar: string, bas: bool> │ true │ ╭───────┬───────────────╮ │ │ │ │ │ │ │ │ foo │ 22 │ │ │ │ │ │ │ │ │ bar │ other worlds │ │ │ │ │ │ │ │ │ bas │ false │ │ │ │ │ │ │ │ ╰───────┴───────────────╯ │ │ 7 │ │ output │ any │ false │ │ ╰───┴────────────────┴────────────────┴──────────────────────────────────────────┴─────────────┴───────────────────────────╯ 〉help dflts sample function to show defaults in help Usage: > dflts {flags} <arg1> (arg2) Flags: --switch - switch -- no default here --named <Int> - named flag, typed, but no default --other <String> - flag with default (default: 'def') --hard <Record([("foo", Int), ("bar", String), ("bas", Boolean)])> - default can be compound type (default: {foo: 22, bar: 'other worlds', bas: false}) -h, --help - Display the help message for this command Parameters: arg1 <string>: mandatory positional arg2 <string>: optional positional (optional, default: 'abc') ``` Compared to (relevant bits of) help output previously: ``` Flags: -h, --help - Display the help message for this command -, --switch - no default here -, --named <int> - named flag, no default -, --other <string> - flag -, --hard <record<foo: int, bar: string, bas: bool>> - default can be compound type Signatures: <any> | dflts <string> <string> -> <any> Parameters: arg1 <string>: mandatory positional (optional) arg2 <string>: optional positional ``` # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > [x] toolkit check pr > ``` --> # 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. -->
2023-05-11 18:59:56 +00:00
if let Some(val) = &named.default_value {
val.clone()
} else {
Value::nothing(span)
},
];
sig_records.push(Value::Record {
cols: sig_cols.clone(),
vals: sig_vals,
span,
});
}
// output
sig_records.push(Value::Record {
cols: sig_cols,
vals: vec![
Value::nothing(span),
Value::string("output", span),
Value::string(output_type.to_shape().to_string(), span),
Value::bool(false, span),
Value::nothing(span),
Value::nothing(span),
Value::nothing(span),
Parameter defaults to $nu.scope.commands (#9152) (*third* try at posting this PR, #9104, like #9084, got polluted with unrelated commits. I'm never going to pull from the github feature branch again!) # Description <!-- Thank you for improving Nushell. Please, check our [contributing guide](../CONTRIBUTING.md) and talk to the core team before making major changes. Description of your pull request goes here. **Provide examples and/or screenshots** if your changes affect the user experience. --> Show parameter defaults in scope command signature, where they're available for display by help. per https://github.com/nushell/nushell/issues/8928. I found unexpected ramifications in one completer (NuHelpCompleter) and plugins, which both use the flag-formatting routine from builtin help. For the moment I made the minimum necessary changes to get the mainline scenario to pass tests and run. But we should circle back on what to do with plugins and help completer.. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> 1. New `parameter_default` column to `signatures` table in `$nu.scope.commands` It is populated with whatever parameters can be defaulted: currently positional args and named flags. 2. Built in help (both `help <command>` and `<command> --help` will display the defaults 3. Help completer will display defaults for flags, but not for positionals. Example: A custom command with some default parameters: ``` 〉cat ~/work/dflts.nu # sample function to show defaults in help export def main [ arg1: string # mandatory positional arg2:string=abc # optional positional --switch # no default here --named:int # named flag, no default --other:string=def # flag --hard:record<foo:int bar:string, bas:bool> # default can be compound type = {foo:22, bar:"other worlds", bas:false} ] { {arg1: $arg1, arg2: $arg2, switch: $switch, named: $named, other: $other, hard: $hard, } } 〉use ~/work/dflts.nu 〉$nu.scope.commands | where name == 'dflts' | get signatures.0.any | reject short_flag description custom_completion ╭───┬────────────────┬────────────────┬──────────────────────────────────────────┬─────────────┬───────────────────────────╮ │ # │ parameter_name │ parameter_type │ syntax_shape │ is_optional │ parameter_default │ ├───┼────────────────┼────────────────┼──────────────────────────────────────────┼─────────────┼───────────────────────────┤ │ 0 │ │ input │ any │ false │ │ │ 1 │ arg1 │ positional │ string │ false │ │ │ 2 │ arg2 │ positional │ string │ true │ abc │ │ 3 │ switch │ switch │ │ true │ │ │ 4 │ named │ named │ int │ true │ │ │ 5 │ other │ named │ string │ true │ def │ │ 6 │ hard │ named │ record<foo: int, bar: string, bas: bool> │ true │ ╭───────┬───────────────╮ │ │ │ │ │ │ │ │ foo │ 22 │ │ │ │ │ │ │ │ │ bar │ other worlds │ │ │ │ │ │ │ │ │ bas │ false │ │ │ │ │ │ │ │ ╰───────┴───────────────╯ │ │ 7 │ │ output │ any │ false │ │ ╰───┴────────────────┴────────────────┴──────────────────────────────────────────┴─────────────┴───────────────────────────╯ 〉help dflts sample function to show defaults in help Usage: > dflts {flags} <arg1> (arg2) Flags: --switch - switch -- no default here --named <Int> - named flag, typed, but no default --other <String> - flag with default (default: 'def') --hard <Record([("foo", Int), ("bar", String), ("bas", Boolean)])> - default can be compound type (default: {foo: 22, bar: 'other worlds', bas: false}) -h, --help - Display the help message for this command Parameters: arg1 <string>: mandatory positional arg2 <string>: optional positional (optional, default: 'abc') ``` Compared to (relevant bits of) help output previously: ``` Flags: -h, --help - Display the help message for this command -, --switch - no default here -, --named <int> - named flag, no default -, --other <string> - flag -, --hard <record<foo: int, bar: string, bas: bool>> - default can be compound type Signatures: <any> | dflts <string> <string> -> <any> Parameters: arg1 <string>: mandatory positional (optional) arg2 <string>: optional positional ``` # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > [x] toolkit check pr > ``` --> # 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. -->
2023-05-11 18:59:56 +00:00
Value::nothing(span),
],
span,
});
sig_records
}
Added `help externs` command (#8403) # Description `help externs` - command, which list external commands Closes https://github.com/nushell/nushell/issues/8301 # User-Facing Changes ```nu $ help externs ╭───┬──────────────┬─────────────┬───────────────────────────────────────────────────╮ │ # │ name │ module_name │ usage │ ├───┼──────────────┼─────────────┼───────────────────────────────────────────────────┤ │ 0 │ git push │ completions │ Push changes │ │ │ │ │ │ │ 1 │ git fetch │ completions │ Download objects and refs from another repository │ │ │ │ │ │ │ 2 │ git checkout │ completions │ Check out git branches and files │ │ │ │ │ │ ╰───┴──────────────┴─────────────┴───────────────────────────────────────────────────╯ ``` # 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.
2023-03-15 17:40:27 +00:00
pub fn collect_externs(&self, span: Span) -> Vec<Value> {
let mut externals = vec![];
Remove broken compile-time overload system (#9677) # Description This PR removes the compile-time overload system. Unfortunately, this system never worked correctly because in a gradual type system where types can be `Any`, you don't have enough information to correctly resolve function calls with overloads. These resolutions must be done at runtime, if they're supported. That said, there's a bit of work that needs to go into resolving input/output types (here overloads do not execute separate commands, but the same command and each overload explains how each output type corresponds to input types). This PR also removes the type scope, which would give incorrect answers in cases where multiple subexpressions were used in a pipeline. # User-Facing Changes Finishes removing compile-time overloads. These were only used in a few places in the code base, but it's possible it may impact user code. I'll mark this as breaking change so we can review. # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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. -->
2023-07-13 19:05:03 +00:00
for (command_name, decl_id) in &self.decls_map {
Added `help externs` command (#8403) # Description `help externs` - command, which list external commands Closes https://github.com/nushell/nushell/issues/8301 # User-Facing Changes ```nu $ help externs ╭───┬──────────────┬─────────────┬───────────────────────────────────────────────────╮ │ # │ name │ module_name │ usage │ ├───┼──────────────┼─────────────┼───────────────────────────────────────────────────┤ │ 0 │ git push │ completions │ Push changes │ │ │ │ │ │ │ 1 │ git fetch │ completions │ Download objects and refs from another repository │ │ │ │ │ │ │ 2 │ git checkout │ completions │ Check out git branches and files │ │ │ │ │ │ ╰───┴──────────────┴─────────────┴───────────────────────────────────────────────────╯ ``` # 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.
2023-03-15 17:40:27 +00:00
let decl = self.engine_state.get_decl(**decl_id);
if decl.is_known_external() {
let mut cols = vec![];
let mut vals = vec![];
let mut module_commands = vec![];
for module in &self.modules_map {
let module_name = String::from_utf8_lossy(module.0).to_string();
let module_id = self.engine_state.find_module(module.0, &[]);
if let Some(module_id) = module_id {
let module = self.engine_state.get_module(module_id);
if module.has_decl(command_name) {
module_commands.push(module_name);
}
}
}
cols.push("name".into());
vals.push(Value::String {
val: String::from_utf8_lossy(command_name).to_string(),
span,
});
cols.push("module_name".into());
vals.push(Value::String {
val: module_commands.join(", "),
span,
});
cols.push("usage".to_string());
vals.push(Value::String {
val: decl.usage().into(),
span,
});
externals.push(Value::Record { cols, vals, span })
}
}
externals
}
2022-12-30 15:44:37 +00:00
pub fn collect_aliases(&self, span: Span) -> Vec<Value> {
let mut aliases = vec![];
Rename `main` to script name when running scripts (#9948) # Description This PR does three related changes: * Keeps the originally declared name in help outputs. * Updates the name of the commands called `main` in the user script to the name of the script. * Fixes the source of signature information in multiple places. This allows scripts to have more complete help output. Combined, the above allow the user to see the script name in the help output of scripts, like so: ![image](https://github.com/nushell/nushell/assets/547158/741d192c-0a39-45a7-8f36-3a0dc8eeae2b) NOTE: You still declare and call the definition `main`, so from inside the script `main` is still the correct name. But multiple folks agreed that seeing `main` in the script help was confusing, so this PR changes that. # User-Facing Changes One potential minor breaking change is that module renames will be shown as their originally defined name rather than the renamed name. I believe this to be a better default. # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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. -->
2023-08-11 17:58:49 +00:00
for (_, decl_id) in self.engine_state.get_decls_sorted(false) {
2023-03-10 18:14:55 +00:00
if self.visibility.is_decl_id_visible(&decl_id) {
let decl = self.engine_state.get_decl(decl_id);
if let Some(alias) = decl.as_alias() {
Rename `main` to script name when running scripts (#9948) # Description This PR does three related changes: * Keeps the originally declared name in help outputs. * Updates the name of the commands called `main` in the user script to the name of the script. * Fixes the source of signature information in multiple places. This allows scripts to have more complete help output. Combined, the above allow the user to see the script name in the help output of scripts, like so: ![image](https://github.com/nushell/nushell/assets/547158/741d192c-0a39-45a7-8f36-3a0dc8eeae2b) NOTE: You still declare and call the definition `main`, so from inside the script `main` is still the correct name. But multiple folks agreed that seeing `main` in the script help was confusing, so this PR changes that. # User-Facing Changes One potential minor breaking change is that module renames will be shown as their originally defined name rather than the renamed name. I believe this to be a better default. # 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 -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- -c "use std testing; testing run-tests --path crates/nu-std"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # 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. -->
2023-08-11 17:58:49 +00:00
let sig = decl.signature().update_from_command(decl.borrow());
2023-03-10 18:14:55 +00:00
let key = sig.name;
aliases.push(Value::Record {
cols: vec!["name".into(), "expansion".into(), "usage".into()],
vals: vec![
Value::String { val: key, span },
Value::String {
val: String::from_utf8_lossy(
self.engine_state.get_span_contents(alias.wrapped_call.span),
2023-03-10 18:14:55 +00:00
)
.to_string(),
span,
},
Value::String {
val: alias.signature().usage,
span,
},
],
span,
});
}
}
}
aliases.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
aliases
}
2022-12-30 15:44:37 +00:00
pub fn collect_modules(&self, span: Span) -> Vec<Value> {
let mut modules = vec![];
2022-12-30 15:44:37 +00:00
for (module_name, module_id) in &self.modules_map {
let module = self.engine_state.get_module(**module_id);
let export_commands: Vec<Value> = module
.decls()
.iter()
.filter(|(_, id)| {
self.visibility.is_decl_id_visible(id)
&& !self.engine_state.get_decl(*id).is_alias()
})
.map(|(bytes, _)| Value::string(String::from_utf8_lossy(bytes), span))
2022-12-30 15:44:37 +00:00
.collect();
let export_aliases: Vec<Value> = module
.decls()
.iter()
.filter(|(_, id)| {
self.visibility.is_decl_id_visible(id)
&& self.engine_state.get_decl(*id).is_alias()
})
.map(|(bytes, _)| Value::string(String::from_utf8_lossy(bytes), span))
2022-12-30 15:44:37 +00:00
.collect();
let export_env_block = module.env_block.map_or_else(
|| Value::nothing(span),
|block_id| Value::Block {
val: block_id,
span,
},
);
let module_usage = self
.engine_state
.build_module_usage(**module_id)
.map(|(usage, _)| usage)
.unwrap_or_default();
modules.push(Value::Record {
cols: vec![
"name".into(),
"commands".into(),
"aliases".into(),
"env_block".into(),
"usage".into(),
],
vals: vec![
Value::string(String::from_utf8_lossy(module_name), span),
Value::List {
vals: export_commands,
span,
},
Value::List {
vals: export_aliases,
span,
},
export_env_block,
Value::string(module_usage, span),
],
span,
});
}
modules.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
modules
}
2022-12-30 15:44:37 +00:00
pub fn collect_engine_state(&self, span: Span) -> Value {
let engine_state_cols = vec![
"source_bytes".to_string(),
"num_vars".to_string(),
"num_decls".to_string(),
"num_blocks".to_string(),
"num_modules".to_string(),
"num_env_vars".to_string(),
];
let engine_state_vals = vec![
Value::int(self.engine_state.next_span_start() as i64, span),
Value::int(self.engine_state.num_vars() as i64, span),
Value::int(self.engine_state.num_decls() as i64, span),
Value::int(self.engine_state.num_blocks() as i64, span),
Value::int(self.engine_state.num_modules() as i64, span),
Value::int(
self.engine_state
.env_vars
.values()
.map(|overlay| overlay.len() as i64)
.sum(),
span,
),
];
Value::Record {
cols: engine_state_cols,
vals: engine_state_vals,
span,
}
}
}
fn extract_custom_completion_from_arg(engine_state: &EngineState, shape: &SyntaxShape) -> String {
return match shape {
SyntaxShape::Custom(_, custom_completion_decl_id) => {
let custom_completion_command = engine_state.get_decl(*custom_completion_decl_id);
let custom_completion_command_name: &str = custom_completion_command.name();
custom_completion_command_name.to_string()
}
_ => "".to_string(),
};
}