spreadsheet_mcp/cli/commands/
write.rs1use crate::core::types::CellEdit;
2use crate::model::Warning;
3use crate::runtime::stateless::StatelessRuntime;
4use anyhow::{Context, Result, bail};
5use serde::Serialize;
6use serde_json::Value;
7use std::path::PathBuf;
8
9#[derive(Debug, Serialize)]
10struct CopyResponse {
11 source: String,
12 dest: String,
13 bytes_copied: u64,
14}
15
16#[derive(Debug, Serialize)]
17struct EditResponse {
18 file: String,
19 sheet: String,
20 edits_applied: usize,
21 recalc_needed: bool,
22 warnings: Vec<Warning>,
23}
24
25pub async fn copy(source: PathBuf, dest: PathBuf) -> Result<Value> {
26 let runtime = StatelessRuntime;
27 let source = runtime.normalize_existing_file(&source)?;
28 let dest = runtime.normalize_destination_path(&dest)?;
29 let bytes_copied = runtime.copy_file(&source, &dest).with_context(|| {
30 format!(
31 "failed to copy workbook from '{}' to '{}'",
32 source.display(),
33 dest.display()
34 )
35 })?;
36
37 Ok(serde_json::to_value(CopyResponse {
38 source: source.display().to_string(),
39 dest: dest.display().to_string(),
40 bytes_copied,
41 })?)
42}
43
44pub async fn edit(file: PathBuf, sheet: String, edits: Vec<String>) -> Result<Value> {
45 if edits.is_empty() {
46 bail!("at least one edit must be provided");
47 }
48
49 let runtime = StatelessRuntime;
50 let file = runtime.normalize_existing_file(&file)?;
51
52 let mut normalized_edits = Vec::with_capacity(edits.len());
53 let mut warnings = Vec::new();
54 for (idx, entry) in edits.into_iter().enumerate() {
55 let (edit, entry_warnings) = crate::core::write::normalize_shorthand_edit(&entry)
56 .with_context(|| format!("invalid shorthand edit at index {}", idx))?;
57 normalized_edits.push(edit);
58 warnings.extend(entry_warnings.into_iter().map(|warning| Warning {
59 code: warning.code,
60 message: warning.message,
61 }));
62 }
63
64 runtime.apply_edits(&file, &sheet, &normalized_edits)?;
65
66 Ok(serde_json::to_value(EditResponse {
67 file: file.display().to_string(),
68 sheet,
69 edits_applied: normalized_edits.len(),
70 recalc_needed: true,
71 warnings,
72 })?)
73}
74
75pub fn parse_shorthand_for_tests(entries: Vec<String>) -> Result<(Vec<CellEdit>, Vec<Warning>)> {
76 let mut edits = Vec::with_capacity(entries.len());
77 let mut warnings = Vec::new();
78 for entry in entries {
79 let (edit, entry_warnings) = crate::core::write::normalize_shorthand_edit(&entry)?;
80 edits.push(edit);
81 warnings.extend(entry_warnings.into_iter().map(|warning| Warning {
82 code: warning.code,
83 message: warning.message,
84 }));
85 }
86 Ok((edits, warnings))
87}