use std::io::Write;
use std::process::{Command, Stdio};
use crate::config::{AppConfig, GlobalConfig};
pub fn create_note(name: Option<String>, template_override: Option<String>, body_content: Option<String>) {
let global = GlobalConfig::load();
let notebook_path = global.notebook_path().unwrap_or_else(|| {
eprintln!("Notebook not initialized. Run `sma -I` first.");
std::process::exit(1);
});
let config = AppConfig::load();
let title = name.unwrap_or_else(|| config.smarana.default_title.clone());
let filename_slug = generate_filename(&title, &config.smarana.filename_gen, &config.smarana.shell);
let filename = format!("{}.typ", filename_slug.trim());
let file_path = notebook_path.join(&filename);
if !file_path.exists() {
let template_name = template_override.unwrap_or_else(|| config.frontmatter.template.clone());
let template_path = notebook_path.join(".smarana").join("templates").join(&template_name);
let mut matter = match std::fs::read_to_string(&template_path) {
Ok(content) => content,
Err(e) => {
eprintln!("Failed to read template `{}`: {}", template_path.display(), e);
std::process::exit(1);
}
};
matter = matter.replace("{title}", &title);
for (k, v) in &config.frontmatter.variables {
let output = eval_shell_script(v, &config.smarana.shell);
matter = matter.replace(&format!("{{{}}}", k), output.trim());
}
if let Some(content) = body_content {
matter.push_str("\n");
matter.push_str(&content);
matter.push_str("\n");
}
if let Err(e) = std::fs::write(&file_path, matter) {
eprintln!("Failed to create note file: {e}");
std::process::exit(1);
}
println!("Created note: {}", file_path.display());
}
let status = Command::new(&config.smarana.editor)
.arg(&file_path)
.status();
match status {
Ok(s) if !s.success() => {
eprintln!("Editor exited with non-zero status");
}
Err(e) => {
eprintln!("Failed to open editor '{}': {}", config.smarana.editor, e);
}
_ => {}
}
crate::db::sync_all(¬ebook_path);
}
fn generate_filename(name: &str, script: &str, shell: &str) -> String {
let mut child = Command::new(shell)
.arg("-c")
.arg(script)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap_or_else(|e| {
eprintln!("Failed to spawn filename generation script: {e}");
std::process::exit(1);
});
if let Some(mut stdin) = child.stdin.take() {
if let Err(e) = stdin.write_all(name.as_bytes()) {
eprintln!("Failed to pipe name to filename_gen script: {e}");
}
}
let output = child.wait_with_output().unwrap_or_else(|e| {
eprintln!("Failed to wait on filename_gen script: {e}");
std::process::exit(1);
});
if !output.status.success() {
eprintln!("filename_gen script failed with status: {}", output.status);
std::process::exit(1);
}
String::from_utf8_lossy(&output.stdout).to_string()
}
fn eval_shell_script(script: &str, shell: &str) -> String {
let output = Command::new(shell)
.arg("-c")
.arg(script)
.output()
.unwrap_or_else(|e| {
eprintln!("Failed to execute frontmatter script `{}`: {e}", script);
std::process::exit(1);
});
if !output.status.success() {
eprintln!("frontmatter script `{}` failed with status: {}", script, output.status);
}
String::from_utf8_lossy(&output.stdout).to_string()
}