mirror of
https://github.com/kdheepak/taskwarrior-tui.git
synced 2025-08-25 08:47:18 +02:00
[redesign] - update ui
This commit is contained in:
parent
9517bc1966
commit
046d2e25c1
3 changed files with 110 additions and 166 deletions
|
@ -1,4 +1,4 @@
|
|||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[derive(Clone, PartialEq, Debug, Copy)]
|
||||
pub enum Action {
|
||||
Report,
|
||||
Filter,
|
||||
|
|
272
src/app.rs
272
src/app.rs
|
@ -83,6 +83,7 @@ use task_hookrs::project::Project;
|
|||
use versions::Versioning;
|
||||
|
||||
use log::{debug, error, info, log_enabled, trace, warn, Level, LevelFilter};
|
||||
use tui::widgets::Tabs;
|
||||
|
||||
const MAX_LINE: usize = 4096;
|
||||
|
||||
|
@ -133,7 +134,7 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
|||
Constraint::Percentage(percent_y),
|
||||
Constraint::Percentage((100 - percent_y) / 2),
|
||||
]
|
||||
.as_ref(),
|
||||
.as_ref(),
|
||||
)
|
||||
.split(r);
|
||||
|
||||
|
@ -145,7 +146,7 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
|
|||
Constraint::Percentage(percent_x),
|
||||
Constraint::Percentage((100 - percent_x) / 2),
|
||||
]
|
||||
.as_ref(),
|
||||
.as_ref(),
|
||||
)
|
||||
.split(popup_layout[1])[1]
|
||||
}
|
||||
|
@ -329,8 +330,8 @@ impl TaskwarriorTui {
|
|||
}
|
||||
|
||||
pub fn render<B>(&mut self, terminal: &mut Terminal<B>) -> Result<()>
|
||||
where
|
||||
B: Backend,
|
||||
where
|
||||
B: Backend,
|
||||
{
|
||||
terminal.draw(|f| self.draw(f))?;
|
||||
Ok(())
|
||||
|
@ -340,54 +341,65 @@ impl TaskwarriorTui {
|
|||
let rect = f.size();
|
||||
self.terminal_width = rect.width;
|
||||
self.terminal_height = rect.height;
|
||||
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Length(1), Constraint::Min(0)])
|
||||
.split(f.size());
|
||||
|
||||
let tab_layout = chunks[0];
|
||||
let main_layout = chunks[1];
|
||||
|
||||
self.draw_tabs(f, tab_layout);
|
||||
match self.mode {
|
||||
Mode::Tasks(_) => self.draw_task(f),
|
||||
Mode::Calendar => self.draw_calendar(f),
|
||||
Mode::Projects => self.draw_projects(f),
|
||||
Mode::Tasks(action) => self.draw_task(f, main_layout, action),
|
||||
Mode::Calendar => self.draw_calendar(f, main_layout),
|
||||
Mode::Projects => self.draw_projects(f, main_layout),
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_tabs(&self, f: &mut Frame<impl Backend>, layout: Rect) {
|
||||
let titles: Vec<&str> = vec!["Tasks", "Projects", "Calendar"];
|
||||
let tab_names: Vec<_> = titles.into_iter().map(|name| Spans::from(name)).collect();
|
||||
let selected_tab = match self.mode {
|
||||
Mode::Tasks(_) => 0,
|
||||
Mode::Projects => 1,
|
||||
Mode::Calendar => 2,
|
||||
};
|
||||
let tabs_block = Block::default().style(Style::default().add_modifier(Modifier::REVERSED));
|
||||
let context = Spans::from(vec![
|
||||
Span::from("["),
|
||||
Span::from(if self.current_context.is_empty() { "none" } else { &self.current_context }),
|
||||
Span::from("]")
|
||||
]);
|
||||
let tabs = Tabs::new(tab_names)
|
||||
.block(tabs_block.clone())
|
||||
.select(selected_tab)
|
||||
.divider(" ")
|
||||
.highlight_style(
|
||||
Style::default().add_modifier(Modifier::BOLD)
|
||||
);
|
||||
let rects = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints([Constraint::Min(0), Constraint::Length(context.width() as u16)])
|
||||
.split(layout);
|
||||
|
||||
f.render_widget(tabs, rects[0]);
|
||||
f.render_widget(Paragraph::new(Text::from(context)).block(tabs_block), rects[1]);
|
||||
}
|
||||
|
||||
pub fn draw_debug(&mut self, f: &mut Frame<impl Backend>) {
|
||||
let area = centered_rect(50, 50, f.size());
|
||||
f.render_widget(Clear, area);
|
||||
let t = format!("{}", self.current_selection,);
|
||||
let t = format!("{}", self.current_selection);
|
||||
let p = Paragraph::new(Text::from(t))
|
||||
.block(Block::default().borders(Borders::ALL).border_type(BorderType::Rounded));
|
||||
f.render_widget(p, area);
|
||||
}
|
||||
|
||||
pub fn draw_projects(&mut self, f: &mut Frame<impl Backend>) {
|
||||
let rects = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Min(0)].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
let today = Local::today();
|
||||
let title = vec![
|
||||
Span::styled("Task", Style::default().add_modifier(Modifier::DIM)),
|
||||
Span::from("|"),
|
||||
Span::styled("Projects", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::from("|"),
|
||||
Span::styled("Calendar", Style::default().add_modifier(Modifier::DIM)),
|
||||
];
|
||||
|
||||
let split_task_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Percentage(100)].as_ref())
|
||||
.split(rects[0]);
|
||||
|
||||
self.projects.report_height = split_task_layout[0].height;
|
||||
self.draw_projects_report_window(f, split_task_layout[0], title);
|
||||
}
|
||||
|
||||
fn draw_projects_report_window(&mut self, f: &mut Frame<impl Backend>, rect: Rect, title: Vec<Span>) {
|
||||
pub fn draw_projects(&mut self, f: &mut Frame<impl Backend>, rect: Rect) {
|
||||
let data = self.projects.data.clone();
|
||||
let p = Paragraph::new(Text::from(&data[..])).block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.title(title),
|
||||
);
|
||||
let p = Paragraph::new(Text::from(&data[..]));
|
||||
f.render_widget(p, rect);
|
||||
}
|
||||
|
||||
|
@ -411,50 +423,32 @@ impl TaskwarriorTui {
|
|||
style
|
||||
}
|
||||
|
||||
pub fn draw_calendar(&mut self, f: &mut Frame<impl Backend>) {
|
||||
let dates_with_styles = self.get_dates_with_styles();
|
||||
let rects = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Min(0)].as_ref())
|
||||
.split(f.size());
|
||||
let today = Local::today();
|
||||
let mut title = vec![
|
||||
Span::styled("Task", Style::default().add_modifier(Modifier::DIM)),
|
||||
Span::from("|"),
|
||||
Span::styled("Projects", Style::default().add_modifier(Modifier::DIM)),
|
||||
Span::from("|"),
|
||||
Span::styled("Calendar", Style::default().add_modifier(Modifier::BOLD)),
|
||||
];
|
||||
|
||||
if !self.current_context.is_empty() {
|
||||
let context_style = Style::default();
|
||||
context_style.add_modifier(Modifier::ITALIC);
|
||||
title.insert(title.len(), Span::from(" ("));
|
||||
title.insert(title.len(), Span::styled(&self.current_context, context_style));
|
||||
title.insert(title.len(), Span::from(")"));
|
||||
}
|
||||
pub fn draw_calendar(&mut self, f: &mut Frame<impl Backend>, layout: Rect) {
|
||||
// FIXME:
|
||||
// if !self.current_context.is_empty() {
|
||||
// let context_style = Style::default();
|
||||
// context_style.add_modifier(Modifier::ITALIC);
|
||||
// title.insert(title.len(), Span::from(" ("));
|
||||
// title.insert(title.len(), Span::styled(&self.current_context, context_style));
|
||||
// title.insert(title.len(), Span::from(")"));
|
||||
// }
|
||||
|
||||
let mut c = Calendar::default()
|
||||
.block(
|
||||
Block::default()
|
||||
.title(Spans::from(title))
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded),
|
||||
)
|
||||
.today_style(self.config.uda_style_calendar_today)
|
||||
.year(self.calendar_year)
|
||||
.date_style(dates_with_styles)
|
||||
.date_style(self.get_dates_with_styles())
|
||||
.months_per_row(self.config.uda_calendar_months_per_row);
|
||||
c.title_background_color = self.config.uda_style_calendar_title.bg.unwrap_or(Color::Reset);
|
||||
f.render_widget(c, rects[0]);
|
||||
f.render_widget(c, layout);
|
||||
}
|
||||
|
||||
pub fn draw_task(&mut self, f: &mut Frame<impl Backend>) {
|
||||
pub fn draw_task(&mut self, f: &mut Frame<impl Backend>, layout: Rect, action: Action) {
|
||||
let rects = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Min(0), Constraint::Length(3)].as_ref())
|
||||
.split(f.size());
|
||||
.constraints([Constraint::Min(0), Constraint::Length(2)].as_ref())
|
||||
.split(layout);
|
||||
|
||||
// render task report and task details if required
|
||||
if self.task_report_show_info {
|
||||
let split_task_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
|
@ -465,14 +459,11 @@ impl TaskwarriorTui {
|
|||
self.draw_task_report(f, split_task_layout[0]);
|
||||
self.draw_task_details(f, split_task_layout[1]);
|
||||
} else {
|
||||
let full_table_layout = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Percentage(100)].as_ref())
|
||||
.split(rects[0]);
|
||||
|
||||
self.task_report_height = full_table_layout[0].height;
|
||||
self.draw_task_report(f, full_table_layout[0]);
|
||||
self.task_report_height = rects[0].height;
|
||||
self.draw_task_report(f, rects[0]);
|
||||
}
|
||||
|
||||
// calculate selected tasks
|
||||
let selected = self.current_selection;
|
||||
let task_ids = if self.tasks.is_empty() {
|
||||
vec!["0".to_string()]
|
||||
|
@ -490,12 +481,14 @@ impl TaskwarriorTui {
|
|||
}
|
||||
}
|
||||
};
|
||||
self.handle_task_mode_action(f, &rects, &task_ids);
|
||||
|
||||
// render task mode
|
||||
self.handle_task_mode_action(f, &rects, &task_ids, action);
|
||||
}
|
||||
|
||||
fn handle_task_mode_action(&mut self, f: &mut Frame<impl Backend>, rects: &[Rect], task_ids: &[String]) {
|
||||
match self.mode {
|
||||
Mode::Tasks(Action::Error) => {
|
||||
fn handle_task_mode_action(&mut self, f: &mut Frame<impl Backend>, rects: &[Rect], task_ids: &[String], action: Action) {
|
||||
match action {
|
||||
Action::Error => {
|
||||
Self::draw_command(
|
||||
f,
|
||||
rects[1],
|
||||
|
@ -527,7 +520,7 @@ impl TaskwarriorTui {
|
|||
.constraints([Constraint::Min(0)].as_ref())
|
||||
.split(f.size());
|
||||
}
|
||||
Mode::Tasks(Action::Report) => {
|
||||
Action::Report => {
|
||||
// reset error when entering Action::Report
|
||||
self.previous_mode = None;
|
||||
self.error = None;
|
||||
|
@ -545,7 +538,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::Jump) => {
|
||||
Action::Jump => {
|
||||
let position = Self::get_position(&self.command);
|
||||
Self::draw_command(
|
||||
f,
|
||||
|
@ -560,7 +553,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::Filter) => {
|
||||
Action::Filter => {
|
||||
let position = Self::get_position(&self.filter);
|
||||
if self.show_completion_pane {
|
||||
self.draw_completion_pop_up(f, rects[1], position);
|
||||
|
@ -581,7 +574,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::Log) => {
|
||||
Action::Log => {
|
||||
if self.config.uda_auto_insert_double_quotes_on_log && self.command.is_empty() {
|
||||
self.command.update(r#""""#, 1);
|
||||
};
|
||||
|
@ -605,7 +598,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::Subprocess) => {
|
||||
Action::Subprocess => {
|
||||
let position = Self::get_position(&self.command);
|
||||
Self::draw_command(
|
||||
f,
|
||||
|
@ -620,7 +613,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::Modify) => {
|
||||
Action::Modify => {
|
||||
let position = Self::get_position(&self.modify);
|
||||
if self.show_completion_pane {
|
||||
self.draw_completion_pop_up(f, rects[1], position);
|
||||
|
@ -646,7 +639,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::Annotate) => {
|
||||
Action::Annotate => {
|
||||
if self.config.uda_auto_insert_double_quotes_on_annotate && self.command.is_empty() {
|
||||
self.command.update(r#""""#, 1);
|
||||
};
|
||||
|
@ -675,7 +668,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::Add) => {
|
||||
Action::Add => {
|
||||
if self.config.uda_auto_insert_double_quotes_on_add && self.command.is_empty() {
|
||||
self.command.update(r#""""#, 1);
|
||||
};
|
||||
|
@ -699,7 +692,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::HelpPopup) => {
|
||||
Action::HelpPopup => {
|
||||
Self::draw_command(
|
||||
f,
|
||||
rects[1],
|
||||
|
@ -711,7 +704,7 @@ impl TaskwarriorTui {
|
|||
);
|
||||
self.draw_help_popup(f, 80, 90);
|
||||
}
|
||||
Mode::Tasks(Action::ContextMenu) => {
|
||||
Action::ContextMenu => {
|
||||
Self::draw_command(
|
||||
f,
|
||||
rects[1],
|
||||
|
@ -723,7 +716,7 @@ impl TaskwarriorTui {
|
|||
);
|
||||
self.draw_context_menu(f, 80, 50);
|
||||
}
|
||||
Mode::Tasks(Action::DonePrompt) => {
|
||||
Action::DonePrompt => {
|
||||
let label = if task_ids.len() > 1 {
|
||||
format!("Done Tasks {}?", task_ids.join(","))
|
||||
} else {
|
||||
|
@ -747,7 +740,7 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
Mode::Tasks(Action::DeletePrompt) => {
|
||||
Action::DeletePrompt => {
|
||||
let label = if task_ids.len() > 1 {
|
||||
format!("Delete Tasks {}?", task_ids.join(","))
|
||||
} else {
|
||||
|
@ -771,9 +764,6 @@ impl TaskwarriorTui {
|
|||
self.error.clone(),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
panic!("Reached unreachable code. Something went wrong");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,15 +930,11 @@ impl TaskwarriorTui {
|
|||
f.render_widget(Clear, rect);
|
||||
if cursor {
|
||||
f.set_cursor(
|
||||
std::cmp::min(rect.x + position as u16 + 1, rect.x + rect.width.saturating_sub(2)),
|
||||
std::cmp::min(rect.x + position as u16, rect.x + rect.width.saturating_sub(2)),
|
||||
rect.y + 1,
|
||||
);
|
||||
}
|
||||
let border_style = if error.is_some() {
|
||||
Style::default().fg(Color::Indexed(1)) // red color border for errors
|
||||
} else {
|
||||
Style::default()
|
||||
};
|
||||
let fg_color = if error.is_some() { Color::Red } else { Color::Reset };
|
||||
|
||||
let title = if let Some(subtitle) = title.1 {
|
||||
let w = (title.0.width() + subtitle.width()).try_into().unwrap();
|
||||
|
@ -961,9 +947,8 @@ impl TaskwarriorTui {
|
|||
let p = Paragraph::new(Text::from(text))
|
||||
.block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.border_style(border_style)
|
||||
.borders(Borders::TOP)
|
||||
.style(Style::default().fg(fg_color))
|
||||
.title(title),
|
||||
)
|
||||
.scroll((0, ((position + 3) as u16).saturating_sub(rect.width)));
|
||||
|
@ -996,12 +981,7 @@ impl TaskwarriorTui {
|
|||
self.task_details_scroll,
|
||||
);
|
||||
let p = Paragraph::new(Text::from(&data[..]))
|
||||
.block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.title(format!("Task {}", task_id)),
|
||||
)
|
||||
.block(Block::default().borders(Borders::TOP))
|
||||
.scroll((self.task_details_scroll, 0));
|
||||
f.render_widget(p, rect);
|
||||
}
|
||||
|
@ -1139,36 +1119,14 @@ impl TaskwarriorTui {
|
|||
|
||||
fn draw_task_report(&mut self, f: &mut Frame<impl Backend>, rect: Rect) {
|
||||
let (tasks, headers) = self.get_task_report();
|
||||
let mut style = Style::default();
|
||||
match self.mode {
|
||||
Mode::Tasks(Action::Report) => style = style.add_modifier(Modifier::BOLD),
|
||||
_ => style = style.add_modifier(Modifier::DIM),
|
||||
}
|
||||
|
||||
let mut title = vec![
|
||||
Span::styled("Task", style),
|
||||
Span::from("|"),
|
||||
Span::styled("Projects", Style::default().add_modifier(Modifier::DIM)),
|
||||
Span::from("|"),
|
||||
Span::styled("Calendar", Style::default().add_modifier(Modifier::DIM)),
|
||||
];
|
||||
|
||||
if tasks.is_empty() {
|
||||
if !self.current_context.is_empty() {
|
||||
let context_style = Style::default();
|
||||
context_style.add_modifier(Modifier::ITALIC);
|
||||
title.insert(title.len(), Span::from(" ("));
|
||||
title.insert(title.len(), Span::styled(&self.current_context, context_style));
|
||||
title.insert(title.len(), Span::from(")"));
|
||||
}
|
||||
|
||||
f.render_widget(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.title(Spans::from(title)),
|
||||
rect,
|
||||
);
|
||||
f.render_widget(Block::default(), rect);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1215,21 +1173,9 @@ impl TaskwarriorTui {
|
|||
.map(|i| Constraint::Length((*i).try_into().unwrap_or(maximum_column_width as u16)))
|
||||
.collect();
|
||||
|
||||
if !self.current_context.is_empty() {
|
||||
let context_style = Style::default();
|
||||
context_style.add_modifier(Modifier::ITALIC);
|
||||
title.insert(title.len(), Span::from(" ("));
|
||||
title.insert(title.len(), Span::styled(&self.current_context, context_style));
|
||||
title.insert(title.len(), Span::from(")"));
|
||||
}
|
||||
|
||||
|
||||
let t = Table::new(header, rows.into_iter())
|
||||
.block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.border_type(BorderType::Rounded)
|
||||
.title(Spans::from(title)),
|
||||
)
|
||||
.header_style(
|
||||
self.config
|
||||
.color
|
||||
|
@ -1253,7 +1199,7 @@ impl TaskwarriorTui {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_all_contexts(&self) -> (Vec<Vec<String>>, Vec<String>) {
|
||||
fn get_all_contexts(&self) -> (Vec<Vec<String>>, Vec<String>) {
|
||||
let contexts = self
|
||||
.contexts
|
||||
.rows
|
||||
|
@ -1265,7 +1211,7 @@ impl TaskwarriorTui {
|
|||
(contexts, headers)
|
||||
}
|
||||
|
||||
pub fn get_task_report(&mut self) -> (Vec<Vec<String>>, Vec<String>) {
|
||||
fn get_task_report(&mut self) -> (Vec<Vec<String>>, Vec<String>) {
|
||||
self.task_report_table.generate_table(&self.tasks);
|
||||
let (tasks, headers) = self.task_report_table.simplify_table();
|
||||
(tasks, headers)
|
||||
|
@ -1663,7 +1609,7 @@ impl TaskwarriorTui {
|
|||
// .arg("rc.verbose:override=false");
|
||||
|
||||
if let Some(args) =
|
||||
shlex::split(format!(r#"rc.report.{}.filter='{}'"#, self.report, self.filter.trim(),).trim())
|
||||
shlex::split(format!(r#"rc.report.{}.filter='{}'"#, self.report, self.filter.trim(), ).trim())
|
||||
{
|
||||
for arg in args {
|
||||
task.arg(arg);
|
||||
|
@ -1758,7 +1704,7 @@ impl TaskwarriorTui {
|
|||
let output = command.output();
|
||||
match output {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(format!("Shell command `{}` exited with non-zero output", shell,)),
|
||||
Err(_) => Err(format!("Shell command `{}` exited with non-zero output", shell, )),
|
||||
}
|
||||
}
|
||||
None => Err(format!("Cannot run subprocess. Unable to shlex split `{}`", shell)),
|
||||
|
@ -1874,10 +1820,10 @@ impl TaskwarriorTui {
|
|||
))
|
||||
}
|
||||
}
|
||||
Err(s) => Err(format!("`{}` failed: {}", shell, s,)),
|
||||
Err(s) => Err(format!("`{}` failed: {}", shell, s, )),
|
||||
}
|
||||
} else {
|
||||
Err(format!("`{}` failed: {}", shell, s,))
|
||||
Err(format!("`{}` failed: {}", shell, s, ))
|
||||
}
|
||||
}
|
||||
None => Err(format!(
|
||||
|
@ -1925,7 +1871,7 @@ impl TaskwarriorTui {
|
|||
if o.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Modify failed. {}", String::from_utf8_lossy(&o.stdout),))
|
||||
Err(format!("Modify failed. {}", String::from_utf8_lossy(&o.stdout), ))
|
||||
}
|
||||
}
|
||||
Err(_) => Err(format!(
|
||||
|
@ -1934,7 +1880,7 @@ impl TaskwarriorTui {
|
|||
)),
|
||||
}
|
||||
}
|
||||
None => Err(format!("Cannot shlex split `{}`", shell,)),
|
||||
None => Err(format!("Cannot shlex split `{}`", shell, )),
|
||||
};
|
||||
|
||||
if task_uuids.len() == 1 {
|
||||
|
@ -1976,7 +1922,7 @@ impl TaskwarriorTui {
|
|||
if o.status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Annotate failed. {}", String::from_utf8_lossy(&o.stdout),))
|
||||
Err(format!("Annotate failed. {}", String::from_utf8_lossy(&o.stdout), ))
|
||||
}
|
||||
}
|
||||
Err(_) => Err(format!(
|
||||
|
@ -2029,7 +1975,7 @@ impl TaskwarriorTui {
|
|||
Err(format!("Error: {}", String::from_utf8_lossy(&output.stderr)))
|
||||
}
|
||||
}
|
||||
Err(e) => Err(format!("Cannot run `{:?}`: {}", command, e,)),
|
||||
Err(e) => Err(format!("Cannot run `{:?}`: {}", command, e, )),
|
||||
}
|
||||
}
|
||||
None => Err(format!(
|
||||
|
@ -2086,7 +2032,7 @@ impl TaskwarriorTui {
|
|||
|
||||
let output = Command::new("task").arg(task_uuid.to_string()).arg(command).output();
|
||||
if output.is_err() {
|
||||
return Err(format!("Error running `task {}` for task `{}`.", command, task_uuid,));
|
||||
return Err(format!("Error running `task {}` for task `{}`.", command, task_uuid, ));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2215,7 +2161,7 @@ impl TaskwarriorTui {
|
|||
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();
|
||||
.unwrap();
|
||||
if let Some(caps) = re.captures(&data) {
|
||||
if let Ok(uuid) = Uuid::parse_str(&caps["task_uuid"]) {
|
||||
self.current_selection_uuid = Some(uuid);
|
||||
|
@ -4280,7 +4226,7 @@ mod tests {
|
|||
let position = TaskwarriorTui::get_position(&app.modify);
|
||||
f.set_cursor(
|
||||
std::cmp::min(
|
||||
rects[1].x + position as u16 + 1,
|
||||
rects[1].x + position as u16,
|
||||
rects[1].x + rects[1].width.saturating_sub(2),
|
||||
),
|
||||
rects[1].y + 1,
|
||||
|
@ -4337,7 +4283,7 @@ mod tests {
|
|||
let position = TaskwarriorTui::get_position(&app.modify);
|
||||
f.set_cursor(
|
||||
std::cmp::min(
|
||||
rects[1].x + position as u16 + 1,
|
||||
rects[1].x + position as u16,
|
||||
rects[1].x + rects[1].width.saturating_sub(2),
|
||||
),
|
||||
rects[1].y + 1,
|
||||
|
|
|
@ -36,7 +36,6 @@ pub struct ProjectsState {
|
|||
pub table_state: TableState,
|
||||
pub current_selection: usize,
|
||||
pub marked: HashSet<Project>,
|
||||
pub report_height: u16,
|
||||
pub columns: Vec<String>,
|
||||
pub rows: Vec<ProjectDetails>,
|
||||
pub data: String,
|
||||
|
@ -57,7 +56,6 @@ impl ProjectsState {
|
|||
table_state: TableState::default(),
|
||||
current_selection: 0,
|
||||
marked: HashSet::default(),
|
||||
report_height: 0,
|
||||
columns: vec![
|
||||
PROJECT_HEADER.to_string(),
|
||||
REMAINING_TASK_HEADER.to_string(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue