From 94d2c7b74b3ff878aa7062dd966b92702a1dd6eb Mon Sep 17 00:00:00 2001 From: Dheepak Krishnamurthy Date: Thu, 8 Apr 2021 12:53:17 -0600 Subject: [PATCH] Jump to relevant task after action --- src/app.rs | 108 ++++++++++++++++++++++++++++++++++++++++------ src/completion.rs | 2 +- 2 files changed, 95 insertions(+), 15 deletions(-) diff --git a/src/app.rs b/src/app.rs index d398aba..e014721 100644 --- a/src/app.rs +++ b/src/app.rs @@ -180,6 +180,8 @@ pub struct TaskwarriorTuiApp { pub marked: HashSet, // stores index of current task that is highlighted pub current_selection: usize, + pub current_selection_uuid: Option, + pub current_selection_id: Option, pub task_report_table: TaskReportTable, pub calendar_year: i32, pub mode: AppMode, @@ -236,6 +238,8 @@ impl TaskwarriorTuiApp { task_details: HashMap::new(), marked: HashSet::new(), current_selection: 0, + current_selection_uuid: None, + current_selection_id: None, current_context_filter: "".to_string(), current_context: "".to_string(), command: LineBuffer::with_capacity(MAX_LINE), @@ -777,6 +781,12 @@ impl TaskwarriorTuiApp { m.cloned() } + fn task_index_by_id(&self, id: u64) -> Option { + let tasks = &self.tasks; + let m = tasks.iter().position(|t| t.id().unwrap() == id); + m + } + fn task_index_by_uuid(&self, uuid: Uuid) -> Option { let tasks = &self.tasks; let m = tasks.iter().position(|t| *t.uuid() == uuid); @@ -995,9 +1005,30 @@ impl TaskwarriorTuiApp { if self.task_report_show_info { task::block_on(self.update_task_details())?; } + self.selection_fix(); Ok(()) } + pub fn selection_fix(&mut self) { + if let (Some(t), Some(id)) = (self.task_current(), self.current_selection_id) { + if t.id() != Some(id) { + if let Some(i) = self.task_index_by_id(id) { + self.current_selection = i; + self.current_selection_id = None; + } + } + } + + if let (Some(t), Some(uuid)) = (self.task_current(), self.current_selection_uuid) { + if t.uuid() != &uuid { + if let Some(i) = self.task_index_by_uuid(uuid) { + self.current_selection = i; + self.current_selection_uuid = None; + } + } + } + } + pub fn save_history(&mut self) -> Result<()> { self.filter_history_context.write()?; self.command_history_context.write()?; @@ -1439,7 +1470,7 @@ impl TaskwarriorTuiApp { .join(" ") ); let shell = shellexpand::tilde(&shell).into_owned(); - match shlex::split(&shell) { + let r = match shlex::split(&shell) { Some(cmd) => { let mut command = Command::new(&cmd[0]); for s in cmd.iter().skip(1) { @@ -1462,7 +1493,15 @@ impl TaskwarriorTuiApp { } } None => Err(format!("Unable to run `{}`. Cannot shlex split `{}`", shell, shell)), + }; + + if task_uuids.len() == 1 { + if let Some(uuid) = task_uuids.get(0) { + self.current_selection_uuid = Some(*uuid); + } } + + r } pub fn task_modify(&mut self) -> Result<(), String> { @@ -1484,7 +1523,7 @@ impl TaskwarriorTuiApp { let shell = self.modify.as_str(); - match shlex::split(&shell) { + let r = match shlex::split(&shell) { Some(cmd) => { for s in cmd { command.arg(&s); @@ -1505,7 +1544,15 @@ impl TaskwarriorTuiApp { } } None => Err(format!("Cannot shlex split `{}`", shell,)), + }; + + if task_uuids.len() == 1 { + if let Some(uuid) = task_uuids.get(0) { + self.current_selection_uuid = Some(*uuid); + } } + + r } pub fn task_annotate(&mut self) -> Result<(), String> { @@ -1527,7 +1574,7 @@ impl TaskwarriorTuiApp { let shell = self.command.as_str(); - match shlex::split(&shell) { + let r = match shlex::split(&shell) { Some(cmd) => { for s in cmd { command.arg(&s); @@ -1553,7 +1600,14 @@ impl TaskwarriorTuiApp { } } None => Err(format!("Cannot shlex split `{}`", shell)), + }; + + if task_uuids.len() == 1 { + if let Some(uuid) = task_uuids.get(0) { + self.current_selection_uuid = Some(*uuid); + } } + r } pub fn task_add(&mut self) -> Result<(), String> { @@ -1569,7 +1623,13 @@ impl TaskwarriorTuiApp { } let output = command.output(); match output { - Ok(_) => Ok(()), + Ok(output) => { + let data = String::from_utf8_lossy(&output.stdout); + let re = Regex::new(r"^Created task (?P\d+).\n$").unwrap(); + let caps = re.captures(&data).unwrap(); + self.current_selection_id = Some(caps["task_id"].parse::().unwrap()); + Ok(()) + } Err(_) => Err(format!( "Cannot run `task add {}`. Check documentation for more information", shell @@ -1611,9 +1671,6 @@ impl TaskwarriorTuiApp { if self.tasks.is_empty() { return Ok(()); } - let selected = self.current_selection; - let task_id = self.tasks[selected].id().unwrap_or_default(); - let task_uuid = *self.tasks[selected].uuid(); let task_uuids = self.selected_task_uuids(); @@ -1631,10 +1688,16 @@ impl TaskwarriorTuiApp { } } + if task_uuids.len() == 1 { + if let Some(uuid) = task_uuids.get(0) { + self.current_selection_uuid = Some(*uuid); + } + } + Ok(()) } - pub fn task_delete(&self) -> Result<(), String> { + pub fn task_delete(&mut self) -> Result<(), String> { if self.tasks.is_empty() { return Ok(()); } @@ -1651,7 +1714,7 @@ impl TaskwarriorTuiApp { } cmd.arg("delete"); let output = cmd.output(); - match output { + let r = match output { Ok(_) => Ok(()), Err(_) => Err(format!( "Cannot run `task delete` for tasks `{}`. Check documentation for more information", @@ -1661,7 +1724,10 @@ impl TaskwarriorTuiApp { .collect::>() .join(" ") )), - } + }; + self.current_selection_uuid = None; + self.current_selection_id = None; + r } pub fn task_done(&mut self) -> Result<(), String> { @@ -1679,7 +1745,7 @@ impl TaskwarriorTuiApp { } cmd.arg("done"); let output = cmd.output(); - match output { + let r = match output { Ok(_) => Ok(()), Err(_) => Err(format!( "Cannot run `task done` for task `{}`. Check documentation for more information", @@ -1689,17 +1755,31 @@ impl TaskwarriorTuiApp { .collect::>() .join(" ") )), - } + }; + self.current_selection_uuid = None; + self.current_selection_id = None; + r } - pub fn task_undo(&self) -> Result<(), String> { + pub fn task_undo(&mut self) -> Result<(), String> { if self.tasks.is_empty() { return Ok(()); } let output = Command::new("task").arg("rc.confirmation=off").arg("undo").output(); match output { - Ok(_) => Ok(()), + Ok(output) => { + let data = String::from_utf8_lossy(&output.stdout); + let re = Regex::new( + r"(?P[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})", + ) + .unwrap(); + let caps = re.captures(&data).unwrap(); + if let Ok(uuid) = Uuid::parse_str(&caps["task_uuid"]) { + self.current_selection_uuid = Some(uuid); + } + Ok(()) + } Err(_) => Err("Cannot run `task undo`. Check documentation for more information".to_string()), } } diff --git a/src/completion.rs b/src/completion.rs index 4fbb22f..e5ac1fd 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -139,7 +139,7 @@ impl CompletionList { } pub fn len(&self) -> usize { - self.candidates().iter().count() + self.candidates().len() } pub fn max_width(&self) -> Option {