use clap::Args;
use serde::Serialize;
use crate::commands::Output;
use crate::error::Result;
use crate::fs::FileSystem;
use crate::vault::VaultManager;
#[derive(Args)]
pub struct CatArgs {
pub path: String,
#[arg(short, long)]
pub version: Option<u64>,
}
#[derive(Serialize)]
struct CatOutput {
path: String,
content: String,
size: usize,
version: Option<u64>,
}
pub fn run(args: CatArgs, output: &Output, vault: Option<String>) -> Result<()> {
let manager = VaultManager::new()?;
let backend = match vault {
Some(name) => manager.open(&name)?,
None => manager.open_current()?,
};
let fs = FileSystem::new(backend.clone());
let content = if let Some(version_num) = args.version {
let entry = fs.get_entry(&args.path)?;
if !entry.is_file() {
return Err(crate::error::VfsError::NotAFile(
std::path::PathBuf::from(&args.path),
));
}
backend.get_version_content(entry.id, version_num)?
} else {
fs.read_file(&args.path)?
};
if output.is_json() {
let content_str = String::from_utf8_lossy(&content).to_string();
output.print_json(&CatOutput {
path: args.path,
content: content_str,
size: content.len(),
version: args.version,
});
} else {
match String::from_utf8(content.clone()) {
Ok(text) => print!("{}", text),
Err(_) => {
eprintln!("(binary file, {} bytes)", content.len());
}
}
}
Ok(())
}