disk.rs

2.0 kB · rust · 66 lines

1use crate::model::Result;2use std::cell::RefCell;3use std::io::Write;4use std::path::{Path, PathBuf};5use std::process::{Command, Stdio};67const EDITION: &str = "2021";89thread_local! {10    static STALE: RefCell<Option<Vec<PathBuf>>> = const { RefCell::new(None) };11}1213pub fn watch() {14    STALE.with(|stale| *stale.borrow_mut() = Some(Vec::new()));15}1617pub fn stale() -> Vec<PathBuf> {18    STALE.with(|stale| stale.borrow_mut().take().unwrap_or_default())19}2021pub fn save(path: &Path, text: &str) -> Result<()> {22    let at = |e: String| format!("{}: {e}", path.display());23    let text = if path.extension().is_some_and(|e| e == "rs") {24        rustfmt(text).map_err(at)?25    } else {26        text.to_string()27    };28    if std::fs::read_to_string(path).ok().as_deref() == Some(text.as_str()) {29        return Ok(());30    }31    let watched = STALE.with(|stale| {32        let mut stale = stale.borrow_mut();33        if let Some(list) = stale.as_mut() {34            list.push(path.to_path_buf());35        }36        stale.is_some()37    });38    if watched {39        return Ok(());40    }41    if let Some(dir) = path.parent() {42        std::fs::create_dir_all(dir).map_err(|e| at(e.to_string()))?;43    }44    std::fs::write(path, text).map_err(|e| at(e.to_string()))45}4647pub fn rustfmt(text: &str) -> Result<String> {48    let mut child = Command::new("rustfmt")49        .args(["--edition", EDITION])50        .stdin(Stdio::piped())51        .stdout(Stdio::piped())52        .stderr(Stdio::piped())53        .spawn()54        .map_err(|e| format!("rustfmt: {e}"))?;55    let mut stdin = child.stdin.take().ok_or("rustfmt: no stdin")?;56    let out = std::thread::scope(|scope| {57        scope.spawn(move || stdin.write_all(text.as_bytes()));58        child.wait_with_output()59    })60    .map_err(|e| format!("rustfmt: {e}"))?;61    if !out.status.success() {62        let said = String::from_utf8_lossy(&out.stderr);63        return Err(format!("rustfmt: {}", said.trim()));64    }65    String::from_utf8(out.stdout).map_err(|e| format!("rustfmt: {e}"))66}