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