Specify default capture file

This commit is contained in:
Joscha 2022-01-14 17:53:07 +01:00
parent 039b7b73ee
commit 0b4f614af6
7 changed files with 70 additions and 6 deletions

View file

@ -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

View file

@ -85,6 +85,7 @@ pub struct Files {
/// Codespan-reporting file database.
cs_files: SimpleFiles<String, String>,
timezone: Option<Tz>,
capture: Option<usize>,
logs: HashMap<NaiveDate, Source>,
}
@ -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<Source> = 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<FileSource> {
self.capture.map(FileSource)
}
pub fn now(&self) -> DateTime<&Tz> {
if let Some(tz) = &self.timezone {
Utc::now().with_timezone(&tz)

View file

@ -271,6 +271,7 @@ pub enum Statement {
Remind(Option<Spanned<Delta>>),
}
#[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<String>),
Timezone(Spanned<String>),
Capture, // TODO Set capture file by template?
Task(Task),
Note(Note),
Log(Log),

View file

@ -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,

View file

@ -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,
});
}

View file

@ -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 }

View file

@ -826,6 +826,7 @@ fn parse_command(p: Pair<'_, Rule>) -> Result<Spanned<Command>> {
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)?),