slash_lib/builtins/
write.rs1use slash_lang::parser::ast::Arg;
2
3use crate::command::{MethodDef, SlashCommand};
4use crate::executor::{CommandOutput, ExecutionError, PipeValue};
5
6pub struct Write;
11
12impl SlashCommand for Write {
13 fn name(&self) -> &str {
14 "write"
15 }
16
17 fn methods(&self) -> &[MethodDef] {
18 static METHODS: [MethodDef; 1] = [MethodDef::flag("append")];
19 &METHODS
20 }
21
22 fn execute(
23 &self,
24 primary: Option<&str>,
25 args: &[Arg],
26 input: Option<&PipeValue>,
27 ) -> Result<CommandOutput, ExecutionError> {
28 let path = primary.ok_or_else(|| {
29 ExecutionError::Runner("/write requires a path: /write(file.txt)".into())
30 })?;
31
32 let data = match input {
33 Some(PipeValue::Bytes(b)) => b.as_slice(),
34 Some(PipeValue::Context(ctx)) => {
35 let json = ctx.to_json();
36 return write_data(path, json.as_bytes(), args);
37 }
38 None => return Err(ExecutionError::Runner("/write: no piped input".into())),
39 };
40
41 write_data(path, data, args)
42 }
43}
44
45fn write_data(path: &str, data: &[u8], args: &[Arg]) -> Result<CommandOutput, ExecutionError> {
46 let append = args.iter().any(|a| a.name == "append");
47
48 if append {
49 use std::io::Write as _;
50 let mut file = std::fs::OpenOptions::new()
51 .create(true)
52 .append(true)
53 .open(path)
54 .map_err(|e| ExecutionError::Runner(format!("/write({}): {}", path, e)))?;
55 file.write_all(data)
56 .map_err(|e| ExecutionError::Runner(format!("/write({}): {}", path, e)))?;
57 } else {
58 std::fs::write(path, data)
59 .map_err(|e| ExecutionError::Runner(format!("/write({}): {}", path, e)))?;
60 }
61
62 Ok(CommandOutput {
63 stdout: None,
64 stderr: None,
65 success: true,
66 })
67}