Skip to main content

slash_lib/builtins/
write.rs

1use slash_lang::parser::ast::Arg;
2
3use crate::command::{MethodDef, SlashCommand};
4use crate::executor::{CommandOutput, ExecutionError, PipeValue};
5
6/// `/write(path)` — write piped input to a file.
7///
8/// Pure `std::fs::write`. Overwrites by default.
9/// `/write(path).append` — append instead of overwrite.
10pub 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}