use std::io::{self, BufRead};
use anyhow::{Context, Result};
use colored::Colorize;
use crate::helpers::*;
pub(crate) fn cmd_template(
profile: &str,
file: &str,
output: Option<&str>,
ignore_missing: bool,
) -> Result<()> {
let vault = open_vault(profile)?;
let all = vault.export_all()?;
let template = std::fs::read_to_string(file)
.with_context(|| format!("could not read template file: {file}"))?;
let mut result = template.clone();
let re_pattern = "{{";
let mut pos = 0;
let mut missing = Vec::new();
while let Some(start) = result[pos..].find(re_pattern) {
let abs_start = pos + start;
if let Some(end) = result[abs_start + 2..].find("}}") {
let abs_end = abs_start + 2 + end;
let key = result[abs_start + 2..abs_end].trim();
if let Some(value) = all.get(key) {
let placeholder = &result[abs_start..abs_end + 2];
result = result.replacen(placeholder, value, 1);
} else {
if !ignore_missing {
missing.push(key.to_string());
}
pos = abs_end + 2;
}
} else {
break;
}
}
if !missing.is_empty() {
anyhow::bail!(
"template has unknown placeholders: {}\nUse --ignore-missing to skip them.",
missing.join(", ")
);
}
if let Some(out_path) = output {
let tmp = format!("{out_path}.tmp");
std::fs::write(&tmp, &result)?;
std::fs::rename(&tmp, out_path)?;
println!("{} Written to {}", "✓".green(), out_path);
} else {
print!("{result}");
}
Ok(())
}
pub(crate) fn cmd_redact(profile: &str) -> Result<()> {
let vault = open_vault(profile)?;
let all = vault.export_all()?;
let mut values: Vec<&str> = all.values().map(String::as_str).collect();
values.sort_by_key(|b| std::cmp::Reverse(b.len()));
let values: Vec<&str> = values.into_iter().filter(|v| v.len() > 2).collect();
drop(vault);
let stdin = io::stdin();
for line in stdin.lock().lines() {
let mut line = line?;
for val in &values {
if line.contains(val) {
line = line.replace(val, "[REDACTED]");
}
}
println!("{line}");
}
Ok(())
}