Skip to main content

nu_cmd_lang/core_commands/scope/
variables.rs

1use nu_engine::{command_prelude::*, scope::ScopeData};
2
3#[derive(Clone)]
4pub struct ScopeVariables;
5
6impl Command for ScopeVariables {
7    fn name(&self) -> &str {
8        "scope variables"
9    }
10
11    fn signature(&self) -> Signature {
12        Signature::build("scope variables")
13            .input_output_types(vec![(Type::Nothing, Type::Any)])
14            .allow_variants_without_examples(true)
15            .category(Category::Core)
16    }
17
18    fn description(&self) -> &str {
19        "Output info on the variables in the current scope."
20    }
21
22    fn extra_description(&self) -> &str {
23        "Lists variables that are available at runtime in the current stack and active overlays \
24(locals and globals). Nested scopes such as `do`, `if`/`for` bodies, and custom commands include \
25their locals while that scope is active; outer locals remain visible when the outer frame is still \
26on the stack.
27
28Closures only capture free variables that are referenced in the closure body. An outer local that \
29is never mentioned is not captured, so after the defining scope ends it will not appear in \
30`scope variables` when that closure runs. Mentioning the variable (for example `$a`) causes it to \
31be captured and listed.
32
33For example, this shows `$a` inside the `do` block, but not when the returned closure runs later:
34
35    do {
36      let a = 123
37      scope variables | where name == '$a' | print
38      {|| scope variables | where name == '$a' }
39    } | let factory
40    do $factory
41
42Adding a reference to `$a` in the closure body captures it so it appears:
43
44    {|| $a; scope variables | where name == '$a' }"
45    }
46
47    fn run(
48        &self,
49        engine_state: &EngineState,
50        stack: &mut Stack,
51        call: &Call,
52        _input: PipelineData,
53    ) -> Result<PipelineData, ShellError> {
54        let head = call.head;
55        let mut scope_data = ScopeData::new(engine_state, stack);
56        scope_data.populate_vars();
57        Ok(Value::list(scope_data.collect_vars(head), head).into_pipeline_data())
58    }
59
60    fn examples(&self) -> Vec<Example<'_>> {
61        vec![Example {
62            description: "Show the variables in the current scope.",
63            example: "scope variables",
64            result: None,
65        }]
66    }
67}
68
69#[cfg(test)]
70mod test {
71    use super::*;
72
73    #[test]
74    fn test_examples() -> nu_test_support::Result {
75        nu_test_support::test().examples(ScopeVariables)
76    }
77}