From 0b4f614af6305f883354c08eb50dcaf1f1b1998b Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 14 Jan 2022 17:53:07 +0100 Subject: [PATCH] Specify default capture file --- CHANGELOG.md | 2 +- src/files.rs | 33 +++++++++++++++++++++++++++++++++ src/files/commands.rs | 2 ++ src/files/error.rs | 24 ++++++++++++++++++++++++ src/files/format.rs | 11 +++++++---- src/files/grammar.pest | 3 ++- src/files/parse.rs | 1 + 7 files changed, 70 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2d0971..1de5b85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## Unreleased ### Added -- `LOG` command +- `LOG` and `CAPTURE` commands - `REMIND` and `CANCEL` statements - `MOVE` entries to a different time - `today log` CLI command diff --git a/src/files.rs b/src/files.rs index 0edc0ca..8d66b2c 100644 --- a/src/files.rs +++ b/src/files.rs @@ -85,6 +85,7 @@ pub struct Files { /// Codespan-reporting file database. cs_files: SimpleFiles, timezone: Option, + capture: Option, logs: HashMap, } @@ -132,6 +133,7 @@ impl Files { files: vec![], cs_files: SimpleFiles::new(), timezone: None, + capture: None, logs: HashMap::new(), } } @@ -155,6 +157,7 @@ impl Files { self.load_file(&mut loaded, path)?; self.determine_timezone()?; + self.determine_capture()?; self.collect_logs()?; Ok(()) @@ -257,6 +260,32 @@ impl Files { Ok(()) } + fn determine_capture(&mut self) -> Result<()> { + assert_eq!(self.capture, None); + + let mut found: Option = None; + + for command in self.commands() { + if let Command::Capture = &command.value.value { + if let Some(found) = &found { + let found_cmd = self.command(*found); + return Err(Error::MultipleCapture { + file1: found.file(), + span1: found_cmd.value.span, + file2: command.source.file(), + span2: command.value.span, + }); + } else { + found = Some(command.source); + } + } + } + + self.capture = found.map(|s| s.file); + + Ok(()) + } + fn collect_logs(&mut self) -> Result<()> { for command in Self::commands_of_files(&self.files) { if let Command::Log(log) = &command.value.value { @@ -369,6 +398,10 @@ impl Files { .max_by_key(|(d, _)| *d) } + pub fn capture(&self) -> Option { + self.capture.map(FileSource) + } + pub fn now(&self) -> DateTime<&Tz> { if let Some(tz) = &self.timezone { Utc::now().with_timezone(&tz) diff --git a/src/files/commands.rs b/src/files/commands.rs index 1b0ee1a..a53aa50 100644 --- a/src/files/commands.rs +++ b/src/files/commands.rs @@ -271,6 +271,7 @@ pub enum Statement { Remind(Option>), } +#[allow(clippy::enum_variant_names)] #[derive(Debug, Clone, Copy)] pub enum DoneDate { Date { @@ -374,6 +375,7 @@ pub struct Log { pub enum Command { Include(Spanned), Timezone(Spanned), + Capture, // TODO Set capture file by template? Task(Task), Note(Note), Log(Log), diff --git a/src/files/error.rs b/src/files/error.rs index 3133221..983160d 100644 --- a/src/files/error.rs +++ b/src/files/error.rs @@ -114,6 +114,13 @@ pub enum Error { span2: Span, tz2: String, }, + #[error("Multiple capture commands")] + MultipleCapture { + file1: FileSource, + span1: Span, + file2: FileSource, + span2: Span, + }, #[error("Duplicate logs for {date}")] LogConflict { file1: FileSource, @@ -179,6 +186,23 @@ impl<'a> Eprint<'a, Files> for Error { ]); Self::eprint_diagnostic(files, config, &diagnostic); } + Error::MultipleCapture { + file1, + span1, + file2, + span2, + } => { + let diagnostic = Diagnostic::error() + .with_message("Multiple capture commands") + .with_labels(vec![ + Label::primary(*file1, span1), + Label::primary(*file2, span2), + ]) + .with_notes(vec![ + "There must be at most one CAPTURE command.".to_string() + ]); + Self::eprint_diagnostic(files, config, &diagnostic); + } Error::LogConflict { file1, span1, diff --git a/src/files/format.rs b/src/files/format.rs index 6fb79b2..f9ad86a 100644 --- a/src/files/format.rs +++ b/src/files/format.rs @@ -302,6 +302,7 @@ impl fmt::Display for Command { match self { Command::Include(name) => writeln!(f, "INCLUDE {}", name), Command::Timezone(name) => writeln!(f, "TIMEZONE {}", name), + Command::Capture => writeln!(f, "CAPTURE"), Command::Task(task) => write!(f, "{}", task), Command::Note(note) => write!(f, "{}", note), Command::Log(log) => write!(f, "{}", log), @@ -322,8 +323,9 @@ impl File { // Order of commands in a file: // 1. Imports, sorted alphabetically // 2. Time zone(s) - // 3. Log entries, sorted by date (ascending) - // 4. Tasks and notes, in original order + // 3. Captures + // 4. Log entries, sorted by date (ascending) + // 5. Tasks and notes, in original order // There should always be at most one time zone, so we don't care about // their order. @@ -347,8 +349,9 @@ impl File { commands.sort_by_key(|c| match c { Command::Include(_) => 0, Command::Timezone(_) => 1, - Command::Log(_) => 2, - Command::Task(_) | Command::Note(_) => 3, + Command::Capture => 2, + Command::Log(_) => 3, + Command::Task(_) | Command::Note(_) => 4, }); } diff --git a/src/files/grammar.pest b/src/files/grammar.pest index cb7d4e6..b83741e 100644 --- a/src/files/grammar.pest +++ b/src/files/grammar.pest @@ -5,6 +5,7 @@ rest_any = { (!eol ~ ANY)* } include = { "INCLUDE" ~ WHITESPACE ~ rest_some ~ eol } timezone = { "TIMEZONE" ~ WHITESPACE ~ rest_some ~ eol } +capture = { "CAPTURE" ~ eol } number = @{ ASCII_DIGIT{1,9} } // Fits into an i32 @@ -144,7 +145,7 @@ log_head = !{ "LOG" ~ datum ~ eol } log = { log_head ~ description } empty_line = _{ WHITESPACE* ~ NEWLINE } -command = { include | timezone | task | note | log } +command = { include | timezone | capture | task | note | log } file = ${ SOI ~ (empty_line* ~ command)* ~ empty_line* ~ WHITESPACE* ~ EOI } diff --git a/src/files/parse.rs b/src/files/parse.rs index 629ffea..65200d4 100644 --- a/src/files/parse.rs +++ b/src/files/parse.rs @@ -826,6 +826,7 @@ fn parse_command(p: Pair<'_, Rule>) -> Result> { let command = match p.as_rule() { Rule::include => Command::Include(parse_include(p)), Rule::timezone => Command::Timezone(parse_timezone(p)), + Rule::capture => Command::Capture, Rule::task => Command::Task(parse_task(p)?), Rule::note => Command::Note(parse_note(p)?), Rule::log => Command::Log(parse_log(p)?),