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

557 lines
21 KiB
Rust
Raw Normal View History

use nu_protocol::{
ast::Expr,
2023-03-10 18:14:55 +00:00
engine::{Command, EngineState, Stack, Visibility},
record, ModuleId, Signature, Span, SyntaxShape, Type, Value,
};
use std::{cmp::Ordering, collections::HashMap};
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(),
}
}
2023-08-17 08:58:38 +00:00
pub fn populate_vars(&mut self) {
for overlay_frame in self.engine_state.active_overlays(&[]) {
self.vars_map.extend(&overlay_frame.vars);
2023-08-17 08:58:38 +00:00
}
}
// decls include all commands, i.e., normal commands, aliases, and externals
pub fn populate_decls(&mut self) {
for overlay_frame in self.engine_state.active_overlays(&[]) {
self.decls_map.extend(&overlay_frame.decls);
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![];
2023-08-17 08:58:38 +00:00
for (var_name, var_id) in &self.vars_map {
let var_name = Value::string(String::from_utf8_lossy(var_name).to_string(), span);
let var = self.engine_state.get_var(**var_id);
let var_type = Value::string(var.ty.to_string(), span);
let is_const = Value::bool(var.const_val.is_some(), span);
2023-08-17 08:58:38 +00:00
let var_value = if let Ok(val) = self.stack.get_var(**var_id, span) {
val
} else {
Value::nothing(span)
};
2023-08-17 08:58:38 +00:00
let var_id_val = Value::int(**var_id as i64, span);
vars.push(Value::record(
record! {
"name" => var_name,
"type" => var_type,
"value" => var_value,
"is_const" => is_const,
"var_id" => var_id_val,
},
span,
));
}
sort_rows(&mut vars);
vars
}
2022-12-30 15:44:37 +00:00
pub fn collect_commands(&self, span: Span) -> Vec<Value> {
let mut commands = vec![];
2023-08-17 08:58:38 +00:00
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 decl = self.engine_state.get_decl(**decl_id);
let signature = decl.signature();
let examples = decl
.examples()
.into_iter()
.map(|x| {
Value::record(
record! {
"description" => Value::string(x.description, span),
"example" => Value::string(x.example, span),
"result" => x.result.unwrap_or(Value::nothing(span)),
},
span,
)
})
.collect();
let record = record! {
"name" => Value::string(String::from_utf8_lossy(command_name), span),
"category" => Value::string(signature.category.to_string(), span),
"signatures" => self.collect_signatures(&signature, span),
"usage" => Value::string(decl.usage(), span),
"examples" => Value::list(examples, span),
"type" => Value::string(decl.command_type().to_string(), span),
"is_sub" => Value::bool(decl.is_sub(), span),
"creates_scope" => Value::bool(signature.creates_scope, span),
"extra_usage" => Value::string(decl.extra_usage(), span),
"search_terms" => Value::string(decl.search_terms().join(", "), span),
"decl_id" => Value::int(**decl_id as i64, span),
};
commands.push(Value::record(record, span))
}
}
sort_rows(&mut commands);
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(),
Move Value to helpers, separate span call (#10121) # Description As part of the refactor to split spans off of Value, this moves to using helper functions to create values, and using `.span()` instead of matching span out of Value directly. Hoping to get a few more helping hands to finish this, as there are a lot of commands to update :) # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `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. --> --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: WindSoilder <windsoilder@outlook.com>
2023-09-03 14:27:29 +00:00
Value::list(
self.collect_signature_entries(input_type, output_type, signature, span),
span,
Move Value to helpers, separate span call (#10121) # Description As part of the refactor to split spans off of Value, this moves to using helper functions to create values, and using `.span()` instead of matching span out of Value directly. Hoping to get a few more helping hands to finish this, as there are a lot of commands to update :) # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `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. --> --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: WindSoilder <windsoilder@outlook.com>
2023-09-03 14:27:29 +00:00
),
)
})
.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(),
Move Value to helpers, separate span call (#10121) # Description As part of the refactor to split spans off of Value, this moves to using helper functions to create values, and using `.span()` instead of matching span out of Value directly. Hoping to get a few more helping hands to finish this, as there are a lot of commands to update :) # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `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. --> --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: WindSoilder <windsoilder@outlook.com>
2023-09-03 14:27:29 +00:00
Value::list(
self.collect_signature_entries(any_type, any_type, signature, span),
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
span,
Move Value to helpers, separate span call (#10121) # Description As part of the refactor to split spans off of Value, this moves to using helper functions to create values, and using `.span()` instead of matching span out of Value directly. Hoping to get a few more helping hands to finish this, as there are a lot of commands to update :) # 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` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `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. --> --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: WindSoilder <windsoilder@outlook.com>
2023-09-03 14:27:29 +00:00
),
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
));
}
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);
Value::record(sigs.into_iter().collect(), span)
}
fn collect_signature_entries(
&self,
input_type: &Type,
output_type: &Type,
signature: &Signature,
span: Span,
) -> Vec<Value> {
let mut sig_records = vec![];
// input
sig_records.push(Value::record(
record! {
"parameter_name" => Value::nothing(span),
"parameter_type" => Value::string("input", span),
"syntax_shape" => Value::string(input_type.to_shape().to_string(), span),
"is_optional" => Value::bool(false, span),
"short_flag" => Value::nothing(span),
"description" => Value::nothing(span),
"custom_completion" => Value::nothing(span),
"parameter_default" => Value::nothing(span),
},
span,
));
// required_positional
for req in &signature.required_positional {
let custom = extract_custom_completion_from_arg(self.engine_state, &req.shape);
sig_records.push(Value::record(
record! {
"parameter_name" => Value::string(&req.name, span),
"parameter_type" => Value::string("positional", span),
"syntax_shape" => Value::string(req.shape.to_string(), span),
"is_optional" => Value::bool(false, span),
"short_flag" => Value::nothing(span),
"description" => Value::string(&req.desc, span),
"custom_completion" => Value::string(custom, span),
"parameter_default" => Value::nothing(span),
},
span,
));
}
// optional_positional
for opt in &signature.optional_positional {
let custom = extract_custom_completion_from_arg(self.engine_state, &opt.shape);
let default = if let Some(val) = &opt.default_value {
val.clone()
} else {
Value::nothing(span)
};
sig_records.push(Value::record(
record! {
"parameter_name" => Value::string(&opt.name, span),
"parameter_type" => Value::string("positional", span),
"syntax_shape" => Value::string(opt.shape.to_string(), span),
"is_optional" => Value::bool(true, span),
"short_flag" => Value::nothing(span),
"description" => Value::string(&opt.desc, span),
"custom_completion" => Value::string(custom, span),
"parameter_default" => default,
},
span,
));
}
// rest_positional
if let Some(rest) = &signature.rest_positional {
let name = if rest.name == "rest" { "" } else { &rest.name };
let custom = extract_custom_completion_from_arg(self.engine_state, &rest.shape);
sig_records.push(Value::record(
record! {
"parameter_name" => Value::string(name, span),
"parameter_type" => Value::string("rest", span),
"syntax_shape" => Value::string(rest.shape.to_string(), span),
"is_optional" => Value::bool(true, span),
"short_flag" => Value::nothing(span),
"description" => Value::string(&rest.desc, span),
"custom_completion" => Value::string(custom, span),
// rest_positional does have default, but parser prohibits specifying it?!
"parameter_default" => Value::nothing(span),
},
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 default = if let Some(val) = &named.default_value {
val.clone()
} else {
Value::nothing(span)
};
sig_records.push(Value::record(
record! {
"parameter_name" => Value::string(&named.long, span),
"parameter_type" => flag_type,
"syntax_shape" => shape,
"is_optional" => Value::bool(!named.required, span),
"short_flag" => short_flag,
"description" => Value::string(&named.desc, span),
"custom_completion" => Value::string(custom_completion_command_name, span),
"parameter_default" => default,
},
span,
));
}
// output
sig_records.push(Value::record(
record! {
"parameter_name" => Value::nothing(span),
"parameter_type" => Value::string("output", span),
"syntax_shape" => Value::string(output_type.to_shape().to_string(), span),
"is_optional" => Value::bool(false, span),
"short_flag" => Value::nothing(span),
"description" => Value::nothing(span),
"custom_completion" => Value::nothing(span),
"parameter_default" => 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![];
2023-08-17 08:58:38 +00:00
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 record = record! {
"name" => Value::string(String::from_utf8_lossy(command_name), span),
"usage" => Value::string(decl.usage(), span),
"decl_id" => Value::int(**decl_id as i64, span),
};
2023-08-17 08:58:38 +00:00
externals.push(Value::record(record, span))
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
}
}
sort_rows(&mut externals);
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
externals
}
2022-12-30 15:44:37 +00:00
pub fn collect_aliases(&self, span: Span) -> Vec<Value> {
let mut aliases = vec![];
2023-08-17 08:58:38 +00:00
for (decl_name, 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() {
let aliased_decl_id = if let Expr::Call(wrapped_call) = &alias.wrapped_call.expr
{
Value::int(wrapped_call.decl_id as i64, span)
} else {
Value::nothing(span)
};
let expansion = String::from_utf8_lossy(
self.engine_state.get_span_contents(alias.wrapped_call.span),
);
aliases.push(Value::record(
record! {
"name" => Value::string(String::from_utf8_lossy(&decl_name), span),
"expansion" => Value::string(expansion, span),
"usage" => Value::string(alias.usage(), span),
"decl_id" => Value::int(decl_id as i64, span),
"aliased_decl_id" => aliased_decl_id,
},
2023-03-10 18:14:55 +00:00
span,
));
2023-03-10 18:14:55 +00:00
}
}
}
sort_rows(&mut aliases);
// aliases.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
aliases
}
2023-08-17 08:58:38 +00:00
fn collect_module(&self, module_name: &[u8], module_id: &ModuleId, span: Span) -> Value {
let module = self.engine_state.get_module(*module_id);
2023-08-17 08:58:38 +00:00
let all_decls = module.decls();
2022-12-30 15:44:37 +00:00
let mut export_commands: Vec<Value> = all_decls
2023-08-17 08:58:38 +00:00
.iter()
.filter_map(|(name_bytes, decl_id)| {
let decl = self.engine_state.get_decl(*decl_id);
if !decl.is_alias() && !decl.is_known_external() {
Some(Value::record(
record! {
"name" => Value::string(String::from_utf8_lossy(name_bytes), span),
"decl_id" => Value::int(*decl_id as i64, span),
},
2023-08-17 08:58:38 +00:00
span,
))
} else {
None
}
})
.collect();
2022-12-30 15:44:37 +00:00
let mut export_aliases: Vec<Value> = all_decls
2023-08-17 08:58:38 +00:00
.iter()
.filter_map(|(name_bytes, decl_id)| {
let decl = self.engine_state.get_decl(*decl_id);
if decl.is_alias() {
Some(Value::record(
record! {
"name" => Value::string(String::from_utf8_lossy(name_bytes), span),
"decl_id" => Value::int(*decl_id as i64, span),
},
2022-12-30 15:44:37 +00:00
span,
2023-08-17 08:58:38 +00:00
))
} else {
None
}
})
.collect();
let mut export_externs: Vec<Value> = all_decls
2023-08-17 08:58:38 +00:00
.iter()
.filter_map(|(name_bytes, decl_id)| {
let decl = self.engine_state.get_decl(*decl_id);
if decl.is_known_external() {
Some(Value::record(
record! {
"name" => Value::string(String::from_utf8_lossy(name_bytes), span),
"decl_id" => Value::int(*decl_id as i64, span),
},
2022-12-30 15:44:37 +00:00
span,
2023-08-17 08:58:38 +00:00
))
} else {
None
}
})
.collect();
let mut export_submodules: Vec<Value> = module
2023-08-17 08:58:38 +00:00
.submodules()
.iter()
.map(|(name_bytes, submodule_id)| self.collect_module(name_bytes, submodule_id, span))
.collect();
let mut export_consts: Vec<Value> = module
Recursively export constants from modules (#10049) <!-- if this PR closes one or more issues, you can automatically link the PR with them by using one of the [*linking keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword), e.g. - this PR should close #xxxx - fixes #xxxx you can also mention related issues, PRs or discussions! --> # 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. --> https://github.com/nushell/nushell/pull/9773 introduced constants to modules and allowed to export them, but only within one level. This PR: * allows recursive exporting of constants from all submodules * fixes submodule imports in a list import pattern * makes sure exported constants are actual constants Should unblock https://github.com/nushell/nushell/pull/9678 ### Example: ```nushell module spam { export module eggs { export module bacon { export const viking = 'eats' } } } use spam print $spam.eggs.bacon.viking # prints 'eats' use spam [eggs] print $eggs.bacon.viking # prints 'eats' use spam eggs bacon viking print $viking # prints 'eats' ``` ### Limitation 1: Considering the above `spam` module, attempting to get `eggs bacon` from `spam` module doesn't work directly: ```nushell use spam [ eggs bacon ] # attempts to load `eggs`, then `bacon` use spam [ "eggs bacon" ] # obviously wrong name for a constant, but doesn't work also for commands ``` Workaround (for example): ```nushell use spam eggs use eggs [ bacon ] print $bacon.viking # prints 'eats' ``` I'm thinking I'll just leave it in, as you can easily work around this. It is also a limitation of the import pattern in general, not just constants. ### Limitation 2: `overlay use` successfully imports the constants, but `overlay hide` does not hide them, even though it seems to hide normal variables successfully. This needs more investigation. # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> Allows recursive constant exports from submodules. # 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-20 12:51:35 +00:00
.consts()
2023-08-17 08:58:38 +00:00
.iter()
.map(|(name_bytes, var_id)| {
Value::record(
record! {
"name" => Value::string(String::from_utf8_lossy(name_bytes), span),
"type" => Value::string(self.engine_state.get_var(*var_id).ty.to_string(), span),
"var_id" => Value::int(*var_id as i64, span),
},
2023-08-17 08:58:38 +00:00
span,
)
})
.collect();
sort_rows(&mut export_commands);
sort_rows(&mut export_aliases);
sort_rows(&mut export_externs);
sort_rows(&mut export_submodules);
sort_rows(&mut export_consts);
let (module_usage, module_extra_usage) = self
2023-08-17 08:58:38 +00:00
.engine_state
.build_module_usage(*module_id)
.unwrap_or_default();
Value::record(
record! {
"name" => Value::string(String::from_utf8_lossy(module_name), span),
"commands" => Value::list(export_commands, span),
"aliases" => Value::list(export_aliases, span),
"externs" => Value::list(export_externs, span),
"submodules" => Value::list(export_submodules, span),
"constants" => Value::list(export_consts, span),
"has_env_block" => Value::bool(module.env_block.is_some(), span),
"usage" => Value::string(module_usage, span),
"extra_usage" => Value::string(module_extra_usage, span),
"module_id" => Value::int(*module_id as i64, span),
},
2023-08-17 08:58:38 +00:00
span,
)
2023-08-17 08:58:38 +00:00
}
pub fn collect_modules(&self, span: Span) -> Vec<Value> {
let mut modules = vec![];
for (module_name, module_id) in &self.modules_map {
modules.push(self.collect_module(module_name, module_id, span));
}
2023-08-17 08:58:38 +00:00
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 num_env_vars = self
.engine_state
.env_vars
.values()
.map(|overlay| overlay.len() as i64)
.sum();
Value::record(
record! {
"source_bytes" => Value::int(self.engine_state.next_span_start() as i64, span),
"num_vars" => Value::int(self.engine_state.num_vars() as i64, span),
"num_decls" => Value::int(self.engine_state.num_decls() as i64, span),
"num_blocks" => Value::int(self.engine_state.num_blocks() as i64, span),
"num_modules" => Value::int(self.engine_state.num_modules() as i64, span),
"num_env_vars" => Value::int(num_env_vars, span),
},
span,
)
}
}
fn extract_custom_completion_from_arg(engine_state: &EngineState, shape: &SyntaxShape) -> String {
return match shape {
SyntaxShape::CompleterWrapper(_, 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(),
};
}
fn sort_rows(decls: &mut [Value]) {
decls.sort_by(|a, b| match (a, b) {
(Value::Record { val: rec_a, .. }, Value::Record { val: rec_b, .. }) => {
// Comparing the first value from the record
// It is expected that the first value is the name of the entry (command, module, alias, etc.)
match (rec_a.values().next(), rec_b.values().next()) {
(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,
});
}