nu_command/debug/
metadata.rs1use 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 {
34 true
35 }
36
37 fn run(
38 &self,
39 engine_state: &EngineState,
40 stack: &mut Stack,
41 call: &Call,
42 input: PipelineData,
43 ) -> Result<PipelineData, ShellError> {
44 let arg = call.positional_nth(stack, 0);
45 let head = call.head;
46
47 if !matches!(input, PipelineData::Empty)
48 && let Some(arg_expr) = arg
49 {
50 return Err(ShellError::IncompatibleParameters {
51 left_message: "pipeline input was provided".into(),
52 left_span: head,
53 right_message: "but a positional metadata expression was also given".into(),
54 right_span: arg_expr.span,
55 });
56 }
57
58 match arg {
59 Some(Expression {
60 expr: Expr::FullCellPath(full_cell_path),
61 span,
62 ..
63 }) => {
64 if full_cell_path.tail.is_empty() {
65 match &full_cell_path.head {
66 Expression {
67 expr: Expr::Var(var_id),
68 ..
69 } => {
70 let origin = stack.get_var_with_origin(*var_id, *span)?;
71 Ok(
72 build_metadata_record_value(&origin, input.metadata_ref(), head)
73 .into_pipeline_data(),
74 )
75 }
76 _ => {
77 let val: Value = call.req(engine_state, stack, 0)?;
78 Ok(
79 build_metadata_record_value(&val, input.metadata_ref(), head)
80 .into_pipeline_data(),
81 )
82 }
83 }
84 } else {
85 let val: Value = call.req(engine_state, stack, 0)?;
86 Ok(
87 build_metadata_record_value(&val, input.metadata_ref(), head)
88 .into_pipeline_data(),
89 )
90 }
91 }
92 Some(_) => {
93 let val: Value = call.req(engine_state, stack, 0)?;
94 Ok(
95 build_metadata_record_value(&val, input.metadata_ref(), head)
96 .into_pipeline_data(),
97 )
98 }
99 None => {
100 Ok(Value::record(build_metadata_record(&input, head), head).into_pipeline_data())
101 }
102 }
103 }
104
105 fn examples(&self) -> Vec<Example<'_>> {
106 vec![
107 Example {
108 description: "Get the metadata of a variable.",
109 example: "let a = 42; metadata $a",
110 result: None,
111 },
112 Example {
113 description: "Get the metadata of the input.",
114 example: "ls | metadata",
115 result: None,
116 },
117 ]
118 }
119}
120
121fn build_metadata_record_value(
122 arg: &Value,
123 metadata: Option<&PipelineMetadata>,
124 head: Span,
125) -> Value {
126 let mut record = Record::new();
127 record.push("span", arg.span().into_value(head));
128 Value::record(extend_record_with_metadata(record, metadata, head), head)
129}
130
131#[cfg(test)]
132mod test {
133 use super::*;
134
135 #[test]
136 fn test_examples() -> nu_test_support::Result {
137 nu_test_support::test().examples(Metadata)
138 }
139}