use std::path::Path;
use std::sync::Arc;
use serde::Serialize;
use void_core::workspace::stage::{reset_paths, ResetOptions};
use crate::context::{build_void_context, void_err_to_cli};
use crate::observer::ProgressObserver;
use crate::output::{run_command, CliError, CliOptions};
#[derive(Debug, Clone, Serialize)]
pub struct ResetOutput {
pub reset: Vec<String>,
pub count: usize,
}
pub fn run(cwd: &Path, paths: Vec<String>, opts: &CliOptions) -> Result<(), CliError> {
let paths: Vec<String> = paths.into_iter().filter(|p| !p.trim().is_empty()).collect();
let patterns = if paths.is_empty() {
vec![".".to_string()]
} else {
paths
};
run_command("reset", opts, |ctx| {
let void_ctx = build_void_context(cwd)?;
let observer: Arc<ProgressObserver> = if ctx.use_json() {
Arc::new(ProgressObserver::new_hidden())
} else {
Arc::new(ProgressObserver::new("Resetting files..."))
};
let reset_opts = ResetOptions {
ctx: void_ctx,
patterns,
observer: Some(observer.clone()),
};
let result = reset_paths(reset_opts).map_err(void_err_to_cli)?;
observer.finish();
if !ctx.use_json() {
if result.reset.is_empty() {
ctx.info("Nothing to reset");
} else {
for path in &result.reset {
ctx.info(format!("Unstaged: {}", path));
}
ctx.info(format!("\n{} file(s) unstaged", result.reset.len()));
}
}
let count = result.reset.len();
Ok(ResetOutput {
reset: result.reset,
count,
})
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reset_output_serialization() {
let output = ResetOutput {
reset: vec!["src/main.rs".to_string(), "src/lib.rs".to_string()],
count: 2,
};
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("\"reset\""));
assert!(json.contains("\"count\":2"));
assert!(json.contains("src/main.rs"));
assert!(json.contains("src/lib.rs"));
}
#[test]
fn test_reset_output_empty() {
let output = ResetOutput {
reset: vec![],
count: 0,
};
let json = serde_json::to_string(&output).unwrap();
assert!(json.contains("\"reset\":[]"));
assert!(json.contains("\"count\":0"));
}
}