nu_command/debug/
metadata.rs

1use super::util::{build_metadata_record, extend_record_with_metadata};
2use nu_engine::command_prelude::*;
3use nu_protocol::{
4    PipelineMetadata,
5    ast::{Expr, Expression},
6};
7
8#[derive(Clone)]
9pub struct Metadata;
10
11impl Command for Metadata {
12    fn name(&self) -> &str {
13        "metadata"
14    }
15
16    fn description(&self) -> &str {
17        "Get the metadata for items in the stream."
18    }
19
20    fn signature(&self) -> nu_protocol::Signature {
21        Signature::build("metadata")
22            .input_output_types(vec![(Type::Any, Type::record())])
23            .allow_variants_without_examples(true)
24            .optional(
25                "expression",
26                SyntaxShape::Any,
27                "The expression you want metadata for.",
28            )
29            .category(Category::Debug)
30    }
31
32    fn requires_ast_for_arguments(&self) -> bool {
33        true
34    }
35
36    fn run(
37        &self,
38        engine_state: &EngineState,
39        stack: &mut Stack,
40        call: &Call,
41        input: PipelineData,
42    ) -> Result<PipelineData, ShellError> {
43        let arg = call.positional_nth(stack, 0);
44        let head = call.head;
45
46        match arg {
47            Some(Expression {
48                expr: Expr::FullCellPath(full_cell_path),
49                span,
50                ..
51            }) => {
52                if full_cell_path.tail.is_empty() {
53                    match &full_cell_path.head {
54                        Expression {
55                            expr: Expr::Var(var_id),
56                            ..
57                        } => {
58                            let origin = stack.get_var_with_origin(*var_id, *span)?;
59
60                            Ok(build_metadata_record_value(
61                                &origin,
62                                input.metadata().as_ref(),
63                                head,
64                            )
65                            .into_pipeline_data())
66                        }
67                        _ => {
68                            let val: Value = call.req(engine_state, stack, 0)?;
69                            Ok(
70                                build_metadata_record_value(&val, input.metadata().as_ref(), head)
71                                    .into_pipeline_data(),
72                            )
73                        }
74                    }
75                } else {
76                    let val: Value = call.req(engine_state, stack, 0)?;
77                    Ok(
78                        build_metadata_record_value(&val, input.metadata().as_ref(), head)
79                            .into_pipeline_data(),
80                    )
81                }
82            }
83            Some(_) => {
84                let val: Value = call.req(engine_state, stack, 0)?;
85                Ok(
86                    build_metadata_record_value(&val, input.metadata().as_ref(), head)
87                        .into_pipeline_data(),
88                )
89            }
90            None => Ok(
91                Value::record(build_metadata_record(input.metadata().as_ref(), head), head)
92                    .into_pipeline_data(),
93            ),
94        }
95    }
96
97    fn examples(&self) -> Vec<Example> {
98        vec![
99            Example {
100                description: "Get the metadata of a variable",
101                example: "let a = 42; metadata $a",
102                result: None,
103            },
104            Example {
105                description: "Get the metadata of the input",
106                example: "ls | metadata",
107                result: None,
108            },
109        ]
110    }
111}
112
113fn build_metadata_record_value(
114    arg: &Value,
115    metadata: Option<&PipelineMetadata>,
116    head: Span,
117) -> Value {
118    let mut record = Record::new();
119
120    let span = arg.span();
121    record.push(
122        "span",
123        Value::record(
124            record! {
125                "start" => Value::int(span.start as i64,span),
126                "end" => Value::int(span.end as i64, span),
127            },
128            head,
129        ),
130    );
131
132    Value::record(extend_record_with_metadata(record, metadata, head), head)
133}
134
135#[cfg(test)]
136mod test {
137    use super::*;
138
139    #[test]
140    fn test_examples() {
141        use crate::test_examples;
142
143        test_examples(Metadata {})
144    }
145}