1use crate::{error::to_shell_err, globals::get_pwd};
2use nu_engine::CallExt;
3use nu_protocol::{
4 Category, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
5 engine::{Command, EngineState, Stack},
6};
7use vfs::VfsError;
8
9#[derive(Clone)]
10pub struct Save;
11
12impl Command for Save {
13 fn name(&self) -> &str {
14 "save"
15 }
16
17 fn signature(&self) -> Signature {
18 Signature::build("save")
19 .required("path", SyntaxShape::Filepath, "path to write the data to")
20 .input_output_types(vec![(Type::Any, Type::Nothing)])
21 .category(Category::FileSystem)
22 }
23
24 fn description(&self) -> &str {
25 "save content to a file in the virtual filesystem."
26 }
27
28 fn run(
29 &self,
30 engine_state: &EngineState,
31 stack: &mut Stack,
32 call: &nu_protocol::engine::Call,
33 input: PipelineData,
34 ) -> Result<PipelineData, ShellError> {
35 let path: String = call.req(engine_state, stack, 0)?;
36
37 let value = input.into_value(call.head)?;
38 let contents = match value {
39 Value::String { val, .. } => val.into_bytes(),
40 Value::Binary { val, .. } => val,
41 Value::Bool { val, .. } => val.to_string().into_bytes(),
42 Value::Float { val, .. } => val.to_string().into_bytes(),
43 Value::Int { val, .. } => val.to_string().into_bytes(),
44 Value::Date { val, .. } => val.to_string().into_bytes(),
45 _ => {
46 return Err(ShellError::CantConvert {
47 to_type: "string".to_string(),
48 from_type: value.get_type().to_string(),
49 span: value.span(),
50 help: None,
51 });
52 }
53 };
54
55 let target_file = get_pwd().join(&path).map_err(to_shell_err(call.head))?;
56
57 target_file
58 .create_file()
59 .map_err(to_shell_err(call.head))
60 .and_then(|mut f| {
61 f.write_all(&contents)
62 .map_err(VfsError::from)
63 .map_err(to_shell_err(call.head))
64 })
65 .map(|_| PipelineData::Empty)
66 }
67}