From 80bd48f44c1ba6c5010f7d50fd9387b1c4424464 Mon Sep 17 00:00:00 2001 From: Lars Wirzenius Date: Thu, 15 Jul 2021 17:34:08 +0300 Subject: feat: add command to list current drafts Sponsored-by: author --- src/bin/jt2.rs | 1 + src/cmd.rs | 11 +++++++++++ src/error.rs | 8 ++++++++ src/journal.rs | 30 ++++++++++++++++++++++++++++++ src/opt.rs | 3 +++ 5 files changed, 53 insertions(+) (limited to 'src') diff --git a/src/bin/jt2.rs b/src/bin/jt2.rs index c37b799..1574f2e 100644 --- a/src/bin/jt2.rs +++ b/src/bin/jt2.rs @@ -20,6 +20,7 @@ fn do_work() -> anyhow::Result<()> { SubCommand::IsJournal(x) => x.run(&config)?, SubCommand::New(x) => x.run(&config)?, SubCommand::NewTopic(x) => x.run(&config)?, + SubCommand::List(x) => x.run(&config)?, SubCommand::Edit(x) => x.run(&config)?, SubCommand::Finish(x) => x.run(&config)?, } diff --git a/src/cmd.rs b/src/cmd.rs index da917ee..2f2f626 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -61,6 +61,17 @@ impl New { } } +#[derive(Debug, StructOpt)] +pub struct List {} + +impl List { + pub fn run(&self, config: &Configuration) -> Result<(), JournalError> { + let journal = Journal::new(&config.dirname, &config.entries)?; + journal.list_drafts()?; + Ok(()) + } +} + #[derive(Debug, StructOpt)] pub struct NewTopic { #[structopt(help = "Path to topic page in journal")] diff --git a/src/error.rs b/src/error.rs index 8db0991..36d8f07 100644 --- a/src/error.rs +++ b/src/error.rs @@ -97,4 +97,12 @@ pub enum JournalError { /// Failed to make a path relative to a directory. #[error("failed to make {0} relative to {1}: {2}")] RelativePath(PathBuf, PathBuf, std::path::StripPrefixError), + + /// Problem with glob pattern. + #[error("Error in glob pattern {0}: {1}")] + PatternError(String, #[source] glob::PatternError), + + /// Problem when matching glob pattern on actual files. + #[error("Failed to match glob pattern {0}: {1}")] + GlobError(String, #[source] glob::GlobError), } diff --git a/src/journal.rs b/src/journal.rs index 8042f83..ad8b4af 100644 --- a/src/journal.rs +++ b/src/journal.rs @@ -2,6 +2,8 @@ use crate::error::JournalError; use crate::git; use crate::template::Templates; use chrono::{DateTime, Local}; +use glob::glob; +use regex::Regex; use std::path::{Path, PathBuf}; use std::process::Command; use tera::Context; @@ -121,6 +123,21 @@ impl Journal { } } + pub fn list_drafts(&self) -> Result<(), JournalError> { + let prefix = format!("{}/", self.drafts().display()); + let pattern = format!("{}*.md", prefix); + let entries = + glob(&pattern).map_err(|err| JournalError::PatternError(pattern.to_string(), err))?; + for entry in entries { + let entry = entry.map_err(|err| JournalError::GlobError(pattern.to_string(), err))?; + let title = get_title(&entry)?; + let entry = entry.file_stem().unwrap().to_string_lossy(); + let entry = entry.strip_prefix(&prefix).unwrap_or(&entry); + println!("{} {}", entry, title); + } + Ok(()) + } + fn edit(&self, editor: &str, filename: &Path) -> Result<(), JournalError> { if editor == "none" { return Ok(()); @@ -209,3 +226,16 @@ fn current_timestamp() -> String { let now: DateTime = Local::now(); now.to_rfc2822() } + +fn get_title(filename: &Path) -> Result { + let text = std::fs::read(filename) + .map_err(|err| JournalError::ReadDraft(filename.to_path_buf(), err))?; + let text = String::from_utf8_lossy(&text); + let pat = Regex::new(r#"^\[\[!meta title="(?P.*)"\]\]"#).unwrap(); + if let Some(caps) = pat.captures(&text) { + if let Some(m) = caps.name("title") { + return Ok(m.as_str().to_string()); + } + } + Ok("(untitled)".to_string()) +} diff --git a/src/opt.rs b/src/opt.rs index 7d3dcda..7530f54 100644 --- a/src/opt.rs +++ b/src/opt.rs @@ -58,6 +58,9 @@ pub enum SubCommand { /// Create draft for a new journal entry. New(cmd::New), + /// List current drafts. + List(cmd::List), + /// Create topic page. NewTopic(cmd::NewTopic), -- cgit v1.2.1