fix: Fix tests and better logging and history 🐛

This commit is contained in:
Dheepak Krishnamurthy 2021-12-02 11:28:24 -07:00
parent b3683ae548
commit 08c30cf912
4 changed files with 137 additions and 64 deletions

3
.envrc
View file

@ -1,4 +1,5 @@
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 TASKWARRIOR_TUI_CONFIG=`pwd`/tests/data/.config
export TASKWARRIOR_TUI_DATA=`pwd`/tests/data/.data
export TASKWARRIOR_TUI_LOG_LEVEL=debug export TASKWARRIOR_TUI_LOG_LEVEL=debug

View file

@ -2546,10 +2546,13 @@ impl TaskwarriorTui {
} }
} else if input == self.keyconfig.modify { } else if input == self.keyconfig.modify {
self.mode = Mode::Tasks(Action::Modify); self.mode = Mode::Tasks(Action::Modify);
self.command_history.last(); self.command_history.reset();
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
self.update_completion_list(); self.update_completion_list();
@ -2598,28 +2601,37 @@ impl TaskwarriorTui {
self.mode = Mode::Tasks(Action::Subprocess); self.mode = Mode::Tasks(Action::Subprocess);
} else if input == self.keyconfig.log { } else if input == self.keyconfig.log {
self.mode = Mode::Tasks(Action::Log); self.mode = Mode::Tasks(Action::Log);
self.command_history.last(); self.command_history.reset();
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
self.update_completion_list(); self.update_completion_list();
} else if input == self.keyconfig.add { } else if input == self.keyconfig.add {
self.mode = Mode::Tasks(Action::Add); self.mode = Mode::Tasks(Action::Add);
self.command_history.last(); self.command_history.reset();
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
self.update_completion_list(); self.update_completion_list();
} else if input == self.keyconfig.annotate { } else if input == self.keyconfig.annotate {
self.mode = Mode::Tasks(Action::Annotate); self.mode = Mode::Tasks(Action::Annotate);
self.command_history.last(); self.command_history.reset();
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
self.update_completion_list(); self.update_completion_list();
@ -2627,10 +2639,13 @@ impl TaskwarriorTui {
self.mode = Mode::Tasks(Action::HelpPopup); self.mode = Mode::Tasks(Action::HelpPopup);
} else if input == self.keyconfig.filter { } else if input == self.keyconfig.filter {
self.mode = Mode::Tasks(Action::Filter); self.mode = Mode::Tasks(Action::Filter);
self.filter_history.last(); self.filter_history.reset();
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.filter_history.history_index() + 1, self.filter_history
.history_index()
.unwrap_or_else(|| self.filter_history.history_len().saturating_sub(1))
.saturating_add(1),
self.filter_history.history_len() self.filter_history.history_len()
)); ));
self.update_completion_list(); self.update_completion_list();
@ -2815,7 +2830,10 @@ impl TaskwarriorTui {
self.modify.update(&s, std::cmp::min(s.len(), p)); self.modify.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
@ -2832,13 +2850,16 @@ impl TaskwarriorTui {
self.modify.update(&s, std::cmp::min(s.len(), p)); self.modify.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
} }
_ => { _ => {
self.command_history.last(); self.command_history.reset();
handle_movement(&mut self.modify, input); handle_movement(&mut self.modify, input);
self.update_input_for_completion(); self.update_input_for_completion();
} }
@ -2932,7 +2953,10 @@ impl TaskwarriorTui {
self.command.update(&s, std::cmp::min(s.len(), p)); self.command.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
@ -2949,13 +2973,16 @@ impl TaskwarriorTui {
self.command.update(&s, std::cmp::min(s.len(), p)); self.command.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
} }
_ => { _ => {
self.command_history.last(); self.command_history.reset();
handle_movement(&mut self.command, input); handle_movement(&mut self.command, input);
self.update_input_for_completion(); self.update_input_for_completion();
} }
@ -3024,7 +3051,10 @@ impl TaskwarriorTui {
self.command.update(&s, std::cmp::min(s.len(), p)); self.command.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
@ -3041,14 +3071,17 @@ impl TaskwarriorTui {
self.command.update(&s, std::cmp::min(s.len(), p)); self.command.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
} }
_ => { _ => {
self.command_history.last(); self.command_history.reset();
handle_movement(&mut self.command, input); handle_movement(&mut self.command, input);
self.update_input_for_completion(); self.update_input_for_completion();
} }
@ -3142,7 +3175,10 @@ impl TaskwarriorTui {
self.command.update(&s, std::cmp::min(s.len(), p)); self.command.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
@ -3160,13 +3196,16 @@ impl TaskwarriorTui {
self.command.update(&s, std::cmp::min(s.len(), p)); self.command.update(&s, std::cmp::min(s.len(), p));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.command_history.history_index() + 1, self.command_history
.history_index()
.unwrap_or_else(|| self.command_history.history_len().saturating_sub(1))
.saturating_add(1),
self.command_history.history_len() self.command_history.history_len()
)); ));
} }
} }
_ => { _ => {
self.command_history.last(); self.command_history.reset();
handle_movement(&mut self.command, input); handle_movement(&mut self.command, input);
self.update_input_for_completion(); self.update_input_for_completion();
} }
@ -3215,7 +3254,10 @@ impl TaskwarriorTui {
self.filter.update(&s, std::cmp::min(p, s.len())); self.filter.update(&s, std::cmp::min(p, s.len()));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.filter_history.history_index() + 1, self.filter_history
.history_index()
.unwrap_or_else(|| self.filter_history.history_len().saturating_sub(1))
.saturating_add(1),
self.filter_history.history_len() self.filter_history.history_len()
)); ));
self.dirty = true; self.dirty = true;
@ -3233,7 +3275,10 @@ impl TaskwarriorTui {
self.filter.update(&s, std::cmp::min(p, s.len())); self.filter.update(&s, std::cmp::min(p, s.len()));
self.history_status = Some(format!( self.history_status = Some(format!(
" {} / {}", " {} / {}",
self.filter_history.history_index() + 1, self.filter_history
.history_index()
.unwrap_or_else(|| self.filter_history.history_len().saturating_sub(1))
.saturating_add(1),
self.filter_history.history_len() self.filter_history.history_len()
)); ));
self.dirty = true; self.dirty = true;

View file

@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
pub struct HistoryContext { pub struct HistoryContext {
history: History, history: History,
history_index: usize, history_index: Option<usize>,
config_path: PathBuf, config_path: PathBuf,
} }
@ -15,17 +15,22 @@ impl HistoryContext {
pub fn new(filename: &str) -> Self { pub fn new(filename: &str) -> Self {
let history = History::new(); let history = History::new();
let config_dir_op = dirs::config_dir(); let config_path = if let Ok(s) = std::env::var("TASKWARRIOR_TUI_CONFIG") {
PathBuf::from(s)
} else {
dirs::config_dir()
.map(|d| d.join("taskwarrior-tui"))
.expect("Unable to create configuration directory for taskwarrior-tui")
};
let config_path = config_dir_op.map(|d| d.join("taskwarrior-tui")).unwrap(); std::fs::create_dir_all(&config_path)
.unwrap_or_else(|_| panic!("Unable to create configuration directory in {:?}", &config_path));
std::fs::create_dir_all(&config_path).unwrap();
let config_path = config_path.join(filename); let config_path = config_path.join(filename);
Self { Self {
history, history,
history_index: 0, history_index: None,
config_path, config_path,
} }
} }
@ -36,7 +41,7 @@ impl HistoryContext {
} else { } else {
self.history.save(&self.config_path)?; self.history.save(&self.config_path)?;
} }
self.history_index = self.history.len(); self.history_index = None;
log::debug!("Loading history of length {}", self.history.len()); log::debug!("Loading history of length {}", self.history.len());
Ok(()) Ok(())
} }
@ -50,57 +55,69 @@ impl HistoryContext {
&self.history &self.history
} }
pub fn history_index(&self) -> usize { pub fn history_index(&self) -> Option<usize> {
self.history_index self.history_index
} }
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!( log::debug!(
"Searching history for {:?} in direction {:?} with history index = {:?}", "Searching history for {:?} in direction {:?} with history index = {:?} and history len = {:?}",
buf, buf,
dir, dir,
self.history_index() self.history_index(),
self.history.len(),
); );
if self.history.is_empty() { if self.history.is_empty() {
log::debug!("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
|| self.history_index == 0 && dir == Direction::Reverse let history_index = if self.history_index().is_none() {
log::debug!("History index is none");
match dir {
Direction::Forward => return None,
Direction::Reverse => self.history_index = Some(self.history_len().saturating_sub(1)),
}
self.history_index.unwrap()
} else {
let hi = self.history_index().unwrap();
if hi == self.history.len().saturating_sub(1) && dir == Direction::Forward
|| hi == 0 && dir == Direction::Reverse
{ {
log::debug!("No more history left to search");
return None; return None;
} }
let history_index = match dir {
Direction::Reverse => self.history_index.saturating_sub(1), match dir {
Direction::Forward => self Direction::Reverse => hi.saturating_sub(1),
.history_index Direction::Forward => hi.saturating_add(1).min(self.history_len().saturating_sub(1)),
.saturating_add(1) }
.min(self.history_len().saturating_sub(1)),
}; };
log::debug!("Using history index = {} for searching", history_index); log::debug!("Using history index = {} for searching", history_index);
if let Some(history_index) = self.history.starts_with(buf, history_index, dir) { return if let Some(history_index) = self.history.starts_with(buf, history_index, dir) {
log::debug!("Found index {:?}", history_index); log::debug!("Found index {:?}", history_index);
log::debug!("Previous index {:?}", self.history_index); log::debug!("Previous index {:?}", self.history_index);
self.history_index = history_index; self.history_index = Some(history_index);
Some(self.history.get(history_index).unwrap().clone()) self.history.get(history_index).cloned()
} else if buf.is_empty() { } else if buf.is_empty() {
self.history_index = history_index; self.history_index = Some(history_index);
Some(self.history.get(history_index).unwrap().clone()) self.history.get(history_index).cloned()
} else { } else {
log::debug!("History index = {}. Found no match.", history_index); log::debug!("History index = {}. Found no match.", history_index);
None None
} };
} }
pub fn add(&mut self, buf: &str) { pub fn add(&mut self, buf: &str) {
if self.history.add(buf) { if self.history.add(buf) {
self.history_index = self.history.len() - 1; self.reset();
} }
} }
pub fn last(&mut self) { pub fn reset(&mut self) {
self.history_index = self.history.len().saturating_sub(1); self.history_index = None
} }
pub fn history_len(&self) -> usize { pub fn history_len(&self) -> usize {

View file

@ -24,6 +24,7 @@ use std::env;
use std::error::Error; use std::error::Error;
use std::io::{self, Write}; use std::io::{self, Write};
use std::panic; use std::panic;
use std::path::{Path, PathBuf};
use std::time::Duration; use std::time::Duration;
use anyhow::Result; use anyhow::Result;
@ -62,19 +63,22 @@ pub fn destruct_terminal() {
execute!(io::stdout(), cursor::Show).unwrap(); execute!(io::stdout(), cursor::Show).unwrap();
} }
fn main() { pub fn initialize_logging() {
better_panic::install(); let data_local_dir = if let Ok(s) = std::env::var("TASKWARRIOR_TUI_DATA") {
PathBuf::from(s)
} else {
dirs::data_local_dir()
.expect("Unable to find data directory for taskwarrior-tui")
.join("taskwarrior-tui")
};
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)); std::fs::create_dir_all(&data_local_dir).unwrap_or_else(|_| panic!("Unable to create {:?}", data_local_dir));
let logfile = FileAppender::builder() let logfile = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(LOG_PATTERN))) .encoder(Box::new(PatternEncoder::new(LOG_PATTERN)))
.append(false) .append(false)
.build(data_local_dir.join("taskwarrior-tui.log")) .build(data_local_dir.join("taskwarrior-tui.log"))
.unwrap(); .expect("Failed to build log file appender.");
let levelfilter = match std::env::var("TASKWARRIOR_TUI_LOG_LEVEL") let levelfilter = match std::env::var("TASKWARRIOR_TUI_LOG_LEVEL")
.unwrap_or_else(|_| "info".to_string()) .unwrap_or_else(|_| "info".to_string())
@ -91,9 +95,15 @@ fn main() {
.appender(Appender::builder().build("logfile", Box::new(logfile))) .appender(Appender::builder().build("logfile", Box::new(logfile)))
.logger(Logger::builder().build("taskwarrior_tui", levelfilter)) .logger(Logger::builder().build("taskwarrior_tui", levelfilter))
.build(Root::builder().appender("logfile").build(LevelFilter::Info)) .build(Root::builder().appender("logfile").build(LevelFilter::Info))
.unwrap(); .expect("Failed to build logging config.");
log4rs::init_config(config).unwrap(); log4rs::init_config(config).expect("Failed to initialize logging.");
}
fn main() {
better_panic::install();
initialize_logging();
let matches = cli::generate_cli_app().get_matches(); let matches = cli::generate_cli_app().get_matches();