feat: Add logging and fix history

This commit is contained in:
Dheepak Krishnamurthy 2021-11-27 11:29:01 -07:00
parent 5c7f7fe9fd
commit 7effb72f41
6 changed files with 242 additions and 15 deletions

1
.envrc
View file

@ -1,3 +1,4 @@
export TASKRC=`pwd`/tests/data/.taskrc export TASKRC=`pwd`/tests/data/.taskrc
export TASKDATA=`pwd`/tests/data/.task export TASKDATA=`pwd`/tests/data/.task
export XDG_STATE_HOME=`pwd`/tests/data/.config export XDG_STATE_HOME=`pwd`/tests/data/.config
export TASKWARRIOR_TUI_LOG_LEVEL=debug

176
Cargo.lock generated
View file

@ -32,6 +32,12 @@ version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
[[package]]
name = "arc-swap"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dabe5a181f83789739c194cbe5a897dde195078fac08568d09221fd6137a7ba8"
[[package]] [[package]]
name = "async-attributes" name = "async-attributes"
version = "1.1.2" version = "1.1.2"
@ -476,6 +482,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "derive_builder" name = "derive_builder"
version = "0.9.0" version = "0.9.0"
@ -542,6 +559,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "dtoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
[[package]] [[package]]
name = "either" name = "either"
version = "1.6.1" version = "1.6.1"
@ -792,6 +815,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" version = "1.0.1"
@ -862,6 +891,12 @@ version = "0.2.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.5" version = "0.4.5"
@ -878,9 +913,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"serde",
"value-bag", "value-bag",
] ]
[[package]]
name = "log-mdc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
[[package]]
name = "log4rs"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1572a880d1115ff867396eee7ae2bc924554225e67a0d3c85c745b3e60ca211"
dependencies = [
"anyhow",
"arc-swap",
"chrono",
"derivative",
"fnv",
"humantime",
"libc",
"log",
"log-mdc",
"parking_lot",
"regex",
"serde",
"serde-value",
"serde_json",
"serde_yaml",
"thiserror",
"thread-id",
"typemap",
"winapi",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.4.1" version = "2.4.1"
@ -1010,6 +1079,15 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "ordered-float"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97c9d06878b3a851e8026ef94bf7fef9ba93062cd412601da4d9cf369b1cc62d"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "4.2.0" version = "4.2.0"
@ -1045,7 +1123,7 @@ dependencies = [
"cfg-if", "cfg-if",
"instant", "instant",
"libc", "libc",
"redox_syscall", "redox_syscall 0.2.10",
"smallvec", "smallvec",
"winapi", "winapi",
] ]
@ -1185,6 +1263,12 @@ dependencies = [
"rand_core", "rand_core",
] ]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.10" version = "0.2.10"
@ -1201,7 +1285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"redox_syscall", "redox_syscall 0.2.10",
] ]
[[package]] [[package]]
@ -1272,6 +1356,16 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde-value"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
dependencies = [
"ordered-float",
"serde",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.130" version = "1.0.130"
@ -1294,6 +1388,18 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_yaml"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8c608a35705a5d3cdc9fbe403147647ff34b921f8e833e49306df898f9b20af"
dependencies = [
"dtoa",
"indexmap",
"serde",
"yaml-rust",
]
[[package]] [[package]]
name = "shellexpand" name = "shellexpand"
version = "2.1.0" version = "2.1.0"
@ -1434,6 +1540,8 @@ dependencies = [
"futures-timer", "futures-timer",
"itertools", "itertools",
"lazy_static", "lazy_static",
"log",
"log4rs",
"rand", "rand",
"regex", "regex",
"rustyline", "rustyline",
@ -1477,6 +1585,37 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread-id"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1"
dependencies = [
"libc",
"redox_syscall 0.1.57",
"winapi",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.44" version = "0.1.44"
@ -1488,6 +1627,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "traitobject"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
[[package]] [[package]]
name = "tui" name = "tui"
version = "0.16.0" version = "0.16.0"
@ -1501,6 +1646,15 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "typemap"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6"
dependencies = [
"unsafe-any",
]
[[package]] [[package]]
name = "unicase" name = "unicase"
version = "2.6.0" version = "2.6.0"
@ -1537,6 +1691,15 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unsafe-any"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f"
dependencies = [
"traitobject",
]
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.0" version = "0.2.0"
@ -1706,3 +1869,12 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View file

@ -30,6 +30,8 @@ futures = "0.3.16"
futures-timer = "3.0.2" futures-timer = "3.0.2"
itertools = "0.10.1" itertools = "0.10.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4.14"
log4rs = "1.0.0"
rand = "0.8.4" rand = "0.8.4"
regex = "1.5.4" regex = "1.5.4"
rustyline = "8.2" rustyline = "8.2"

View file

@ -80,6 +80,8 @@ use task_hookrs::project::Project;
use versions::Versioning; use versions::Versioning;
use log::{debug, error, info, log_enabled, trace, warn, Level, LevelFilter};
const MAX_LINE: usize = 4096; const MAX_LINE: usize = 4096;
lazy_static! { lazy_static! {
@ -1283,6 +1285,7 @@ impl TaskwarriorTui {
} }
pub fn update(&mut self, force: bool) -> Result<()> { pub fn update(&mut self, force: bool) -> Result<()> {
trace!("self.update({:?});", force);
if force || self.dirty || self.tasks_changed_since(self.last_export).unwrap_or(true) { if force || self.dirty || self.tasks_changed_since(self.last_export).unwrap_or(true) {
let task_uuids = self.selected_task_uuids(); let task_uuids = self.selected_task_uuids();
if self.current_selection_uuid.is_none() && self.current_selection_id.is_none() && task_uuids.len() == 1 { if self.current_selection_uuid.is_none() && self.current_selection_id.is_none() && task_uuids.len() == 1 {
@ -1410,6 +1413,7 @@ impl TaskwarriorTui {
} }
pub fn update_task_table_state(&mut self) { pub fn update_task_table_state(&mut self) {
trace!("self.update_task_table_state()");
self.task_table_state.select(Some(self.current_selection)); self.task_table_state.select(Some(self.current_selection));
for uuid in self.marked.clone() { for uuid in self.marked.clone() {

View file

@ -15,13 +15,6 @@ impl HistoryContext {
pub fn new(filename: &str) -> Self { pub fn new(filename: &str) -> Self {
let history = History::new(); let history = History::new();
#[cfg(target_family = "unix")]
let config_dir_op = std::env::var_os("XDG_STATE_HOME")
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| dirs::home_dir().map(|d| d.join(".config")));
#[cfg(not(target_family = "unix"))]
let config_dir_op = dirs::config_dir(); let config_dir_op = dirs::config_dir();
let config_path = config_dir_op.map(|d| d.join("taskwarrior-tui")).unwrap(); let config_path = config_dir_op.map(|d| d.join("taskwarrior-tui")).unwrap();
@ -44,6 +37,7 @@ impl HistoryContext {
self.history.save(&self.config_path)?; self.history.save(&self.config_path)?;
} }
self.history_index = self.history.len(); self.history_index = self.history.len();
log::debug!("Loading history of length {}", self.history.len());
Ok(()) Ok(())
} }
@ -61,25 +55,40 @@ impl HistoryContext {
} }
pub fn history_search(&mut self, buf: &str, dir: Direction) -> Option<String> { pub fn history_search(&mut self, buf: &str, dir: Direction) -> Option<String> {
log::debug!(
"Searching history for {:?} in direction {:?} with history index = {:?}",
buf,
dir,
self.history_index()
);
if self.history.is_empty() { if self.history.is_empty() {
log::debug!("History is empty");
return None; return None;
} }
if self.history_index == self.history.len().saturating_sub(1) && dir == Direction::Forward if self.history_index == self.history.len().saturating_sub(1) && dir == Direction::Forward
|| self.history_index == 0 && dir == Direction::Reverse || self.history_index == 0 && dir == Direction::Reverse
{ {
log::debug!("No more history left to search");
return None; return None;
} }
let history_index = match dir { let history_index = match dir {
Direction::Reverse => self.history_index, Direction::Reverse => self.history_index.saturating_sub(1),
Direction::Forward => self.history_index, Direction::Forward => self
.history_index
.saturating_add(1)
.min(self.history_len().saturating_sub(1)),
}; };
log::debug!("Using history index = {} for searching", history_index);
if let Some(history_index) = self.history.starts_with(buf, history_index, dir) { if let Some(history_index) = self.history.starts_with(buf, history_index, dir) {
log::debug!("Found index {:?}", history_index);
log::debug!("Previous index {:?}", self.history_index);
self.history_index = history_index; self.history_index = history_index;
Some(self.history.get(history_index).unwrap().clone()) Some(self.history.get(history_index).unwrap().clone())
} else if buf.is_empty() { } else if buf.is_empty() {
self.history_index = history_index; self.history_index = history_index;
Some(self.history.get(history_index).unwrap().clone()) Some(self.history.get(history_index).unwrap().clone())
} else { } else {
log::debug!("History index = {}. Found no match.", history_index);
None None
} }
} }

View file

@ -16,6 +16,10 @@ mod pane;
mod table; mod table;
mod task_report; mod task_report;
use log::{debug, error, info, log_enabled, trace, warn, Level, LevelFilter};
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
use std::io::{self, Write}; use std::io::{self, Write};
@ -41,8 +45,8 @@ use crate::action::Action;
use crate::event::{Event, EventConfig, Events, Key}; use crate::event::{Event, EventConfig, Events, Key};
use crate::keyconfig::KeyConfig; use crate::keyconfig::KeyConfig;
/// # Panics const LOG_PATTERN: &str = "{d(%Y-%m-%d %H:%M:%S)} | {l} | {f}:{L} | {m}{n}";
/// Will panic if could not obtain terminal
pub fn setup_terminal() -> Terminal<CrosstermBackend<io::Stdout>> { pub fn setup_terminal() -> Terminal<CrosstermBackend<io::Stdout>> {
enable_raw_mode().expect("Running not in terminal"); enable_raw_mode().expect("Running not in terminal");
let mut stdout = io::stdout(); let mut stdout = io::stdout();
@ -51,8 +55,7 @@ pub fn setup_terminal() -> Terminal<CrosstermBackend<io::Stdout>> {
let backend = CrosstermBackend::new(stdout); let backend = CrosstermBackend::new(stdout);
Terminal::new(backend).unwrap() Terminal::new(backend).unwrap()
} }
/// # Panics
/// Will panic if could not `disable_raw_mode`
pub fn destruct_terminal() { pub fn destruct_terminal() {
disable_raw_mode().unwrap(); disable_raw_mode().unwrap();
execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture).unwrap(); execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture).unwrap();
@ -61,10 +64,44 @@ pub fn destruct_terminal() {
fn main() { fn main() {
better_panic::install(); better_panic::install();
let data_local_dir = dirs::data_local_dir()
.expect("Unable to open data local directory.")
.join("taskwarrior-tui");
std::fs::create_dir_all(&data_local_dir).unwrap_or_else(|_| panic!("Unable to create {:?}", data_local_dir));
let logfile = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(LOG_PATTERN)))
.append(false)
.build(data_local_dir.join("taskwarrior-tui.log"))
.unwrap();
let levelfilter = match std::env::var("TASKWARRIOR_TUI_LOG_LEVEL")
.unwrap_or_else(|_| "info".to_string())
.as_str()
{
"off" => LevelFilter::Off,
"warn" => LevelFilter::Warn,
"info" => LevelFilter::Info,
"debug" => LevelFilter::Debug,
"trace" => LevelFilter::Trace,
_ => LevelFilter::Info,
};
let config = Config::builder()
.appender(Appender::builder().build("logfile", Box::new(logfile)))
.logger(Logger::builder().build("taskwarrior_tui", levelfilter))
.build(Root::builder().appender("logfile").build(LevelFilter::Info))
.unwrap();
log4rs::init_config(config).unwrap();
let matches = cli::generate_cli_app().get_matches(); let matches = cli::generate_cli_app().get_matches();
debug!("getting matches from clap...");
let config = matches.value_of("config").unwrap_or("~/.taskrc"); let config = matches.value_of("config").unwrap_or("~/.taskrc");
let report = matches.value_of("report").unwrap_or("next"); let report = matches.value_of("report").unwrap_or("next");
debug!("report = {:?}", &report);
debug!("config = {:?}", &config);
let r = task::block_on(tui_main(config, report)); let r = task::block_on(tui_main(config, report));
if let Err(err) = r { if let Err(err) = r {
eprintln!("\x1b[0;31m[taskwarrior-tui error]\x1b[0m: {}\n\nIf you need additional help, please report as a github issue on https://github.com/kdheepak/taskwarrior-tui", err); eprintln!("\x1b[0;31m[taskwarrior-tui error]\x1b[0m: {}\n\nIf you need additional help, please report as a github issue on https://github.com/kdheepak/taskwarrior-tui", err);
@ -99,6 +136,7 @@ async fn tui_main(_config: &str, report: &str) -> Result<()> {
// Handle input // Handle input
match events.next().await? { match events.next().await? {
Event::Input(input) => { Event::Input(input) => {
debug!("Received input = {:?}", input);
if (input == app.keyconfig.edit if (input == app.keyconfig.edit
|| input == app.keyconfig.shortcut1 || input == app.keyconfig.shortcut1
|| input == app.keyconfig.shortcut2 || input == app.keyconfig.shortcut2
@ -136,6 +174,7 @@ async fn tui_main(_config: &str, report: &str) -> Result<()> {
} }
} }
Event::Tick => { Event::Tick => {
trace!("Tick event");
let r = app.update(false); let r = app.update(false);
if r.is_err() { if r.is_err() {
destruct_terminal(); destruct_terminal();