nu_command/system/
complete.rs1use nu_engine::command_prelude::*;
2use nu_protocol::OutDest;
3
4#[derive(Clone)]
5pub struct Complete;
6
7impl Command for Complete {
8 fn name(&self) -> &str {
9 "complete"
10 }
11
12 fn signature(&self) -> Signature {
13 Signature::build("complete")
14 .category(Category::System)
15 .input_output_types(vec![(Type::Any, Type::record())])
16 }
17
18 fn description(&self) -> &str {
19 "Capture the outputs and exit code from an external piped in command in a nushell table."
20 }
21
22 fn extra_description(&self) -> &str {
23 r#"In order to capture stdout, stderr, and exit_code, externally piped in commands need to be wrapped with `do`"#
24 }
25
26 fn run(
27 &self,
28 _engine_state: &EngineState,
29 _stack: &mut Stack,
30 call: &Call,
31 input: PipelineData,
32 ) -> Result<PipelineData, ShellError> {
33 let head = call.head;
34 match input {
35 PipelineData::ByteStream(stream, ..) => {
36 let Ok(mut child) = stream.into_child() else {
37 return Err(ShellError::GenericError {
38 error: "Complete only works with external commands".into(),
39 msg: "complete only works on external commands".into(),
40 span: Some(call.head),
41 help: None,
42 inner: vec![],
43 });
44 };
45
46 #[cfg(feature = "os")]
50 child.ignore_error(true);
51
52 let output = child.wait_with_output()?;
53 let exit_code = output.exit_status.code();
54 let mut record = Record::new();
55
56 if let Some(stdout) = output.stdout {
57 record.push(
58 "stdout",
59 match String::from_utf8(stdout) {
60 Ok(str) => Value::string(str, head),
61 Err(err) => Value::binary(err.into_bytes(), head),
62 },
63 );
64 }
65
66 if let Some(stderr) = output.stderr {
67 record.push(
68 "stderr",
69 match String::from_utf8(stderr) {
70 Ok(str) => Value::string(str, head),
71 Err(err) => Value::binary(err.into_bytes(), head),
72 },
73 );
74 }
75
76 record.push("exit_code", Value::int(exit_code.into(), head));
77
78 Ok(Value::record(record, call.head).into_pipeline_data())
79 }
80 PipelineData::Value(Value::Error { error, .. }, _) => Err(*error),
82 _ => Err(ShellError::GenericError {
83 error: "Complete only works with external commands".into(),
84 msg: "complete only works on external commands".into(),
85 span: Some(head),
86 help: None,
87 inner: vec![],
88 }),
89 }
90 }
91
92 fn examples(&self) -> Vec<Example<'_>> {
93 vec![Example {
94 description: "Run the external command to completion, capturing stdout, stderr, and exit_code",
95 example: "^external arg1 | complete",
96 result: None,
97 }]
98 }
99
100 fn pipe_redirection(&self) -> (Option<OutDest>, Option<OutDest>) {
101 (Some(OutDest::PipeSeparate), Some(OutDest::PipeSeparate))
102 }
103}