From 3befb7c773ceaed5b28b33ea5a1c25afd2f62adb Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 14 Jan 2022 22:37:40 +0100 Subject: [PATCH] Implement 'today new' --- CHANGELOG.md | 2 +- Cargo.lock | 105 ++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/cli.rs | 18 +++++++ src/cli/error.rs | 3 ++ src/cli/new.rs | 46 ++++++++++++++++++ src/files.rs | 2 +- src/files/grammar.pest | 2 +- 8 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 src/cli/new.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index fffc35e..74be72d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - `LOG` command and `today log` CLI command -- `CAPTURE` command +- `CAPTURE` command and `today new` CLI command - `REMIND` statement - `CANCEL` statement for tasks - One-letter aliases for diff --git a/Cargo.lock b/Cargo.lock index 73c80f8..ceb2ab1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,6 +67,18 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -146,6 +158,16 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs-next" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf36e65a80337bea855cd4ef9b8401ffce06a7baedf2e85ec467b1ac3f6e82b6" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.3.6" @@ -157,6 +179,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "edit" version = "0.1.3" @@ -194,7 +227,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi", ] @@ -229,12 +262,39 @@ version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "maplit" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "nix" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055" +dependencies = [ + "bitflags", + "cc", + "cfg-if 0.1.10", + "libc", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -342,6 +402,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "promptly" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99cfb0289110d969dd21637cfbc922584329bc9e5037c5e576325c615658509" +dependencies = [ + "rustyline", +] + [[package]] name = "quote" version = "1.0.10" @@ -419,6 +488,31 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustyline" +version = "6.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0d5e7b0219a3eadd5439498525d4765c59b7c993ef0c12244865cd2d988413" +dependencies = [ + "cfg-if 0.1.10", + "dirs-next", + "libc", + "log", + "memchr", + "nix", + "scopeguard", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "sha-1" version = "0.8.2" @@ -478,7 +572,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "rand", "redox_syscall", @@ -547,6 +641,7 @@ dependencies = [ "edit", "pest", "pest_derive", + "promptly", "structopt", "termcolor", "thiserror", @@ -592,6 +687,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 2807701..4ee590e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ directories = "4.0.1" edit = "0.1.3" pest = "2.1.3" pest_derive = "2.1.0" +promptly = "0.3.0" structopt = "0.3.25" termcolor = "1.1.2" thiserror = "1.0.30" diff --git a/src/cli.rs b/src/cli.rs index db3c14e..25b944f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -19,6 +19,7 @@ mod done; mod error; mod layout; mod log; +mod new; mod print; mod show; mod util; @@ -47,6 +48,12 @@ pub enum Command { #[structopt(required = true)] identifiers: Vec, }, + /// Create a new entry based on a template + #[structopt(alias = "n")] + New { + #[structopt(subcommand)] + template: Template, + }, /// Marks one or more entries as done #[structopt(alias = "d")] Done { @@ -71,6 +78,14 @@ pub enum Command { Fmt, } +// TODO Add templates for tasks and notes +#[derive(Debug, StructOpt)] +pub enum Template { + /// An undated task marked as done today + #[structopt(alias = "d")] + Done, +} + fn default_file() -> PathBuf { ProjectDirs::from("", "", "today") .expect("could not determine config dir") @@ -136,6 +151,9 @@ fn run_command(opt: &Opt, files: &mut Files, range: DateRange, now: NaiveDateTim let idents = parse_show_idents(identifiers, now.date())?; show::show(files, &entries, &layout, &idents); } + Some(Command::New { template }) => match template { + Template::Done => new::done(files, now)?, + }, Some(Command::Done { entries: ns }) => { let entries = find_entries(files, range)?; let layout = find_layout(files, &entries, range, now); diff --git a/src/cli/error.rs b/src/cli/error.rs index c625dbe..7ab0130 100644 --- a/src/cli/error.rs +++ b/src/cli/error.rs @@ -28,6 +28,8 @@ pub enum Error { NoSuchLog(NaiveDate), #[error("Not a task")] NotATask(Vec), + #[error("No capture file found")] + NoCaptureFile, #[error("Error editing: {0}")] EditingIo(io::Error), } @@ -55,6 +57,7 @@ where eprintln!("{} are not tasks.", ns.join(", ")); } } + Error::NoCaptureFile => eprintln!("No capture file found"), Error::EditingIo(error) => { eprintln!("Error while editing:"); eprintln!(" {error}"); diff --git a/src/cli/new.rs b/src/cli/new.rs new file mode 100644 index 0000000..67a66e6 --- /dev/null +++ b/src/cli/new.rs @@ -0,0 +1,46 @@ +use std::str::FromStr; + +use chrono::NaiveDateTime; +use codespan_reporting::files::SimpleFile; + +use crate::files::cli::CliCommand; +use crate::files::commands::{Done, DoneKind, Task}; +use crate::files::Files; + +use super::error::{Error, Result}; +use super::util; + +pub fn done(files: &mut Files, now: NaiveDateTime) -> Result<()> { + let capture = files.capture().ok_or(Error::NoCaptureFile)?; + + let command = Task { + title: String::new(), + statements: vec![], + done: vec![Done { + kind: DoneKind::Done, + date: None, + done_at: now.date(), + }], + desc: vec![], + }; + + let mut text = format!("{command}"); + let command = loop { + text = util::edit(&text)?; + match CliCommand::from_str(&text) { + Ok(command) => break command.0, + Err(e) => crate::error::eprint_error(&SimpleFile::new("new command", &text), &e), + } + if !matches!( + promptly::prompt_default("Continue editing?", true), + Ok(true) + ) { + println!("Aborting"); + return Ok(()); + } + }; + + files.insert(capture, command); + + Ok(()) +} diff --git a/src/files.rs b/src/files.rs index aba9c48..8522547 100644 --- a/src/files.rs +++ b/src/files.rs @@ -424,7 +424,7 @@ impl Files { file.dirty = true; } - fn insert(&mut self, file: FileSource, command: Command) { + pub fn insert(&mut self, file: FileSource, command: Command) { let file = &mut self.files[file.0]; file.file.commands.push(Spanned::dummy(command)); file.dirty = true; diff --git a/src/files/grammar.pest b/src/files/grammar.pest index 3d80b4c..894a695 100644 --- a/src/files/grammar.pest +++ b/src/files/grammar.pest @@ -156,4 +156,4 @@ cli_ident = { SOI ~ (cli_date | number) ~ EOI } cli_range_start = { cli_datum ~ delta? } cli_range_end = { cli_datum ~ delta? | delta } cli_range = { SOI ~ cli_range_start ~ ("--" ~ cli_range_end)? ~ EOI } -cli_command = { SOI ~ command ~ EOI } +cli_command = ${ SOI ~ empty_line* ~ command ~ empty_line* ~ WHITESPACE* ~ EOI }