use std::collections::HashMap; use std::path::Path; /// Name of the file (inside the workspace) that stores the manual ordering. /// It is committed to git so the order syncs across machines. pub const ORDER_FILE: &str = "order.json"; /// Name of the file that stores per-file chapter title overrides /// (a JSON object mapping `file name` -> `chapter title`). Also committed to git. pub const TITLES_FILE: &str = "titles.json"; /// Read the chapter-title overrides. Missing/invalid -> empty map. pub fn read_titles(workspace: &Path) -> HashMap { let path = workspace.join(TITLES_FILE); match std::fs::read_to_string(&path) { Ok(text) => serde_json::from_str(&text).unwrap_or_default(), Err(_) => HashMap::new(), } } /// Persist the chapter-title overrides as JSON into the workspace. pub fn write_titles(workspace: &Path, titles: &HashMap) -> std::io::Result<()> { let path = workspace.join(TITLES_FILE); let text = serde_json::to_string_pretty(titles).unwrap_or_else(|_| "{}".to_string()); std::fs::write(path, text) } /// Read the saved order (a JSON array of file names). Missing/invalid -> empty. fn read_saved_order(workspace: &Path) -> Vec { let path = workspace.join(ORDER_FILE); match std::fs::read_to_string(&path) { Ok(text) => serde_json::from_str(&text).unwrap_or_default(), Err(_) => Vec::new(), } } /// Persist the given order as JSON into the workspace. pub fn write_order(workspace: &Path, order: &[String]) -> std::io::Result<()> { let path = workspace.join(ORDER_FILE); let text = serde_json::to_string_pretty(order).unwrap_or_else(|_| "[]".to_string()); std::fs::write(path, text) } /// List all `*.md` files currently present in the workspace (file names only). fn list_markdown_files(workspace: &Path) -> Vec { let mut files = Vec::new(); if let Ok(entries) = std::fs::read_dir(workspace) { for entry in entries.flatten() { let path = entry.path(); if path.is_file() { if let Some(ext) = path.extension() { if ext.eq_ignore_ascii_case("md") { if let Some(name) = path.file_name().and_then(|n| n.to_str()) { files.push(name.to_string()); } } } } } } files } /// Produce the effective ordered list of markdown files: /// 1. saved-order entries that still exist on disk, in saved order /// 2. any new `.md` files not yet in the saved order, appended alphabetically pub fn resolve_order(workspace: &Path) -> Vec { let saved = read_saved_order(workspace); let mut present = list_markdown_files(workspace); present.sort_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase())); let mut result: Vec = Vec::new(); for name in &saved { if present.contains(name) && !result.contains(name) { result.push(name.clone()); } } for name in present { if !result.contains(&name) { result.push(name); } } result }