diff --git a/crates/nu-cli/src/completions.rs b/crates/nu-cli/src/completions.rs index 0a93d151f..0f1c372ab 100644 --- a/crates/nu-cli/src/completions.rs +++ b/crates/nu-cli/src/completions.rs @@ -86,7 +86,7 @@ impl NuCompleter { ) -> Vec<(reedline::Span, String)> { let mut output = vec![]; - let builtins = ["$nu", "$scope", "$in", "$config", "$env", "$nothing"]; + let builtins = ["$nu", "$in", "$config", "$env", "$nothing"]; for builtin in builtins { if builtin.as_bytes().starts_with(prefix) { diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 3ec587e81..e4abf2507 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -672,6 +672,343 @@ pub fn eval_subexpression( Ok(input) } +pub fn create_scope( + engine_state: &EngineState, + stack: &Stack, + span: Span, +) -> Result { + let mut output_cols = vec![]; + let mut output_vals = vec![]; + + let mut vars = vec![]; + + let mut commands = vec![]; + let mut aliases = vec![]; + let mut overlays = vec![]; + + for frame in &engine_state.scope { + for var in &frame.vars { + let var_name = Value::string(String::from_utf8_lossy(var.0).to_string(), span); + + let var_type = Value::string(engine_state.get_var(*var.1).to_string(), span); + + let var_value = if let Ok(val) = 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, + }) + } + + for command in &frame.decls { + let mut cols = vec![]; + let mut vals = vec![]; + + cols.push("command".into()); + vals.push(Value::String { + val: String::from_utf8_lossy(command.0).to_string(), + span, + }); + + let decl = engine_state.get_decl(*command.1); + let signature = decl.signature(); + cols.push("category".to_string()); + vals.push(Value::String { + val: signature.category.to_string(), + span, + }); + + // signature + let mut sig_records = vec![]; + { + let sig_cols = vec![ + "command".to_string(), + "parameter_name".to_string(), + "parameter_type".to_string(), + "syntax_shape".to_string(), + "is_optional".to_string(), + "short_flag".to_string(), + "description".to_string(), + ]; + + // required_positional + for req in signature.required_positional { + let sig_vals = vec![ + Value::string(&signature.name, span), + Value::string(req.name, span), + Value::string("positional", span), + Value::string(req.shape.to_string(), span), + Value::boolean(false, span), + Value::nothing(span), + Value::string(req.desc, 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(&signature.name, span), + Value::string(opt.name, span), + Value::string("positional", span), + Value::string(opt.shape.to_string(), span), + Value::boolean(true, span), + Value::nothing(span), + Value::string(opt.desc, 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(&signature.name, span), + Value::string(rest.name, span), + Value::string("rest", span), + Value::string(rest.shape.to_string(), span), + Value::boolean(true, span), + Value::nothing(span), + Value::string(rest.desc, span), + ]; + + 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 shape = if let Some(arg) = named.arg { + flag_type = Value::string("named", span); + 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(&signature.name, span), + Value::string(named.long, span), + flag_type, + shape, + Value::boolean(!named.required, span), + short_flag, + Value::string(named.desc, span), + ]; + + sig_records.push(Value::Record { + cols: sig_cols.clone(), + vals: sig_vals, + span, + }); + } + } + + cols.push("signature".to_string()); + vals.push(Value::List { + vals: sig_records, + 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 { + cols: vec!["description".into(), "example".into()], + vals: vec![ + Value::String { + val: x.description.to_string(), + span, + }, + Value::String { + val: x.example.to_string(), + span, + }, + ], + span, + }) + .collect(), + span, + }); + + cols.push("is_binary".to_string()); + vals.push(Value::Bool { + val: decl.is_binary(), + span, + }); + + cols.push("is_private".to_string()); + vals.push(Value::Bool { + val: decl.is_private(), + span, + }); + + cols.push("is_builtin".to_string()); + vals.push(Value::Bool { + val: decl.is_builtin(), + 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.get_block_id().is_some(), + 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, + }); + + commands.push(Value::Record { cols, vals, span }) + } + + for (alias_name, alias_id) in &frame.aliases { + let alias = engine_state.get_alias(*alias_id); + let mut alias_text = String::new(); + for span in alias { + let contents = engine_state.get_span_contents(span); + if !alias_text.is_empty() { + alias_text.push(' '); + } + alias_text.push_str(&String::from_utf8_lossy(contents).to_string()); + } + aliases.push(( + Value::String { + val: String::from_utf8_lossy(alias_name).to_string(), + span, + }, + Value::string(alias_text, span), + )); + } + + for overlay in &frame.overlays { + overlays.push(Value::String { + val: String::from_utf8_lossy(overlay.0).to_string(), + span, + }); + } + } + + output_cols.push("vars".to_string()); + output_vals.push(Value::List { vals: vars, 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, + }); + output_cols.push("commands".to_string()); + output_vals.push(Value::List { + vals: commands, + span, + }); + + aliases.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); + output_cols.push("aliases".to_string()); + output_vals.push(Value::List { + vals: aliases + .into_iter() + .map(|(alias, value)| Value::Record { + cols: vec!["alias".into(), "expansion".into()], + vals: vec![alias, value], + span, + }) + .collect(), + span, + }); + + overlays.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); + output_cols.push("overlays".to_string()); + output_vals.push(Value::List { + vals: overlays, + span, + }); + + Ok(Value::Record { + cols: output_cols, + vals: output_vals, + span, + }) +} + pub fn eval_variable( engine_state: &EngineState, stack: &Stack, @@ -723,6 +1060,9 @@ pub fn eval_variable( output_cols.push("cwd".into()); output_vals.push(Value::String { val: cwd, span }); + output_cols.push("scope".into()); + output_vals.push(create_scope(engine_state, stack, span)?); + if let Some(home_path) = nu_path::home_dir() { if let Some(home_path_str) = home_path.to_str() { output_cols.push("home-path".into()); @@ -748,339 +1088,6 @@ pub fn eval_variable( span, }) } - nu_protocol::SCOPE_VARIABLE_ID => { - let mut output_cols = vec![]; - let mut output_vals = vec![]; - - let mut vars = vec![]; - - let mut commands = vec![]; - let mut aliases = vec![]; - let mut overlays = vec![]; - - for frame in &engine_state.scope { - for var in &frame.vars { - let var_name = Value::string(String::from_utf8_lossy(var.0).to_string(), span); - - let var_type = Value::string(engine_state.get_var(*var.1).to_string(), span); - - let var_value = if let Ok(val) = 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, - }) - } - - for command in &frame.decls { - let mut cols = vec![]; - let mut vals = vec![]; - - cols.push("command".into()); - vals.push(Value::String { - val: String::from_utf8_lossy(command.0).to_string(), - span, - }); - - let decl = engine_state.get_decl(*command.1); - let signature = decl.signature(); - cols.push("category".to_string()); - vals.push(Value::String { - val: signature.category.to_string(), - span, - }); - - // signature - let mut sig_records = vec![]; - { - let sig_cols = vec![ - "command".to_string(), - "parameter_name".to_string(), - "parameter_type".to_string(), - "syntax_shape".to_string(), - "is_optional".to_string(), - "short_flag".to_string(), - "description".to_string(), - ]; - - // required_positional - for req in signature.required_positional { - let sig_vals = vec![ - Value::string(&signature.name, span), - Value::string(req.name, span), - Value::string("positional", span), - Value::string(req.shape.to_string(), span), - Value::boolean(false, span), - Value::nothing(span), - Value::string(req.desc, 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(&signature.name, span), - Value::string(opt.name, span), - Value::string("positional", span), - Value::string(opt.shape.to_string(), span), - Value::boolean(true, span), - Value::nothing(span), - Value::string(opt.desc, 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(&signature.name, span), - Value::string(rest.name, span), - Value::string("rest", span), - Value::string(rest.shape.to_string(), span), - Value::boolean(true, span), - Value::nothing(span), - Value::string(rest.desc, span), - ]; - - 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 shape = if let Some(arg) = named.arg { - flag_type = Value::string("named", span); - 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(&signature.name, span), - Value::string(named.long, span), - flag_type, - shape, - Value::boolean(!named.required, span), - short_flag, - Value::string(named.desc, span), - ]; - - sig_records.push(Value::Record { - cols: sig_cols.clone(), - vals: sig_vals, - span, - }); - } - } - - cols.push("signature".to_string()); - vals.push(Value::List { - vals: sig_records, - 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 { - cols: vec!["description".into(), "example".into()], - vals: vec![ - Value::String { - val: x.description.to_string(), - span, - }, - Value::String { - val: x.example.to_string(), - span, - }, - ], - span, - }) - .collect(), - span, - }); - - cols.push("is_binary".to_string()); - vals.push(Value::Bool { - val: decl.is_binary(), - span, - }); - - cols.push("is_private".to_string()); - vals.push(Value::Bool { - val: decl.is_private(), - span, - }); - - cols.push("is_builtin".to_string()); - vals.push(Value::Bool { - val: decl.is_builtin(), - 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.get_block_id().is_some(), - 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, - }); - - commands.push(Value::Record { cols, vals, span }) - } - - for (alias_name, alias_id) in &frame.aliases { - let alias = engine_state.get_alias(*alias_id); - let mut alias_text = String::new(); - for span in alias { - let contents = engine_state.get_span_contents(span); - if !alias_text.is_empty() { - alias_text.push(' '); - } - alias_text.push_str(&String::from_utf8_lossy(contents).to_string()); - } - aliases.push(( - Value::String { - val: String::from_utf8_lossy(alias_name).to_string(), - span, - }, - Value::string(alias_text, span), - )); - } - - for overlay in &frame.overlays { - overlays.push(Value::String { - val: String::from_utf8_lossy(overlay.0).to_string(), - span, - }); - } - } - - output_cols.push("vars".to_string()); - output_vals.push(Value::List { vals: vars, 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, - }); - output_cols.push("commands".to_string()); - output_vals.push(Value::List { - vals: commands, - span, - }); - - aliases.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); - output_cols.push("aliases".to_string()); - output_vals.push(Value::List { - vals: aliases - .into_iter() - .map(|(alias, value)| Value::Record { - cols: vec!["alias".into(), "expansion".into()], - vals: vec![alias, value], - span, - }) - .collect(), - span, - }); - - overlays.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); - output_cols.push("overlays".to_string()); - output_vals.push(Value::List { - vals: overlays, - span, - }); - - Ok(Value::Record { - cols: output_cols, - vals: output_vals, - span, - }) - } ENV_VARIABLE_ID => { let env_vars = stack.get_env_vars(engine_state); let env_columns = env_vars.keys(); diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 08f0abe29..a039afe92 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1556,16 +1556,6 @@ pub fn parse_variable_expr( }, None, ); - } else if contents == b"$scope" { - return ( - Expression { - expr: Expr::Var(nu_protocol::SCOPE_VARIABLE_ID), - span, - ty: Type::Unknown, - custom_completion: None, - }, - None, - ); } else if contents == b"$in" { return ( Expression { diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index ddd2e5bde..fcb6512ad 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -175,10 +175,9 @@ pub struct EngineState { } pub const NU_VARIABLE_ID: usize = 0; -pub const SCOPE_VARIABLE_ID: usize = 1; -pub const IN_VARIABLE_ID: usize = 2; -pub const CONFIG_VARIABLE_ID: usize = 3; -pub const ENV_VARIABLE_ID: usize = 4; +pub const IN_VARIABLE_ID: usize = 1; +pub const CONFIG_VARIABLE_ID: usize = 2; +pub const ENV_VARIABLE_ID: usize = 3; // NOTE: If you add more to this list, make sure to update the > checks based on the last in the list impl EngineState { diff --git a/crates/nu-protocol/src/lib.rs b/crates/nu-protocol/src/lib.rs index 60e45b2bb..f60956b85 100644 --- a/crates/nu-protocol/src/lib.rs +++ b/crates/nu-protocol/src/lib.rs @@ -15,9 +15,7 @@ mod value; pub use value::Value; pub use config::*; -pub use engine::{ - CONFIG_VARIABLE_ID, ENV_VARIABLE_ID, IN_VARIABLE_ID, NU_VARIABLE_ID, SCOPE_VARIABLE_ID, -}; +pub use engine::{CONFIG_VARIABLE_ID, ENV_VARIABLE_ID, IN_VARIABLE_ID, NU_VARIABLE_ID}; pub use example::*; pub use exportable::*; pub use id::*; diff --git a/docs/Modules_and_Overlays.md b/docs/Modules_and_Overlays.md index 930d86fa9..e37f79245 100644 --- a/docs/Modules_and_Overlays.md +++ b/docs/Modules_and_Overlays.md @@ -25,7 +25,7 @@ You can say that the module `greetings` exports an overlay which consists of two By itself, the module does not do anything. We can verify its existence by printing all available overlays: ``` -> $scope.overlays +> $nu.scope.overlays ╭───┬───────────╮ │ 0 │ greetings │ ╰───┴───────────╯ @@ -306,7 +306,7 @@ It creates the `$config` variable using the module system. ## Known Issues -* It might be more appropriate to use `$scope.modules` instead of `$scope.overlays` +* It might be more appropriate to use `$nu.scope.modules` instead of `$nu.scope.overlays` ## Future Design Ideas diff --git a/docs/make_docs.nu b/docs/make_docs.nu index 23d62d686..a06d62635 100644 --- a/docs/make_docs.nu +++ b/docs/make_docs.nu @@ -1,6 +1,6 @@ let vers = (version).version -for command in ($scope.commands | where is_custom == false && is_extern == false) { +for command in ($nu.scope.commands | where is_custom == false && is_extern == false) { let top = $"--- title: ($command.command) layout: command diff --git a/src/tests/test_engine.rs b/src/tests/test_engine.rs index 5ad9ab4c7..634b2d53d 100644 --- a/src/tests/test_engine.rs +++ b/src/tests/test_engine.rs @@ -78,7 +78,7 @@ fn help_works_with_missing_requirements() -> TestResult { #[test] fn scope_variable() -> TestResult { run_test( - r#"let x = 3; $scope.vars | where name == "$x" | get type.0"#, + r#"let x = 3; $nu.scope.vars | where name == "$x" | get type.0"#, "int", ) }