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(
71 build_metadata_record_value(&origin, input.metadata_ref(), head)
72 .into_pipeline_data(),
73 )
74 }
75 _ => {
76 let val: Value = call.req(engine_state, stack, 0)?;
77 Ok(
78 build_metadata_record_value(&val, input.metadata_ref(), head)
79 .into_pipeline_data(),
80 )
81 }
82 }
83 } else {
84 let val: Value = call.req(engine_state, stack, 0)?;
85 Ok(
86 build_metadata_record_value(&val, input.metadata_ref(), head)
87 .into_pipeline_data(),
88 )
89 }
90 }
91 Some(_) => {
92 let val: Value = call.req(engine_state, stack, 0)?;
93 Ok(
94 build_metadata_record_value(&val, input.metadata_ref(), head)
95 .into_pipeline_data(),
96 )
97 }
98 None => {
99 Ok(Value::record(build_metadata_record(&input, head), head).into_pipeline_data())
100 }
101 }
102 }
103
104 fn examples(&self) -> Vec<Example<'_>> {
105 vec![
106 Example {
107 description: "Get the metadata of a variable.",
108 example: "let a = 42; metadata $a",
109 result: None,
110 },
111 Example {
112 description: "Get the metadata of the input.",
113 example: "ls | metadata",
114 result: None,
115 },
116 ]
117 }
118}
119
120fn build_metadata_record_value(
121 arg: &Value,
122 metadata: Option<&PipelineMetadata>,
123 head: Span,
124) -> Value {
125 let mut record = Record::new();
126 record.push("span", arg.span().into_value(head));
127 Value::record(extend_record_with_metadata(record, metadata, head), head)
128}
129
130#[cfg(test)]
131mod test {
132 use super::*;
133
134 #[test]
135 fn test_examples() -> nu_test_support::Result {
136 nu_test_support::test().examples(Metadata)
137 }
138}