diff --git a/Cargo.lock b/Cargo.lock index dbf672b..39bf144 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,18 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "async-attributes" version = "1.1.2" @@ -218,6 +230,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + [[package]] name = "better-panic" version = "0.2.0" @@ -234,6 +252,17 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + [[package]] name = "blocking" version = "1.0.2" @@ -357,6 +386,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "crossbeam-utils" version = "0.8.3" @@ -464,6 +499,16 @@ dependencies = [ "syn", ] +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if 0.1.10", + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -474,6 +519,17 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +dependencies = [ + "libc", + "redox_users 0.3.5", + "winapi", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -481,7 +537,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", - "redox_users", + "redox_users 0.4.0", "winapi", ] @@ -1074,6 +1130,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom 0.1.16", + "redox_syscall 0.1.57", + "rust-argon2", +] + [[package]] name = "redox_users" version = "0.4.0" @@ -1101,6 +1168,18 @@ version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +[[package]] +name = "rust-argon2" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + [[package]] name = "rustc-demangle" version = "0.1.18" @@ -1301,6 +1380,7 @@ dependencies = [ "chrono", "clap", "crossterm", + "dirs", "futures", "futures-timer", "itertools", @@ -1316,6 +1396,7 @@ dependencies = [ "unicode-segmentation", "unicode-width", "uuid", + "xdg", ] [[package]] @@ -1538,3 +1619,9 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xdg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" diff --git a/Cargo.toml b/Cargo.toml index 5ad5eb3..af91077 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,8 @@ anyhow = "1" async-std = { version = "1", features = ["attributes", "unstable"] } futures = "0.3" futures-timer = "3.0" +dirs = "2.0.2" +xdg = "2" [package.metadata.rpm] package = "taskwarrior-tui" diff --git a/src/app.rs b/src/app.rs index 0f146cd..499bee3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -14,6 +14,11 @@ use std::collections::{HashMap, HashSet}; use std::convert::TryInto; use std::fs; use std::path::Path; + +use std::io::Read; +use std::io::Write; +use xdg::BaseDirectories; + use std::process::Command; use std::time::SystemTime; @@ -49,14 +54,14 @@ use tui::{ widgets::{Block, BorderType, Borders, Clear, Paragraph}, }; -use rustyline::error::ReadlineError; use rustyline::history::Direction as HistoryDirection; -use rustyline::history::History; use rustyline::line_buffer::LineBuffer; use rustyline::At; use rustyline::Editor; use rustyline::Word; +use crate::history::HistoryContext; + use std::io; use tui::{backend::CrosstermBackend, Terminal}; @@ -150,63 +155,6 @@ pub enum AppMode { Calendar, } -pub struct HistoryContext { - history: History, - history_index: usize, -} - -impl HistoryContext { - pub fn new() -> Self { - let history = History::new(); - Self { - history, - history_index: 0, - } - } - - pub fn history(&self) -> &History { - &self.history - } - - pub fn history_index(&self) -> usize { - self.history_index - } - - pub fn history_search(&mut self, buf: &str, dir: HistoryDirection) -> Option { - if self.history.is_empty() { - return None; - } - if self.history_index == self.history.len().saturating_sub(1) && dir == HistoryDirection::Forward - || self.history_index == 0 && dir == HistoryDirection::Reverse - { - return Some(self.history.get(self.history_index).unwrap().clone()); - } - let history_index = match dir { - HistoryDirection::Reverse => self.history_index - 1, - HistoryDirection::Forward => self.history_index + 1, - }; - if let Some(history_index) = self.history.starts_with(buf, history_index, dir) { - self.history_index = history_index; - Some(self.history.get(history_index).unwrap().clone()) - } else if buf.is_empty() { - self.history_index = history_index; - Some(self.history.get(history_index).unwrap().clone()) - } else { - None - } - } - - pub fn add(&mut self, buf: &str) { - if self.history.add(buf) { - self.history_index = self.history.len() - 1; - } - } - - pub fn last(&mut self) { - self.history_index = self.history.len().saturating_sub(1); - } -} - pub struct TaskwarriorTuiApp { pub should_quit: bool, pub dirty: bool, @@ -282,7 +230,9 @@ impl TaskwarriorTuiApp { } app.get_context()?; app.update(true)?; + app.filter_history_context.load("filter.history")?; app.filter_history_context.add(app.filter.as_str()); + app.command_history_context.load("command.history")?; Ok(app) } @@ -931,6 +881,7 @@ impl TaskwarriorTuiApp { self.update_tags(); self.task_details.clear(); self.dirty = false; + self.save_history()?; } self.cursor_fix(); self.update_task_table_state(); @@ -940,6 +891,12 @@ impl TaskwarriorTuiApp { Ok(()) } + pub fn save_history(&mut self) -> Result<()> { + self.filter_history_context.write("filter.history")?; + self.command_history_context.write("command.history")?; + Ok(()) + } + pub fn cursor_fix(&mut self) { while !self.tasks.is_empty() && self.current_selection >= self.tasks.len() { self.task_report_previous(); @@ -2351,8 +2308,6 @@ mod tests { } fn setup() { - use std::io::Read; - use std::io::Write; use std::process::Stdio; let mut f = File::open(Path::new(env!("TASKDATA")).parent().unwrap().join("export.json")).unwrap(); let mut s = String::new(); diff --git a/src/history.rs b/src/history.rs new file mode 100644 index 0000000..d8f37be --- /dev/null +++ b/src/history.rs @@ -0,0 +1,87 @@ +use anyhow::Result; +use rustyline::error::ReadlineError; +use rustyline::history::Direction; +use rustyline::history::History; +use std::fs::File; +use xdg::BaseDirectories; + +pub struct HistoryContext { + history: History, + history_index: usize, +} + +impl HistoryContext { + pub fn new() -> Self { + let history = History::new(); + Self { + history, + history_index: 0, + } + } + + pub fn load(&mut self, filename: &str) -> Result<()> { + let d = BaseDirectories::with_prefix("taskwarrior-tui")?; + if let Some(path) = d.find_config_file(filename) { + self.history.load(&path)?; + Ok(()) + } else { + let path = d.place_config_file(filename)?; + self.history.save(&path)?; + Ok(()) + } + } + + pub fn write(&mut self, filename: &str) -> Result<()> { + let d = BaseDirectories::with_prefix("taskwarrior-tui")?; + if let Some(path) = d.find_config_file(filename) { + self.history.save(&path)?; + Ok(()) + } else { + let path = d.place_config_file(filename)?; + self.history.save(&path)?; + Ok(()) + } + } + + pub fn history(&self) -> &History { + &self.history + } + + pub fn history_index(&self) -> usize { + self.history_index + } + + pub fn history_search(&mut self, buf: &str, dir: Direction) -> Option { + if self.history.is_empty() { + return None; + } + if self.history_index == self.history.len().saturating_sub(1) && dir == Direction::Forward + || self.history_index == 0 && dir == Direction::Reverse + { + return Some(self.history.get(self.history_index).unwrap().clone()); + } + let history_index = match dir { + Direction::Reverse => self.history_index - 1, + Direction::Forward => self.history_index + 1, + }; + if let Some(history_index) = self.history.starts_with(buf, history_index, dir) { + self.history_index = history_index; + Some(self.history.get(history_index).unwrap().clone()) + } else if buf.is_empty() { + self.history_index = history_index; + Some(self.history.get(history_index).unwrap().clone()) + } else { + None + } + } + + pub fn add(&mut self, buf: &str) { + if self.history.add(buf) { + self.history_index = self.history.len() - 1; + } + } + + pub fn last(&mut self) { + self.history_index = self.history.len().saturating_sub(1); + } +} diff --git a/src/main.rs b/src/main.rs index d089e01..c540f28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod calendar; mod config; mod context; mod help; +mod history; mod keyconfig; mod table; mod task_report;