llm_coding_tools_core/operations/
write.rs1use crate::error::ToolResult;
4use crate::fs;
5use crate::path::PathResolver;
6
7#[maybe_async::maybe_async]
11pub async fn write_file<R: PathResolver>(
12 resolver: &R,
13 file_path: &str,
14 content: &str,
15) -> ToolResult<String> {
16 let path = resolver.resolve(file_path)?;
17
18 if let Some(parent) = path.parent() {
20 if !parent.as_os_str().is_empty() {
21 fs::create_dir_all(parent).await?;
22 }
23 }
24
25 let bytes = content.as_bytes();
26 fs::write(&path, bytes).await?;
27
28 Ok(format!(
29 "Successfully wrote {} bytes to {}",
30 bytes.len(),
31 path.display()
32 ))
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use crate::path::AbsolutePathResolver;
39 use tempfile::TempDir;
40
41 #[maybe_async::test(feature = "blocking", async(not(feature = "blocking"), tokio::test))]
42 async fn write_creates_new_file() {
43 let temp = TempDir::new().unwrap();
44 let file_path = temp.path().join("new_file.txt");
45 let resolver = AbsolutePathResolver;
46
47 let result = write_file(&resolver, file_path.to_str().unwrap(), "hello world")
48 .await
49 .unwrap();
50
51 assert!(result.contains("11 bytes"));
52 assert_eq!(std::fs::read_to_string(&file_path).unwrap(), "hello world");
53 }
54
55 #[maybe_async::test(feature = "blocking", async(not(feature = "blocking"), tokio::test))]
56 async fn write_creates_parent_directories() {
57 let temp = TempDir::new().unwrap();
58 let file_path = temp.path().join("a/b/c/deep.txt");
59 let resolver = AbsolutePathResolver;
60
61 write_file(&resolver, file_path.to_str().unwrap(), "nested")
62 .await
63 .unwrap();
64
65 assert!(file_path.exists());
66 }
67}