fix: Fix multiple line context bug 🐛

This commit is contained in:
Dheepak Krishnamurthy 2021-10-30 16:43:32 -06:00
parent 7a5393860e
commit 279b63874b
6 changed files with 232 additions and 166 deletions

View file

@ -2,7 +2,6 @@ use crate::calendar::Calendar;
use crate::completion::{get_start_word_under_cursor, CompletionList};
use crate::config;
use crate::config::Config;
use crate::context::Context;
use crate::event::Key;
use crate::event::{Event, Events};
use crate::help::Help;
@ -70,6 +69,7 @@ use regex::Regex;
use lazy_static::lazy_static;
use crate::app::Action::Report;
use crate::pane::context::{ContextDetails, ContextsState};
use crate::pane::project::ProjectsState;
use crate::pane::Pane;
use crossterm::style::style;
@ -170,7 +170,6 @@ pub struct TaskwarriorTui {
pub should_quit: bool,
pub dirty: bool,
pub task_table_state: TableState,
pub context_table_state: TableState,
pub current_context_filter: String,
pub current_context: String,
pub command: LineBuffer,
@ -192,18 +191,18 @@ pub struct TaskwarriorTui {
pub task_report_height: u16,
pub task_details_scroll: u16,
pub help_popup: Help,
pub contexts: Vec<Context>,
pub last_export: Option<SystemTime>,
pub keyconfig: KeyConfig,
pub terminal_width: u16,
pub terminal_height: u16,
pub filter_history_context: HistoryContext,
pub command_history_context: HistoryContext,
pub filter_history: HistoryContext,
pub command_history: HistoryContext,
pub history_status: Option<String>,
pub completion_list: CompletionList,
pub show_completion_pane: bool,
pub report: String,
pub projects: ProjectsState,
pub contexts: ContextsState,
}
impl TaskwarriorTui {
@ -238,7 +237,6 @@ impl TaskwarriorTui {
should_quit: false,
dirty: true,
task_table_state: TableState::default(),
context_table_state: TableState::default(),
tasks: vec![],
task_details: HashMap::new(),
marked: HashSet::new(),
@ -259,18 +257,18 @@ impl TaskwarriorTui {
task_report_table: TaskReportTable::new(&data, report)?,
calendar_year: Local::today().year(),
help_popup: Help::new(),
contexts: vec![],
last_export: None,
keyconfig: kc,
terminal_width: w,
terminal_height: h,
filter_history_context: HistoryContext::new("filter.history"),
command_history_context: HistoryContext::new("command.history"),
filter_history: HistoryContext::new("filter.history"),
command_history: HistoryContext::new("command.history"),
history_status: None,
completion_list: CompletionList::with_items(vec![]),
show_completion_pane: false,
report: report.to_string(),
projects: ProjectsState::new(),
contexts: ContextsState::new(),
};
for c in app.config.filter.chars() {
@ -281,9 +279,9 @@ impl TaskwarriorTui {
app.update(true)?;
app.filter_history_context.load()?;
app.filter_history_context.add(app.filter.as_str());
app.command_history_context.load()?;
app.filter_history.load()?;
app.filter_history.add(app.filter.as_str());
app.command_history.load()?;
app.task_background();
Ok(app)
}
@ -831,17 +829,17 @@ impl TaskwarriorTui {
let maximum_column_width = area.width;
let widths = self.calculate_widths(&contexts, &headers, maximum_column_width);
let selected = self.context_table_state.current_selection().unwrap_or_default();
let selected = self.contexts.table_state.current_selection().unwrap_or_default();
let header = headers.iter();
let mut rows = vec![];
let mut highlight_style = Style::default();
for (i, context) in contexts.iter().enumerate() {
let mut style = Style::default();
if &self.contexts[i].active == "yes" {
if &self.contexts.rows[i].active == "yes" {
style = self.config.uda_style_context_active;
}
rows.push(Row::StyledData(context.iter(), style));
if i == self.context_table_state.current_selection().unwrap_or_default() {
if i == self.contexts.table_state.current_selection().unwrap_or_default() {
highlight_style = style;
}
}
@ -874,7 +872,7 @@ impl TaskwarriorTui {
.highlight_symbol(&self.config.uda_selection_indicator)
.widths(&constraints);
f.render_stateful_widget(t, area, &mut self.context_table_state);
f.render_stateful_widget(t, area, &mut self.contexts.table_state);
}
fn draw_completion_pop_up(&mut self, f: &mut Frame<impl Backend>, rect: Rect, cursor_position: usize) {
@ -1221,11 +1219,12 @@ impl TaskwarriorTui {
pub fn get_all_contexts(&self) -> (Vec<Vec<String>>, Vec<String>) {
let contexts = self
.contexts
.rows
.iter()
.filter(|c| &c.typ == "read")
.map(|c| vec![c.name.clone(), c.description.clone(), c.active.clone()])
.filter(|c| &c.type_ == "read")
.map(|c| vec![c.name.clone(), c.definition.clone(), c.active.clone()])
.collect();
let headers = vec!["Name".to_string(), "Description".to_string(), "Active".to_string()];
let headers = vec!["Name".to_string(), "Definition".to_string(), "Active".to_string()];
(contexts, headers)
}
@ -1240,7 +1239,8 @@ impl TaskwarriorTui {
self.last_export = Some(std::time::SystemTime::now());
self.task_report_table.export_headers(None, &self.report)?;
self.export_tasks()?;
self.export_contexts()?;
self.projects.update_data()?;
self.contexts.update_data()?;
self.update_tags();
self.task_details.clear();
self.dirty = false;
@ -1248,7 +1248,6 @@ impl TaskwarriorTui {
}
self.cursor_fix();
self.update_task_table_state();
self.projects.update_data()?;
if self.task_report_show_info {
task::block_on(self.update_task_details())?;
}
@ -1278,8 +1277,8 @@ impl TaskwarriorTui {
}
pub fn save_history(&mut self) -> Result<()> {
self.filter_history_context.write()?;
self.command_history_context.write()?;
self.filter_history.write()?;
self.command_history.write()?;
Ok(())
}
@ -1376,7 +1375,7 @@ impl TaskwarriorTui {
}
pub fn context_next(&mut self) {
let i = match self.context_table_state.current_selection() {
let i = match self.contexts.table_state.current_selection() {
Some(i) => {
if i >= self.contexts.len() - 1 {
0
@ -1386,11 +1385,11 @@ impl TaskwarriorTui {
}
None => 0,
};
self.context_table_state.select(Some(i));
self.contexts.table_state.select(Some(i));
}
pub fn context_previous(&mut self) {
let i = match self.context_table_state.current_selection() {
let i = match self.contexts.table_state.current_selection() {
Some(i) => {
if i == 0 {
self.contexts.len() - 1
@ -1400,13 +1399,13 @@ impl TaskwarriorTui {
}
None => 0,
};
self.context_table_state.select(Some(i));
self.contexts.table_state.select(Some(i));
}
pub fn context_select(&mut self) -> Result<()> {
let i = self.context_table_state.current_selection().unwrap_or_default();
let i = self.contexts.table_state.current_selection().unwrap_or_default();
let mut command = Command::new("task");
command.arg("context").arg(&self.contexts[i].name);
command.arg("context").arg(&self.contexts.rows[i].name);
command.output()?;
Ok(())
}
@ -1530,58 +1529,6 @@ impl TaskwarriorTui {
}
}
pub fn export_contexts(&mut self) -> Result<()> {
let output = Command::new("task").arg("context").output()?;
let data = String::from_utf8_lossy(&output.stdout);
self.contexts = vec![];
for (i, line) in data.trim().split('\n').enumerate() {
if line.starts_with(" ") && line.trim().starts_with("write") {
continue;
}
let line = line.trim();
if line.is_empty() || line == "Use 'task context none' to unset the current context." {
continue;
}
if i == 0 || i == 1 {
continue;
}
let mut s = line.split_whitespace();
let name = s.next().unwrap_or_default();
let typ = s.next().unwrap_or_default();
let active = s.last().unwrap_or_default();
let definition = line.replacen(name, "", 1);
let definition = definition.replacen(typ, "", 1);
let definition = definition.strip_suffix(active).unwrap_or_default();
let context = Context::new(
name.to_string(),
definition.trim().to_string(),
active.to_string(),
typ.to_string(),
);
self.contexts.push(context);
}
if self.contexts.iter().any(|r| r.active != "no") {
self.contexts.insert(
0,
Context::new("none".to_string(), "".to_string(), "no".to_string(), "read".to_string()),
);
} else {
self.contexts.insert(
0,
Context::new(
"none".to_string(),
"".to_string(),
"yes".to_string(),
"read".to_string(),
),
);
}
Ok(())
}
fn get_task_files_max_mtime(&self) -> Result<SystemTime> {
let data_dir = shellexpand::tilde(&self.config.data_location).into_owned();
["backlog.data", "completed.data", "pending.data"]
@ -2502,8 +2449,8 @@ impl TaskwarriorTui {
}
} else if input == self.keyconfig.modify {
self.mode = Mode::Tasks(Action::Modify);
self.command_history_context.last();
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
self.command_history.last();
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
self.update_completion_list();
match self.task_table_state.mode() {
TableMode::SingleSelection => match self.task_current() {
@ -2550,25 +2497,25 @@ impl TaskwarriorTui {
self.mode = Mode::Tasks(Action::Subprocess);
} else if input == self.keyconfig.log {
self.mode = Mode::Tasks(Action::Log);
self.command_history_context.last();
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
self.command_history.last();
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
self.update_completion_list();
} else if input == self.keyconfig.add {
self.mode = Mode::Tasks(Action::Add);
self.command_history_context.last();
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
self.command_history.last();
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
self.update_completion_list();
} else if input == self.keyconfig.annotate {
self.mode = Mode::Tasks(Action::Annotate);
self.command_history_context.last();
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
self.command_history.last();
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
self.update_completion_list();
} else if input == self.keyconfig.help {
self.mode = Mode::Tasks(Action::HelpPopup);
} else if input == self.keyconfig.filter {
self.mode = Mode::Tasks(Action::Filter);
self.filter_history_context.last();
// self.history_status = Some(format!(" {} / {}", self.filter_history_context.history_index() + 1, self.filter_history_context.history_len()));
self.filter_history.last();
// self.history_status = Some(format!(" {} / {}", self.filter_history.history_index() + 1, self.filter_history.history_len()));
self.update_completion_list();
} else if input == Key::Char(':') {
self.mode = Mode::Tasks(Action::Jump);
@ -2716,7 +2663,7 @@ impl TaskwarriorTui {
match self.task_modify() {
Ok(_) => {
self.mode = Mode::Tasks(Action::Report);
self.command_history_context.add(self.modify.as_str());
self.command_history.add(self.modify.as_str());
self.modify.update("", 0);
self.update(true)?;
}
@ -2746,30 +2693,30 @@ impl TaskwarriorTui {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.previous();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.modify.as_str()[..self.modify.pos()], HistoryDirection::Reverse)
{
let p = self.modify.pos();
self.modify.update("", 0);
self.modify.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
Key::Down => {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.next();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.modify.as_str()[..self.modify.pos()], HistoryDirection::Forward)
{
let p = self.modify.pos();
self.modify.update("", 0);
self.modify.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
_ => {
self.command_history_context.last();
self.command_history.last();
handle_movement(&mut self.modify, input);
self.update_input_for_completion();
}
@ -2816,7 +2763,7 @@ impl TaskwarriorTui {
match self.task_log() {
Ok(_) => {
self.mode = Mode::Tasks(Action::Report);
self.command_history_context.add(self.command.as_str());
self.command_history.add(self.command.as_str());
self.command.update("", 0);
// self.history_status = None;
self.update(true)?;
@ -2847,30 +2794,30 @@ impl TaskwarriorTui {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.previous();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.command.as_str()[..self.command.pos()], HistoryDirection::Reverse)
{
let p = self.command.pos();
self.command.update("", 0);
self.command.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
Key::Down => {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.next();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.command.as_str()[..self.command.pos()], HistoryDirection::Forward)
{
let p = self.command.pos();
self.command.update("", 0);
self.command.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
_ => {
self.command_history_context.last();
self.command_history.last();
handle_movement(&mut self.command, input);
self.update_input_for_completion();
}
@ -2899,7 +2846,7 @@ impl TaskwarriorTui {
match self.task_annotate() {
Ok(_) => {
self.mode = Mode::Tasks(Action::Report);
self.command_history_context.add(self.command.as_str());
self.command_history.add(self.command.as_str());
self.command.update("", 0);
// self.history_status = None;
self.update(true)?;
@ -2929,31 +2876,31 @@ impl TaskwarriorTui {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.previous();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.command.as_str()[..self.command.pos()], HistoryDirection::Reverse)
{
let p = self.command.pos();
self.command.update("", 0);
self.command.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
Key::Down => {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.next();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.command.as_str()[..self.command.pos()], HistoryDirection::Forward)
{
let p = self.command.pos();
self.command.update("", 0);
self.command.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
_ => {
self.command_history_context.last();
self.command_history.last();
handle_movement(&mut self.command, input);
self.update_input_for_completion();
}
@ -3001,7 +2948,7 @@ impl TaskwarriorTui {
match self.task_add() {
Ok(_) => {
self.mode = Mode::Tasks(Action::Report);
self.command_history_context.add(self.command.as_str());
self.command_history.add(self.command.as_str());
self.command.update("", 0);
// self.history_status = None;
self.update(true)?;
@ -3031,13 +2978,13 @@ impl TaskwarriorTui {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.previous();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.command.as_str()[..self.command.pos()], HistoryDirection::Reverse)
{
let p = self.command.pos();
self.command.update("", 0);
self.command.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
@ -3045,17 +2992,17 @@ impl TaskwarriorTui {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.next();
} else if let Some(s) = self
.command_history_context
.command_history
.history_search(&self.command.as_str()[..self.command.pos()], HistoryDirection::Forward)
{
let p = self.command.pos();
self.command.update("", 0);
self.command.update(&s, std::cmp::min(s.len(), p));
// self.history_status = Some(format!(" {} / {}", self.command_history_context.history_index() + 1, self.command_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.command_history.history_index() + 1, self.command_history.history_len()));
}
}
_ => {
self.command_history_context.last();
self.command_history.last();
handle_movement(&mut self.command, input);
self.update_input_for_completion();
}
@ -3067,7 +3014,7 @@ impl TaskwarriorTui {
self.completion_list.unselect();
} else {
self.mode = Mode::Tasks(Action::Report);
self.filter_history_context.add(self.filter.as_str());
self.filter_history.add(self.filter.as_str());
// self.history_status = None;
self.update(true)?;
}
@ -3084,7 +3031,7 @@ impl TaskwarriorTui {
self.dirty = true;
} else {
self.mode = Mode::Tasks(Action::Report);
self.filter_history_context.add(self.filter.as_str());
self.filter_history.add(self.filter.as_str());
// self.history_status = None;
self.update(true)?;
}
@ -3093,13 +3040,13 @@ impl TaskwarriorTui {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.previous();
} else if let Some(s) = self
.filter_history_context
.filter_history
.history_search(&self.filter.as_str()[..self.filter.pos()], HistoryDirection::Reverse)
{
let p = self.filter.pos();
self.filter.update("", 0);
self.filter.update(&s, std::cmp::min(p, s.len()));
// self.history_status = Some(format!(" {} / {}", self.filter_history_context.history_index() + 1, self.filter_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.filter_history.history_index() + 1, self.filter_history.history_len()));
self.dirty = true;
}
}
@ -3107,13 +3054,13 @@ impl TaskwarriorTui {
if self.show_completion_pane && !self.completion_list.is_empty() {
self.completion_list.next();
} else if let Some(s) = self
.filter_history_context
.filter_history
.history_search(&self.filter.as_str()[..self.filter.pos()], HistoryDirection::Forward)
{
let p = self.filter.pos();
self.filter.update("", 0);
self.filter.update(&s, std::cmp::min(p, s.len()));
// self.history_status = Some(format!(" {} / {}", self.filter_history_context.history_index() + 1, self.filter_history_context.history_len()));
// self.history_status = Some(format!(" {} / {}", self.filter_history.history_index() + 1, self.filter_history.history_len()));
self.dirty = true;
}
}
@ -3603,10 +3550,10 @@ mod tests {
assert_eq!(app.tasks.len(), 26);
assert_eq!(app.current_context_filter, "");
assert_eq!(app.context_table_state.current_selection(), Some(0));
assert_eq!(app.contexts.table_state.current_selection(), Some(0));
app.context_next();
app.context_select().unwrap();
assert_eq!(app.context_table_state.current_selection(), Some(1));
assert_eq!(app.contexts.table_state.current_selection(), Some(1));
assert!(app.get_context().is_ok());
assert!(app.update(true).is_ok());
@ -3614,10 +3561,10 @@ mod tests {
assert_eq!(app.tasks.len(), 1);
assert_eq!(app.current_context_filter, "+finance -private");
assert_eq!(app.context_table_state.current_selection(), Some(1));
assert_eq!(app.contexts.table_state.current_selection(), Some(1));
app.context_previous();
app.context_select().unwrap();
assert_eq!(app.context_table_state.current_selection(), Some(0));
assert_eq!(app.contexts.table_state.current_selection(), Some(0));
assert!(app.get_context().is_ok());
assert!(app.update(true).is_ok());

View file

@ -1,28 +0,0 @@
use std::cmp;
use tui::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Modifier, Style},
text::{Span, Spans, Text},
widgets::{Block, BorderType, Borders, Clear, Paragraph, StatefulWidget, Widget},
};
#[derive(Debug, Clone, Default)]
pub struct Context {
pub name: String,
pub description: String,
pub active: String,
pub typ: String,
}
impl Context {
pub fn new(name: String, description: String, active: String, typ: String) -> Self {
Self {
name,
description,
active,
typ,
}
}
}

View file

@ -32,7 +32,6 @@ mod calendar;
mod cli;
mod completion;
mod config;
mod context;
mod event;
mod help;
mod history;

144
src/pane/context.rs Normal file
View file

@ -0,0 +1,144 @@
use anyhow::Context as AnyhowContext;
use anyhow::{anyhow, Result};
use std::fmt;
const NAME: &str = "Name";
const TYPE: &str = "Remaining";
const DEFINITION: &str = "Avg age";
const ACTIVE: &str = "Complete";
use chrono::{Datelike, Duration, Local, Month, NaiveDate, NaiveDateTime, TimeZone};
use tui::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Color, Modifier, Style},
symbols,
text::{Span, Spans, Text},
widgets::{Block, BorderType, Borders, Clear, Paragraph, StatefulWidget, Widget},
};
use crate::app::{Action, Mode, TaskwarriorTui};
use crate::event::Key;
use crate::pane::Pane;
use crate::table::TableState;
use itertools::Itertools;
use std::cmp;
use std::cmp::min;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::process::{Command, Output};
use uuid::Uuid;
#[derive(Debug, Clone, Default)]
pub struct ContextDetails {
pub name: String,
pub definition: String,
pub active: String,
pub type_: String,
}
impl ContextDetails {
pub fn new(name: String, definition: String, active: String, type_: String) -> Self {
Self {
name,
definition,
active,
type_,
}
}
}
pub struct ContextsState {
pub table_state: TableState,
pub report_height: u16,
pub columns: Vec<String>,
pub rows: Vec<ContextDetails>,
}
impl ContextsState {
pub(crate) fn new() -> Self {
Self {
table_state: TableState::default(),
report_height: 0,
columns: vec![
NAME.to_string(),
TYPE.to_string(),
DEFINITION.to_string(),
ACTIVE.to_string(),
],
rows: vec![],
}
}
pub fn simplified_view(&mut self) -> (Vec<Vec<String>>, Vec<String>) {
let rows = self
.rows
.iter()
.map(|c| vec![c.name.clone(), c.type_.clone(), c.definition.clone(), c.active.clone()])
.collect();
let headers = self.columns.clone();
(rows, headers)
}
pub fn len(&self) -> usize {
self.rows.len()
}
pub fn update_data(&mut self) -> Result<()> {
let output = Command::new("task").arg("context").output()?;
let data = String::from_utf8_lossy(&output.stdout);
self.rows = vec![];
for (i, line) in data.trim().split('\n').enumerate() {
if line.starts_with(" ") && line.trim().starts_with("write") {
continue;
}
if line.starts_with(" ") && !(line.trim().ends_with("yes") || line.trim().ends_with("no")) {
let definition = line.trim();
if let Some(c) = self.rows.last_mut() {
(*c).definition = format!("{} {}", c.definition, definition);
}
continue;
}
let line = line.trim();
if line.is_empty() || line == "Use 'task context none' to unset the current context." {
continue;
}
if i == 0 || i == 1 {
continue;
}
let mut s = line.split_whitespace();
let name = s.next().unwrap_or_default();
let typ = s.next().unwrap_or_default();
let active = s.last().unwrap_or_default();
let definition = line.replacen(name, "", 1);
let definition = definition.replacen(typ, "", 1);
let definition = definition.strip_suffix(active).unwrap_or_default();
let context = ContextDetails::new(
name.to_string(),
definition.trim().to_string(),
active.to_string(),
typ.to_string(),
);
self.rows.push(context);
}
if self.rows.iter().any(|r| r.active != "no") {
self.rows.insert(
0,
ContextDetails::new("none".to_string(), "".to_string(), "no".to_string(), "read".to_string()),
);
} else {
self.rows.insert(
0,
ContextDetails::new(
"none".to_string(),
"".to_string(),
"yes".to_string(),
"read".to_string(),
),
);
}
Ok(())
}
}

View file

@ -5,6 +5,7 @@ use crate::event::Key;
use clap::App;
use std::ops::Index;
pub mod context;
pub mod project;
pub trait Pane {

View file

@ -1,6 +1,3 @@
// Based on https://gist.github.com/diwic/5c20a283ca3a03752e1a27b0f3ebfa30
// See https://old.reddit.com/r/rust/comments/4xneq5/the_calendar_example_challenge_ii_why_eddyb_all/
use anyhow::Context as AnyhowContext;
use anyhow::{anyhow, Result};
use std::fmt;
@ -66,6 +63,7 @@ impl ProjectsState {
rows: vec![],
}
}
fn pattern_by_marked(app: &mut TaskwarriorTui) -> String {
let mut project_pattern = String::new();
if !app.projects.marked.is_empty() {
@ -74,16 +72,17 @@ impl ProjectsState {
if input.as_str() == "(none)" {
input = " ".to_string();
}
if idx > 0 {
project_pattern = format!("{} or project:{}", project_pattern, input);
} else {
if idx == 0 {
project_pattern = format!("\'(project:{}", input);
} else {
project_pattern = format!("{} or project:{}", project_pattern, input);
}
}
project_pattern = format!("{})\'", project_pattern);
}
project_pattern
}
pub fn toggle_mark(&mut self) {
if !self.list.is_empty() {
let selected = self.current_selection;
@ -92,6 +91,7 @@ impl ProjectsState {
}
}
}
pub fn simplified_view(&mut self) -> (Vec<Vec<String>>, Vec<String>) {
let rows = self
.rows
@ -165,15 +165,18 @@ impl ProjectsState {
self.list = self.rows.iter().map(|x| x.name.clone()).collect_vec();
Ok(())
}
fn update_table_state(&mut self) {
self.table_state.select(Some(self.current_selection));
if self.marked.is_empty() {
self.table_state.single_selection();
}
self.table_state.clear();
for project in &self.marked {
let index = self.list.iter().position(|x| x == project);
self.table_state.mark(index);
} else {
self.table_state.multiple_selection();
self.table_state.clear();
for project in &self.marked {
let index = self.list.iter().position(|x| x == project);
self.table_state.mark(index);
}
}
}
}
@ -218,7 +221,7 @@ fn update_task_filter_by_selection(app: &mut TaskwarriorTui) -> Result<()> {
app.projects.toggle_mark();
let new_project_pattern = ProjectsState::pattern_by_marked(app);
let current_filter = app.filter.as_str();
app.filter_history_context.add(current_filter);
app.filter_history.add(current_filter);
let mut filter = current_filter.replace(&last_project_pattern, "");
filter = format!("{}{}", filter, new_project_pattern);