diff --git a/project_templates/.nvim.lua b/project_templates/.nvim.lua index f243fc1..77e0fb9 100644 --- a/project_templates/.nvim.lua +++ b/project_templates/.nvim.lua @@ -117,7 +117,10 @@ vim.api.nvim_create_user_command("Args", function(a) updateArgs(a.fargs) end, { nargs = '*', desc = "Update run/debug arguments" }) if dap_ok then - local lldb_init = {} + local lldb_init = { + "command script import ~/.rustup/toolchains/nightly-2025-02-19-aarch64-apple-darwin/lib/rustlib/etc/lldb_lookup.py", + "command source ~/.rustup/toolchains/nightly-2025-02-19-aarch64-apple-darwin/lib/rustlib/etc/lldb_commands", + } dap_configs = { { name = 'test all', diff --git a/src/git_tracker.rs b/src/git_tracker.rs deleted file mode 100644 index 07fb615..0000000 --- a/src/git_tracker.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::fs; -use std::path::Path; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct GitVersion { - pub branch: String, - pub commit: String, -} - -impl GitVersion { - pub fn key(&self) -> String { - format!("{}/{}", self.branch, self.commit) - } -} - -pub fn get_git_version(git_dir: &str) -> Result { - let git_path = Path::new(git_dir); - let head_path = git_path.join(".git/HEAD"); - - // Read HEAD file - let head_content = fs::read_to_string(&head_path) - .map_err(|e| format!("Failed to read .git/HEAD: {}", e))?; - - let head_content = head_content.trim(); - - // Check if HEAD points to a ref - if head_content.starts_with("ref:") { - let ref_path = head_content.strip_prefix("ref:").unwrap().trim(); - let full_ref_path = git_path.join(".git").join(ref_path); - - // Read the ref file to get the commit hash - let commit_hash = fs::read_to_string(&full_ref_path) - .map_err(|e| format!("Failed to read ref file: {}", e))? - .trim() - .to_string(); - - // Extract branch name from ref path - let branch = ref_path - .strip_prefix("refs/heads/") - .unwrap_or(ref_path) - .to_string(); - - Ok(GitVersion { - branch, - commit: commit_hash, - }) - } else { - // Detached HEAD state - just use the commit hash - Ok(GitVersion { - branch: "detached".to_string(), - commit: head_content.to_string(), - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_git_version() { - // This test will only work if run in a git repository - if let Ok(version) = get_git_version(".") { - assert!(!version.commit.is_empty()); - assert!(!version.branch.is_empty()); - } - } -} diff --git a/src/main.rs b/src/main.rs index 06f11b9..a462e1a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -mod git_tracker; mod post_manager; mod template_engine; @@ -27,18 +26,6 @@ async fn main() { post_manager: post_manager.clone(), }; - // Spawn background task to watch for git changes - tokio::spawn(async move { - let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(5)); - loop { - interval.tick().await; - let mut manager = post_manager.write().await; - if let Err(e) = manager.refresh_if_needed() { - eprintln!("Error refreshing posts: {}", e); - } - } - }); - let app = Router::new() .route("/", get(index_handler)) .route("/:page", get(all_handler)) diff --git a/src/post_manager.rs b/src/post_manager.rs index dd57963..19dea81 100644 --- a/src/post_manager.rs +++ b/src/post_manager.rs @@ -1,4 +1,3 @@ -use crate::git_tracker::{get_git_version, GitVersion}; use chrono::{DateTime, Utc}; use pulldown_cmark::{html, Options, Parser}; use std::collections::HashMap; @@ -17,63 +16,43 @@ pub struct Post { pub created_at: DateTime, } +struct Entry { + #[allow(dead_code)] + short_name: String, + file_path: String, + timestamp: DateTime, + status: i32, +} + pub struct PostManager { - git_dir: PathBuf, - posts_dir: PathBuf, + root_dir: PathBuf, + posts_dir_rel: String, posts: HashMap, - last_git_version: Option, } impl PostManager { pub fn new(root_dir: &str) -> Result { - let git_dir = PathBuf::from(root_dir); - let posts_dir = git_dir.join("posts"); - - // Create posts directory if it doesn't exist - if !posts_dir.exists() { - fs::create_dir_all(&posts_dir) - .map_err(|e| format!("Failed to create posts directory: {}", e))?; - } + let root_dir = PathBuf::from(root_dir); + let posts_dir_rel = "posts"; let mut manager = PostManager { - git_dir, - posts_dir, + root_dir, + posts_dir_rel: posts_dir_rel.to_string(), posts: HashMap::new(), - last_git_version: None, }; manager.refresh_posts()?; Ok(manager) } - pub fn refresh_if_needed(&mut self) -> Result { - let current_version = get_git_version(self.git_dir.to_str().unwrap())?; - - if self.last_git_version.as_ref() != Some(¤t_version) { - println!( - "Git version changed: {} -> {}", - self.last_git_version - .as_ref() - .map(|v| v.key()) - .unwrap_or_else(|| "none".to_string()), - current_version.key() - ); - self.refresh_posts()?; - self.last_git_version = Some(current_version); - Ok(true) - } else { - Ok(false) - } - } - - fn get_post_timestamps(&self) -> Result>, String> { + fn query_posts(&self) -> Result, String> { let output = Command::new("git") .arg("whatchanged") - .arg("--pretty=%h - %cd - %s") + .arg("--pretty=%h - %ad - %s") .arg("--date=unix") .arg("--") - .arg("posts") - .current_dir(&self.git_dir) + .arg(self.posts_dir_rel.clone()) + .current_dir(&self.root_dir) .output() .map_err(|e| format!("Failed to execute git whatchanged: {}", e))?; @@ -85,8 +64,7 @@ impl PostManager { } let log_output = String::from_utf8_lossy(&output.stdout); - let mut timestamps: HashMap> = HashMap::new(); - + let mut result: HashMap = HashMap::new(); let mut current_timestamp: Option> = None; for line in log_output.lines() { @@ -105,90 +83,64 @@ impl PostManager { let timestamp_str = after_first_dash[..second_dash_pos].trim(); if let Ok(timestamp) = timestamp_str.parse::() { current_timestamp = DateTime::from_timestamp(timestamp, 0); + eprintln!("Timestamp: {:?} ({})", current_timestamp, timestamp); } } } + continue; } + // Parse file change line: ":000000 100644 0000000 6bdad65 A posts/hello-world-2.md" - else if line.starts_with(':') { + if line.starts_with(':') { + eprintln!("Parsing line: {}", line); if let Some(timestamp) = current_timestamp { let parts: Vec<&str> = line.split_whitespace().collect(); if parts.len() >= 6 { let status = parts[4]; // A (add), D (delete), M (modify) let file_path = parts[5]; - // Only process existing files (not deleted ones) - if status != "D" && file_path.starts_with("posts/") { - if let Some(file_name) = file_path.strip_prefix("posts/") { - if let Some(name) = file_name.strip_suffix(".md") { - // Only update if we don't have a timestamp yet (latest commit wins) - timestamps.entry(name.to_string()).or_insert(timestamp); - } + if let Some(file_name) = file_path.strip_prefix("posts/") { + if let Some(name) = file_name.strip_suffix(".md") { + // Only update if we don't have a timestamp yet (latest commit wins) + result.entry(name.to_string()).or_insert(Entry { + short_name: name.to_string(), + file_path: file_path.to_string(), + timestamp, + status: if status == "D" { -1 } else { 1 }, + }); } } } + } else { + eprintln!("Invalid git log output, expected prior timestamp: {}", line); } } } - Ok(timestamps) + Ok(result) } fn refresh_posts(&mut self) -> Result<(), String> { self.posts.clear(); // Get timestamps from git history - let git_timestamps = self.get_post_timestamps()?; - - let entries = fs::read_dir(&self.posts_dir) - .map_err(|e| format!("Failed to read posts directory: {}", e))?; - - for entry in entries { - let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?; - let path = entry.path(); - - if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("md") { - let filename = path - .file_name() - .and_then(|s| s.to_str()) - .ok_or_else(|| "Invalid filename".to_string())? - .to_string(); - - let name = path - .file_stem() - .and_then(|s| s.to_str()) - .ok_or_else(|| "Invalid file stem".to_string())? - .to_string(); - - let markdown_content = fs::read_to_string(&path) - .map_err(|e| format!("Failed to read post file: {}", e))?; - - let html_content = markdown_to_html(&markdown_content); - - // Use git timestamp if available, otherwise fall back to file metadata - let created_at = git_timestamps - .get(&name) - .copied() - .or_else(|| { - let metadata = fs::metadata(&path).ok()?; - metadata - .created() - .or_else(|_| metadata.modified()) - .ok() - .map(|t| DateTime::::from(t)) - }) - .unwrap_or_else(|| Utc::now()); - - let post = Post { - name: name.clone(), - filename, - markdown_content, - html_content, - created_at, - }; - - self.posts.insert(name, post); + let query_result = self.query_posts()?; + for (name, entry) in query_result { + if entry.status != 1 { + continue; } + let markdown_content = fs::read_to_string(&entry.file_path) + .map_err(|e| format!("Failed to read post file: {}", e))?; + let html_content = markdown_to_html(&markdown_content); + let post = Post { + name: name.clone(), + filename: entry.file_path, + markdown_content, + html_content, + created_at: entry.timestamp, + }; + eprintln!("Loaded post: {} ({})", name, entry.timestamp); + self.posts.insert(name, post); } println!("Loaded {} posts", self.posts.len());