mirror of
https://github.com/kdheepak/taskwarrior-tui.git
synced 2025-08-25 08:47:18 +02:00
Merge pull request #182 from kdheepak/jump-to-relevant-task-after-action
This commit is contained in:
commit
1d786d31d9
4 changed files with 115 additions and 18 deletions
|
@ -15,6 +15,7 @@ uda.taskwarrior-tui.unmark.indicator=
|
|||
uda.taskwarrior-tui.calendar.months-per-row=4
|
||||
uda.taskwarrior-tui.task-report.show-info=true
|
||||
uda.taskwarrior-tui.task-report.looping=true
|
||||
uda.taskwarrior-tui.task-report.jump-on-task-add=true
|
||||
uda.taskwarrior-tui.style.context.active=black on rgb444
|
||||
uda.taskwarrior-tui.style.calendar.title=black on rgb444
|
||||
```
|
||||
|
|
120
src/app.rs
120
src/app.rs
|
@ -180,6 +180,8 @@ pub struct TaskwarriorTuiApp {
|
|||
pub marked: HashSet<Uuid>,
|
||||
// stores index of current task that is highlighted
|
||||
pub current_selection: usize,
|
||||
pub current_selection_uuid: Option<Uuid>,
|
||||
pub current_selection_id: Option<u64>,
|
||||
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<usize> {
|
||||
let tasks = &self.tasks;
|
||||
let m = tasks.iter().position(|t| t.id().unwrap() == id);
|
||||
m
|
||||
}
|
||||
|
||||
fn task_index_by_uuid(&self, uuid: Uuid) -> Option<usize> {
|
||||
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,15 @@ 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<task_id>\d+).\n$").unwrap();
|
||||
let caps = re.captures(&data).unwrap();
|
||||
if self.config.uda_task_report_jump_to_task_on_add {
|
||||
self.current_selection_id = Some(caps["task_id"].parse::<u64>().unwrap());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => Err(format!(
|
||||
"Cannot run `task add {}`. Check documentation for more information",
|
||||
shell
|
||||
|
@ -1611,9 +1673,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 +1690,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 +1716,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 +1726,10 @@ impl TaskwarriorTuiApp {
|
|||
.collect::<Vec<String>>()
|
||||
.join(" ")
|
||||
)),
|
||||
}
|
||||
};
|
||||
self.current_selection_uuid = None;
|
||||
self.current_selection_id = None;
|
||||
r
|
||||
}
|
||||
|
||||
pub fn task_done(&mut self) -> Result<(), String> {
|
||||
|
@ -1679,7 +1747,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,22 +1757,36 @@ impl TaskwarriorTuiApp {
|
|||
.collect::<Vec<String>>()
|
||||
.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<task_uuid>[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()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn task_edit(&self) -> Result<(), String> {
|
||||
pub fn task_edit(&mut self) -> Result<(), String> {
|
||||
if self.tasks.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1713,7 +1795,7 @@ impl TaskwarriorTuiApp {
|
|||
let task_uuid = *self.tasks[selected].uuid();
|
||||
let r = Command::new("task").arg(format!("{}", task_uuid)).arg("edit").spawn();
|
||||
|
||||
match r {
|
||||
let r = match r {
|
||||
Ok(child) => {
|
||||
let output = child.wait_with_output();
|
||||
match output {
|
||||
|
@ -1738,7 +1820,11 @@ impl TaskwarriorTuiApp {
|
|||
"Cannot start `task edit` for task `{}`. Check documentation for more information",
|
||||
task_uuid
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
self.current_selection_uuid = Some(task_uuid);
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
pub fn task_current(&self) -> Option<Task> {
|
||||
|
|
|
@ -139,7 +139,7 @@ impl CompletionList {
|
|||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.candidates().iter().count()
|
||||
self.candidates().len()
|
||||
}
|
||||
|
||||
pub fn max_width(&self) -> Option<usize> {
|
||||
|
|
|
@ -48,6 +48,7 @@ pub struct Config {
|
|||
pub uda_task_detail_prefetch: usize,
|
||||
pub uda_task_report_show_info: bool,
|
||||
pub uda_task_report_looping: bool,
|
||||
pub uda_task_report_jump_to_task_on_add: bool,
|
||||
pub uda_selection_indicator: String,
|
||||
pub uda_mark_indicator: String,
|
||||
pub uda_unmark_indicator: String,
|
||||
|
@ -80,6 +81,7 @@ impl Config {
|
|||
let uda_task_detail_prefetch = Self::get_uda_task_detail_prefetch(data);
|
||||
let uda_task_report_show_info = Self::get_uda_task_report_show_info(data);
|
||||
let uda_task_report_looping = Self::get_uda_task_report_looping(data);
|
||||
let uda_task_report_jump_to_task_on_add = Self::get_uda_task_report_jump_to_task_on_add(data);
|
||||
let uda_selection_indicator = Self::get_uda_selection_indicator(data);
|
||||
let uda_mark_indicator = Self::get_uda_mark_indicator(data);
|
||||
let uda_unmark_indicator = Self::get_uda_unmark_indicator(data);
|
||||
|
@ -111,6 +113,7 @@ impl Config {
|
|||
uda_task_detail_prefetch,
|
||||
uda_task_report_show_info,
|
||||
uda_task_report_looping,
|
||||
uda_task_report_jump_to_task_on_add,
|
||||
uda_selection_indicator,
|
||||
uda_mark_indicator,
|
||||
uda_unmark_indicator,
|
||||
|
@ -377,6 +380,13 @@ impl Config {
|
|||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn get_uda_task_report_jump_to_task_on_add(data: &str) -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.task-report.jump-to-task-on-add", data)
|
||||
.unwrap_or_default()
|
||||
.get_bool()
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
fn get_uda_task_report_looping(data: &str) -> bool {
|
||||
Self::get_config("uda.taskwarrior-tui.task-report.looping", data)
|
||||
.unwrap_or_default()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue