Support custom shell command

This commit is contained in:
Dheepak Krishnamurthy 2020-10-09 21:34:54 -06:00
parent c1fcdffb71
commit cbb9e60ca8
3 changed files with 97 additions and 1 deletions

View file

@ -56,6 +56,7 @@ Use your favorite installation method to download the [AUR package](https://aur.
- `x`: `task delete {selected}` - Delete
- `A`: `task {selected} annotate {string}` - Annotate current task
- `?`: `help` - Help menu
- `!`: `{string}` - Custom shell command
![taskwarrior-tui](https://user-images.githubusercontent.com/1813121/88654924-40896880-d08b-11ea-8709-b29cc970da4c.gif)

View file

@ -116,6 +116,7 @@ pub enum AppMode {
TaskFilter,
TaskAdd,
TaskAnnotate,
TaskSubprocess,
TaskLog,
TaskModify,
TaskHelpPopup,
@ -195,6 +196,7 @@ impl TTApp {
| AppMode::TaskAnnotate
| AppMode::TaskError
| AppMode::TaskHelpPopup
| AppMode::TaskSubprocess
| AppMode::TaskLog
| AppMode::TaskModify => self.draw_task(f),
AppMode::Calendar => self.draw_calendar(f),
@ -259,6 +261,11 @@ impl TTApp {
f.render_widget(Clear, rects[1]);
self.draw_command(f, rects[1], &self.command[..], "Log Task");
}
AppMode::TaskSubprocess => {
f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1);
f.render_widget(Clear, rects[1]);
self.draw_command(f, rects[1], &self.command[..], "Shell Command");
}
AppMode::TaskAnnotate => {
f.set_cursor(rects[1].x + self.cursor_location as u16 + 1, rects[1].y + 1);
f.render_widget(Clear, rects[1]);
@ -282,7 +289,7 @@ impl TTApp {
self.draw_command(f, rects[1], &self.filter[..], "Filter Tasks");
self.draw_help_popup(f, f.size());
}
_ => {
AppMode::Calendar => {
panic!("Reached unreachable code. Something went wrong");
}
}
@ -445,6 +452,17 @@ impl TTApp {
Span::from("- Show this help menu"),
]),
Spans::from(""),
Spans::from(vec![
Span::from(" !"),
Span::from(" "),
Span::styled(
"shell ",
Style::default().add_modifier(Modifier::BOLD),
),
Span::from(" "),
Span::from("- Custom shell command"),
]),
Spans::from(""),
];
let paragraph = Paragraph::new(text)
.block(Block::default().title("Help").borders(Borders::ALL))
@ -783,6 +801,35 @@ impl TTApp {
}
}
pub fn task_subprocess(&mut self) -> Result<(), String> {
if self.tasks.lock().unwrap().is_empty() {
return Ok(());
}
match shlex::split(&self.command) {
Some(cmd) => {
let mut command = Command::new(&cmd[0]);
for (i, s) in cmd.iter().enumerate() {
if i == 0 {
continue;
}
command.arg(&s);
}
let output = command.output();
match output {
Ok(_) => {
self.command = "".to_string();
Ok(())
},
Err(_) => Err(
format!("Shell command `{}` exited with non-zero output", self.command),
)
}
}
None => Err(format!("Unable to split `{}`", &self.command)),
}
}
pub fn task_log(&mut self) -> Result<(), String> {
if self.tasks.lock().unwrap().is_empty() {
return Ok(());

View file

@ -114,8 +114,13 @@ fn tui_main(_config: &str) -> Result<(), Box<dyn Error>> {
}
app.cursor_location = app.modify.chars().count();
}
Key::Char('!') => {
app.mode = AppMode::TaskSubprocess;
app.cursor_location = app.command.chars().count();
}
Key::Char('l') => {
app.mode = AppMode::TaskLog;
app.cursor_location = app.command.chars().count();
}
Key::Char('a') => {
app.mode = AppMode::TaskAdd;
@ -183,6 +188,49 @@ fn tui_main(_config: &str) -> Result<(), Box<dyn Error>> {
}
_ => {}
},
AppMode::TaskSubprocess => match input {
Key::Char('\n') => match app.task_subprocess() {
Ok(_) => {
app.mode = AppMode::TaskReport;
app.update();
}
Err(e) => {
app.mode = AppMode::TaskError;
app.error = e;
}
},
Key::Esc => {
app.command = "".to_string();
app.mode = AppMode::TaskReport;
}
Key::Right => {
if app.cursor_location < app.command.chars().count() {
app.cursor_location += 1;
}
}
Key::Left => {
if app.cursor_location > 0 {
app.cursor_location -= 1;
}
}
Key::Char(c) => {
if app.cursor_location < app.command.chars().count() {
app.command.insert_str(app.cursor_location, &c.to_string());
} else {
app.command.push(c);
}
app.cursor_location += 1;
}
Key::Backspace => {
if app.cursor_location > 0 {
app.cursor_location -= 1;
let mut cs = app.command.chars().collect::<Vec<char>>();
cs.remove(app.cursor_location);
app.command = cs.into_iter().collect();
}
}
_ => {}
},
AppMode::TaskLog => match input {
Key::Char('\n') => match app.task_log() {
Ok(_) => {