1use nu_engine::command_prelude::*;
2
3#[derive(Clone)]
4pub struct Debug;
5
6impl Command for Debug {
7 fn name(&self) -> &str {
8 "debug"
9 }
10
11 fn description(&self) -> &str {
12 "Debug print the value(s) piped in."
13 }
14
15 fn signature(&self) -> Signature {
16 Signature::build("debug")
17 .input_output_types(vec![
18 (
19 Type::List(Box::new(Type::Any)),
20 Type::List(Box::new(Type::String)),
21 ),
22 (Type::Any, Type::String),
23 ])
24 .category(Category::Debug)
25 .switch("raw", "Prints the raw value representation", Some('r'))
26 .switch(
27 "raw-value",
28 "Prints the raw value representation but not the nushell value part",
29 Some('v'),
30 )
31 }
32
33 fn run(
34 &self,
35 engine_state: &EngineState,
36 stack: &mut Stack,
37 call: &Call,
38 input: PipelineData,
39 ) -> Result<PipelineData, ShellError> {
40 let head = call.head;
41 let config = stack.get_config(engine_state);
42 let raw = call.has_flag(engine_state, stack, "raw")?;
43 let raw_value = call.has_flag(engine_state, stack, "raw-value")?;
44
45 input.map(
48 move |x| {
49 if raw {
50 Value::string(x.to_debug_string(), head)
51 } else if raw_value {
52 match x.coerce_into_string_all() {
53 Ok(s) => Value::string(format!("{s:#?}"), head),
54 Err(e) => Value::error(e, head),
55 }
56 } else {
57 Value::string(x.to_expanded_string(", ", &config), head)
58 }
59 },
60 engine_state.signals(),
61 )
62 }
63
64 fn examples(&self) -> Vec<Example<'_>> {
65 vec![
66 Example {
67 description: "Debug print a string",
68 example: "'hello' | debug",
69 result: Some(Value::test_string("hello")),
70 },
71 Example {
72 description: "Debug print a list",
73 example: "['hello'] | debug",
74 result: Some(Value::list(
75 vec![Value::test_string("hello")],
76 Span::test_data(),
77 )),
78 },
79 Example {
80 description: "Debug print a table",
81 example: "[[version patch]; ['0.1.0' false] ['0.1.1' true] ['0.2.0' false]] | debug",
82 result: Some(Value::list(
83 vec![
84 Value::test_string("{version: 0.1.0, patch: false}"),
85 Value::test_string("{version: 0.1.1, patch: true}"),
86 Value::test_string("{version: 0.2.0, patch: false}"),
87 ],
88 Span::test_data(),
89 )),
90 },
91 Example {
92 description: "Debug print an ansi escape encoded string and get the raw value",
93 example: "$'(ansi red)nushell(ansi reset)' | debug -v",
94 result: Some(Value::test_string("\"\\u{1b}[31mnushell\\u{1b}[0m\"")),
95 },
96 ]
97 }
98}
99
100trait ValueExt {
103 fn coerce_into_string_all(&self) -> Result<String, ShellError>;
104 fn cant_convert_to<T>(&self, typ: &str) -> Result<T, ShellError>;
105}
106
107impl ValueExt for Value {
108 fn cant_convert_to<T>(&self, typ: &str) -> Result<T, ShellError> {
109 Err(ShellError::CantConvert {
110 to_type: typ.into(),
111 from_type: self.get_type().to_string(),
112 span: self.span(),
113 help: None,
114 })
115 }
116
117 fn coerce_into_string_all(&self) -> Result<String, ShellError> {
118 let span = self.span();
119 match self {
120 Value::Bool { val, .. } => Ok(val.to_string()),
121 Value::Int { val, .. } => Ok(val.to_string()),
122 Value::Float { val, .. } => Ok(val.to_string()),
123 Value::String { val, .. } => Ok(val.to_string()),
124 Value::Glob { val, .. } => Ok(val.to_string()),
125 Value::Filesize { val, .. } => Ok(val.get().to_string()),
126 Value::Duration { val, .. } => Ok(val.to_string()),
127 Value::Date { val, .. } => Ok(val.to_rfc3339_opts(chrono::SecondsFormat::Nanos, true)),
128 Value::Range { val, .. } => Ok(val.to_string()),
129 Value::Record { val, .. } => Ok(format!(
130 "{{{}}}",
131 val.iter()
132 .map(|(x, y)| match y.coerce_into_string_all() {
133 Ok(value) => format!("{x}: {value}"),
134 Err(err) => format!("Error: {err}"),
135 })
136 .collect::<Vec<_>>()
137 .join(", ")
138 )),
139 Value::List { vals, .. } => Ok(format!(
140 "[{}]",
141 vals.iter()
142 .map(|x| match x.coerce_into_string_all() {
143 Ok(value) => value,
144 Err(err) => format!("Error: {err}"),
145 })
146 .collect::<Vec<_>>()
147 .join(", ")
148 )),
149 Value::Binary { val, .. } => match String::from_utf8(val.to_vec()) {
150 Ok(s) => Ok(s),
151 Err(err) => Value::binary(err.into_bytes(), span).cant_convert_to("string"),
152 },
153 Value::CellPath { val, .. } => Ok(val.to_string()),
154 Value::Nothing { .. } => Ok("nothing".to_string()),
155 val => val.cant_convert_to("string"),
156 }
157 }
158}
159
160#[cfg(test)]
161mod test {
162 #[test]
163 fn test_examples() {
164 use super::Debug;
165 use crate::test_examples;
166 test_examples(Debug {})
167 }
168}