mirror of
https://github.com/kdheepak/taskwarrior-tui.git
synced 2025-08-25 17:57:19 +02:00
Merge pull request #171 from kdheepak/speed-up-start-up
This commit is contained in:
commit
085b22854c
6 changed files with 280 additions and 240 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1384,6 +1384,7 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"futures-timer",
|
"futures-timer",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
|
|
39
Cargo.toml
39
Cargo.toml
|
@ -18,29 +18,30 @@ default = ["crossterm-backend"]
|
||||||
crossterm-backend = ["tui/crossterm", "crossterm"]
|
crossterm-backend = ["tui/crossterm", "crossterm"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1"
|
|
||||||
itertools = "0.9"
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
|
||||||
serde_json = "1"
|
|
||||||
clap = "2.33"
|
|
||||||
cassowary = "0.3.0"
|
|
||||||
task-hookrs = { git = "https://github.com/matthiasbeyer/task-hookrs" }
|
|
||||||
rand = "0.7"
|
|
||||||
shlex = "0.1"
|
|
||||||
chrono = "0.4"
|
|
||||||
unicode-width = "0.1"
|
|
||||||
unicode-segmentation = "1.6"
|
|
||||||
tui = { version = "0.12", optional = true, default-features = false }
|
|
||||||
crossterm = { version = "0.17", optional = true, default-features = false, features = ["event-stream"] }
|
|
||||||
rustyline = "8"
|
|
||||||
uuid = { version = "0.8.1", features = ["serde", "v4"] }
|
|
||||||
better-panic = "0.2.0"
|
|
||||||
shellexpand = "2.1"
|
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
async-std = { version = "1", features = ["attributes", "unstable"] }
|
async-std = { version = "1", features = ["attributes", "unstable"] }
|
||||||
|
better-panic = "0.2.0"
|
||||||
|
cassowary = "0.3.0"
|
||||||
|
chrono = "0.4"
|
||||||
|
clap = "2.33"
|
||||||
|
crossterm = { version = "0.17", optional = true, default-features = false, features = ["event-stream"] }
|
||||||
|
dirs = "2.0.2"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
futures-timer = "3.0"
|
futures-timer = "3.0"
|
||||||
dirs = "2.0.2"
|
itertools = "0.9"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
rand = "0.7"
|
||||||
|
regex = "1"
|
||||||
|
rustyline = "8"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
|
shellexpand = "2.1"
|
||||||
|
shlex = "0.1"
|
||||||
|
task-hookrs = { git = "https://github.com/matthiasbeyer/task-hookrs" }
|
||||||
|
tui = { version = "0.12", optional = true, default-features = false }
|
||||||
|
unicode-segmentation = "1.6"
|
||||||
|
unicode-width = "0.1"
|
||||||
|
uuid = { version = "0.8.1", features = ["serde", "v4"] }
|
||||||
|
|
||||||
[package.metadata.rpm]
|
[package.metadata.rpm]
|
||||||
package = "taskwarrior-tui"
|
package = "taskwarrior-tui"
|
||||||
|
|
51
src/app.rs
51
src/app.rs
|
@ -32,14 +32,15 @@ use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
use chrono::{Datelike, Local, NaiveDate, NaiveDateTime, TimeZone, Timelike};
|
use chrono::{Datelike, Local, NaiveDate, NaiveDateTime, TimeZone, Timelike};
|
||||||
|
|
||||||
|
use anyhow::Context as AnyhowContext;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use async_std::prelude::*;
|
use async_std::prelude::*;
|
||||||
use async_std::stream::StreamExt;
|
use async_std::stream::StreamExt;
|
||||||
use async_std::task;
|
use async_std::task;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use futures::join;
|
|
||||||
use futures::stream::FuturesOrdered;
|
use futures::stream::FuturesOrdered;
|
||||||
|
use futures::{join, try_join};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
@ -66,8 +67,16 @@ use tui::{backend::CrosstermBackend, Terminal};
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
const MAX_LINE: usize = 4096;
|
const MAX_LINE: usize = 4096;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref START_TIME: Instant = Instant::now();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cmp(t1: &Task, t2: &Task) -> Ordering {
|
pub fn cmp(t1: &Task, t2: &Task) -> Ordering {
|
||||||
let urgency1 = match t1.urgency() {
|
let urgency1 = match t1.urgency() {
|
||||||
Some(f) => *f,
|
Some(f) => *f,
|
||||||
|
@ -189,10 +198,31 @@ pub struct TaskwarriorTuiApp {
|
||||||
|
|
||||||
impl TaskwarriorTuiApp {
|
impl TaskwarriorTuiApp {
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Result<Self> {
|
||||||
let c = Config::default()?;
|
let output = std::process::Command::new("task")
|
||||||
let mut kc = KeyConfig::default();
|
.arg("rc.color=off")
|
||||||
kc.update()?;
|
.arg("show")
|
||||||
|
.output()
|
||||||
|
.context("Unable to run `task show`.")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let output = Command::new("task")
|
||||||
|
.arg("diagnostics")
|
||||||
|
.output()
|
||||||
|
.context("Unable to run `task diagnostics`.")
|
||||||
|
.unwrap();
|
||||||
|
panic!(
|
||||||
|
"Unable to run `task show`.\n{}\n{}\nPlease check your configuration or open a issue on github.",
|
||||||
|
String::from_utf8_lossy(&output.stdout),
|
||||||
|
String::from_utf8_lossy(&output.stderr),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let (c, kc) = task::block_on(async { try_join!(Config::new(&data), KeyConfig::new(&data)) })?;
|
||||||
|
|
||||||
let (w, h) = crossterm::terminal::size()?;
|
let (w, h) = crossterm::terminal::size()?;
|
||||||
|
|
||||||
let mut app = Self {
|
let mut app = Self {
|
||||||
should_quit: false,
|
should_quit: false,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
|
@ -213,7 +243,7 @@ impl TaskwarriorTuiApp {
|
||||||
task_details_scroll: 0,
|
task_details_scroll: 0,
|
||||||
task_report_show_info: c.uda_task_report_show_info,
|
task_report_show_info: c.uda_task_report_show_info,
|
||||||
config: c,
|
config: c,
|
||||||
task_report_table: TaskReportTable::new()?,
|
task_report_table: TaskReportTable::new(&data)?,
|
||||||
calendar_year: Local::today().year(),
|
calendar_year: Local::today().year(),
|
||||||
help_popup: Help::new(),
|
help_popup: Help::new(),
|
||||||
contexts: vec![],
|
contexts: vec![],
|
||||||
|
@ -224,6 +254,7 @@ impl TaskwarriorTuiApp {
|
||||||
filter_history_context: HistoryContext::new("filter.history"),
|
filter_history_context: HistoryContext::new("filter.history"),
|
||||||
command_history_context: HistoryContext::new("command.history"),
|
command_history_context: HistoryContext::new("command.history"),
|
||||||
};
|
};
|
||||||
|
|
||||||
for c in app.config.filter.chars() {
|
for c in app.config.filter.chars() {
|
||||||
app.filter.insert(c, 1);
|
app.filter.insert(c, 1);
|
||||||
}
|
}
|
||||||
|
@ -874,7 +905,7 @@ impl TaskwarriorTuiApp {
|
||||||
pub fn update(&mut self, force: bool) -> Result<()> {
|
pub fn update(&mut self, force: bool) -> Result<()> {
|
||||||
if force || self.dirty || self.tasks_changed_since(self.last_export)? {
|
if force || self.dirty || self.tasks_changed_since(self.last_export)? {
|
||||||
self.last_export = Some(std::time::SystemTime::now());
|
self.last_export = Some(std::time::SystemTime::now());
|
||||||
self.task_report_table.export_headers()?;
|
self.task_report_table.export_headers(None)?;
|
||||||
let _ = self.export_tasks();
|
let _ = self.export_tasks();
|
||||||
self.export_contexts()?;
|
self.export_contexts()?;
|
||||||
self.update_tags();
|
self.update_tags();
|
||||||
|
@ -2323,6 +2354,14 @@ mod tests {
|
||||||
std::fs::remove_dir_all(cd).unwrap();
|
std::fs::remove_dir_all(cd).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_taskwarrior_timing() {
|
||||||
|
let app = TaskwarriorTuiApp::new();
|
||||||
|
if app.is_err() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_taskwarrior_tui() {
|
fn test_taskwarrior_tui() {
|
||||||
let app = TaskwarriorTuiApp::new();
|
let app = TaskwarriorTuiApp::new();
|
||||||
|
|
213
src/config.rs
213
src/config.rs
|
@ -1,9 +1,9 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use async_std::process::Command;
|
||||||
use async_std::task;
|
use async_std::task;
|
||||||
use futures::join;
|
use futures::join;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::process::Command;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
use tui::style::{Color, Modifier, Style};
|
use tui::style::{Color, Modifier, Style};
|
||||||
|
|
||||||
|
@ -64,34 +64,34 @@ pub struct Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn default() -> Result<Self> {
|
pub async fn new(data: &str) -> Result<Self> {
|
||||||
let bool_collection = Self::get_bool_collection();
|
let bool_collection = Self::get_bool_collection();
|
||||||
|
|
||||||
let enabled = true;
|
let enabled = true;
|
||||||
let obfuscate = bool_collection.get("obfuscate").cloned().unwrap_or(false);
|
let obfuscate = bool_collection.get("obfuscate").cloned().unwrap_or(false);
|
||||||
let print_empty_columns = bool_collection.get("print_empty_columns").cloned().unwrap_or(false);
|
let print_empty_columns = bool_collection.get("print_empty_columns").cloned().unwrap_or(false);
|
||||||
|
|
||||||
let color = Self::get_color_collection();
|
let color = Self::get_color_collection(data);
|
||||||
let filter = Self::get_filter();
|
let filter = Self::get_filter(data);
|
||||||
let data_location = Self::get_data_location();
|
let data_location = Self::get_data_location(data);
|
||||||
let due = Self::get_due();
|
let due = Self::get_due(data);
|
||||||
let rule_precedence_color = Self::get_rule_precedence_color();
|
let rule_precedence_color = Self::get_rule_precedence_color(data);
|
||||||
let uda_tick_rate = Self::get_uda_tick_rate();
|
let uda_tick_rate = Self::get_uda_tick_rate(data);
|
||||||
let uda_prefill_task_metadata = Self::get_uda_prefill_task_metadata();
|
let uda_prefill_task_metadata = Self::get_uda_prefill_task_metadata(data);
|
||||||
let uda_task_detail_prefetch = Self::get_uda_task_detail_prefetch();
|
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();
|
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();
|
let uda_task_report_looping = Self::get_uda_task_report_looping(data);
|
||||||
let uda_selection_indicator = Self::get_uda_selection_indicator();
|
let uda_selection_indicator = Self::get_uda_selection_indicator(data);
|
||||||
let uda_mark_indicator = Self::get_uda_mark_indicator();
|
let uda_mark_indicator = Self::get_uda_mark_indicator(data);
|
||||||
let uda_unmark_indicator = Self::get_uda_unmark_indicator();
|
let uda_unmark_indicator = Self::get_uda_unmark_indicator(data);
|
||||||
let uda_selection_bold = Self::get_uda_selection_bold();
|
let uda_selection_bold = Self::get_uda_selection_bold(data);
|
||||||
let uda_selection_italic = Self::get_uda_selection_italic();
|
let uda_selection_italic = Self::get_uda_selection_italic(data);
|
||||||
let uda_selection_dim = Self::get_uda_selection_dim();
|
let uda_selection_dim = Self::get_uda_selection_dim(data);
|
||||||
let uda_selection_blink = Self::get_uda_selection_blink();
|
let uda_selection_blink = Self::get_uda_selection_blink(data);
|
||||||
let uda_calendar_months_per_row = Self::get_uda_months_per_row();
|
let uda_calendar_months_per_row = Self::get_uda_months_per_row(data);
|
||||||
let uda_style_calendar_title = Self::get_uda_style("calendar.title");
|
let uda_style_calendar_title = Self::get_uda_style("calendar.title", data);
|
||||||
let uda_style_context_active = Self::get_uda_style("context.active");
|
let uda_style_context_active = Self::get_uda_style("context.active", data);
|
||||||
let uda_shortcuts = Self::get_uda_shortcuts();
|
let uda_shortcuts = Self::get_uda_shortcuts(data);
|
||||||
|
|
||||||
let (
|
let (
|
||||||
color,
|
color,
|
||||||
|
@ -115,31 +115,29 @@ impl Config {
|
||||||
uda_style_calendar_title,
|
uda_style_calendar_title,
|
||||||
uda_style_context_active,
|
uda_style_context_active,
|
||||||
uda_shortcuts,
|
uda_shortcuts,
|
||||||
) = task::block_on(async {
|
) = join!(
|
||||||
join!(
|
color,
|
||||||
color,
|
filter,
|
||||||
filter,
|
data_location,
|
||||||
data_location,
|
due,
|
||||||
due,
|
rule_precedence_color,
|
||||||
rule_precedence_color,
|
uda_tick_rate,
|
||||||
uda_tick_rate,
|
uda_prefill_task_metadata,
|
||||||
uda_prefill_task_metadata,
|
uda_task_detail_prefetch,
|
||||||
uda_task_detail_prefetch,
|
uda_task_report_show_info,
|
||||||
uda_task_report_show_info,
|
uda_task_report_looping,
|
||||||
uda_task_report_looping,
|
uda_selection_indicator,
|
||||||
uda_selection_indicator,
|
uda_mark_indicator,
|
||||||
uda_mark_indicator,
|
uda_unmark_indicator,
|
||||||
uda_unmark_indicator,
|
uda_selection_bold,
|
||||||
uda_selection_bold,
|
uda_selection_italic,
|
||||||
uda_selection_italic,
|
uda_selection_dim,
|
||||||
uda_selection_dim,
|
uda_selection_blink,
|
||||||
uda_selection_blink,
|
uda_calendar_months_per_row,
|
||||||
uda_calendar_months_per_row,
|
uda_style_calendar_title,
|
||||||
uda_style_calendar_title,
|
uda_style_context_active,
|
||||||
uda_style_context_active,
|
uda_shortcuts,
|
||||||
uda_shortcuts,
|
);
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let color = color?;
|
let color = color?;
|
||||||
let uda_style_calendar_title = uda_style_calendar_title.unwrap_or_default();
|
let uda_style_calendar_title = uda_style_calendar_title.unwrap_or_default();
|
||||||
|
@ -177,31 +175,24 @@ impl Config {
|
||||||
HashMap::new()
|
HashMap::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_shortcuts() -> Vec<String> {
|
async fn get_uda_shortcuts(data: &str) -> Vec<String> {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
for s in 0..=9 {
|
for s in 0..=9 {
|
||||||
let c = format!("uda.taskwarrior-tui.shortcuts.{}", s);
|
let c = format!("uda.taskwarrior-tui.shortcuts.{}", s);
|
||||||
let s = Self::get_config(&c).await.unwrap_or_default();
|
let s = Self::get_config(&c, data).await.unwrap_or_default();
|
||||||
v.push(s);
|
v.push(s);
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_style(config: &str) -> Option<Style> {
|
async fn get_uda_style(config: &str, data: &str) -> Option<Style> {
|
||||||
let c = format!("uda.taskwarrior-tui.style.{}", config);
|
let c = format!("uda.taskwarrior-tui.style.{}", config);
|
||||||
let s = Self::get_config(&c).await?;
|
let s = Self::get_config(&c, data).await?;
|
||||||
Some(Self::get_tcolor(&s))
|
Some(Self::get_tcolor(&s))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_color_collection() -> Result<HashMap<String, Style>> {
|
async fn get_color_collection(data: &str) -> Result<HashMap<String, Style>> {
|
||||||
let mut color_collection = HashMap::new();
|
let mut color_collection = HashMap::new();
|
||||||
let output = async_std::process::Command::new("task")
|
|
||||||
.arg("rc.color=off")
|
|
||||||
.arg("show")
|
|
||||||
.output()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let data = String::from_utf8_lossy(&output.stdout);
|
|
||||||
for line in data.split('\n') {
|
for line in data.split('\n') {
|
||||||
if line.starts_with("color.") {
|
if line.starts_with("color.") {
|
||||||
let mut i = line.split(' ');
|
let mut i = line.split(' ');
|
||||||
|
@ -365,32 +356,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_config(config: &str) -> Option<String> {
|
async fn get_config(config: &str, data: &str) -> Option<String> {
|
||||||
let output = async_std::process::Command::new("task")
|
|
||||||
.arg("rc.color=off")
|
|
||||||
.arg("show")
|
|
||||||
.arg(config)
|
|
||||||
.output()
|
|
||||||
.await
|
|
||||||
.with_context(|| format!("Unable to run `task show {}`.", config))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
let output = Command::new("task")
|
|
||||||
.arg("diagnostics")
|
|
||||||
.output()
|
|
||||||
.context("Unable to run `task diagnostics`.")
|
|
||||||
.unwrap();
|
|
||||||
panic!(
|
|
||||||
"Unable to run `task show {}`.\n{}\n{}\nPlease check your configuration or open a issue on github.",
|
|
||||||
config,
|
|
||||||
String::from_utf8_lossy(&output.stdout),
|
|
||||||
String::from_utf8_lossy(&output.stderr),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = String::from_utf8_lossy(&output.stdout);
|
|
||||||
|
|
||||||
for line in data.split('\n') {
|
for line in data.split('\n') {
|
||||||
if line.starts_with(config) {
|
if line.starts_with(config) {
|
||||||
return Some(line.trim_start_matches(config).trim_start().trim_end().to_string());
|
return Some(line.trim_start_matches(config).trim_start().trim_end().to_string());
|
||||||
|
@ -403,135 +369,135 @@ impl Config {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_due() -> usize {
|
async fn get_due(data: &str) -> usize {
|
||||||
Self::get_config("due")
|
Self::get_config("due", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.parse::<usize>()
|
.parse::<usize>()
|
||||||
.unwrap_or(7)
|
.unwrap_or(7)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_rule_precedence_color() -> Vec<String> {
|
async fn get_rule_precedence_color(data: &str) -> Vec<String> {
|
||||||
let data = Self::get_config("rule.precedence.color")
|
let data = Self::get_config("rule.precedence.color", data)
|
||||||
.await
|
.await
|
||||||
.context("Unable to parse `task show rule.precedence.color`.")
|
.context("Unable to parse `task show rule.precedence.color`.")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
data.split(',').map(|s| s.to_string()).collect::<Vec<_>>()
|
data.split(',').map(|s| s.to_string()).collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_filter() -> String {
|
async fn get_filter(data: &str) -> String {
|
||||||
let filter = Self::get_config("report.next.filter")
|
let filter = Self::get_config("report.next.filter", data)
|
||||||
.await
|
.await
|
||||||
.context("Unable to parse `task show report.next.filter`.")
|
.context("Unable to parse `task show report.next.filter`.")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
format!("{} ", filter)
|
format!("{} ", filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_data_location() -> String {
|
async fn get_data_location(data: &str) -> String {
|
||||||
Self::get_config("data.location")
|
Self::get_config("data.location", data)
|
||||||
.await
|
.await
|
||||||
.context("Unable to parse `task show data.location`.")
|
.context("Unable to parse `task show data.location`.")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_prefill_task_metadata() -> bool {
|
async fn get_uda_prefill_task_metadata(data: &str) -> bool {
|
||||||
Self::get_config("uda.taskwarrior-tui.task-report.pre-fill-task-meta-data")
|
Self::get_config("uda.taskwarrior-tui.task-report.pre-fill-task-meta-data", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.get_bool()
|
.get_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_tick_rate() -> u64 {
|
async fn get_uda_tick_rate(data: &str) -> u64 {
|
||||||
Self::get_config("uda.taskwarrior-tui.tick-rate")
|
Self::get_config("uda.taskwarrior-tui.tick-rate", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.parse::<u64>()
|
.parse::<u64>()
|
||||||
.unwrap_or(250)
|
.unwrap_or(250)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_task_detail_prefetch() -> usize {
|
async fn get_uda_task_detail_prefetch(data: &str) -> usize {
|
||||||
Self::get_config("uda.taskwarrior-tui.task-report.task-detail-prefetch")
|
Self::get_config("uda.taskwarrior-tui.task-report.task-detail-prefetch", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.parse::<usize>()
|
.parse::<usize>()
|
||||||
.unwrap_or(10)
|
.unwrap_or(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_task_report_show_info() -> bool {
|
async fn get_uda_task_report_show_info(data: &str) -> bool {
|
||||||
Self::get_config("uda.taskwarrior-tui.task-report.show-info")
|
Self::get_config("uda.taskwarrior-tui.task-report.show-info", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.get_bool()
|
.get_bool()
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_task_report_looping() -> bool {
|
async fn get_uda_task_report_looping(data: &str) -> bool {
|
||||||
Self::get_config("uda.taskwarrior-tui.task-report.looping")
|
Self::get_config("uda.taskwarrior-tui.task-report.looping", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.get_bool()
|
.get_bool()
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_selection_indicator() -> String {
|
async fn get_uda_selection_indicator(data: &str) -> String {
|
||||||
let indicator = Self::get_config("uda.taskwarrior-tui.selection.indicator").await;
|
let indicator = Self::get_config("uda.taskwarrior-tui.selection.indicator", data).await;
|
||||||
match indicator {
|
match indicator {
|
||||||
None => "• ".to_string(),
|
None => "• ".to_string(),
|
||||||
Some(indicator) => format!("{} ", indicator),
|
Some(indicator) => format!("{} ", indicator),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_mark_indicator() -> String {
|
async fn get_uda_mark_indicator(data: &str) -> String {
|
||||||
let indicator = Self::get_config("uda.taskwarrior-tui.mark.indicator").await;
|
let indicator = Self::get_config("uda.taskwarrior-tui.mark.indicator", data).await;
|
||||||
match indicator {
|
match indicator {
|
||||||
None => "✔ ".to_string(),
|
None => "✔ ".to_string(),
|
||||||
Some(indicator) => format!("{} ", indicator),
|
Some(indicator) => format!("{} ", indicator),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_unmark_indicator() -> String {
|
async fn get_uda_unmark_indicator(data: &str) -> String {
|
||||||
let indicator = Self::get_config("uda.taskwarrior-tui.unmark.indicator").await;
|
let indicator = Self::get_config("uda.taskwarrior-tui.unmark.indicator", data).await;
|
||||||
match indicator {
|
match indicator {
|
||||||
None => " ".to_string(),
|
None => " ".to_string(),
|
||||||
Some(indicator) => format!("{} ", indicator),
|
Some(indicator) => format!("{} ", indicator),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_selection_bold() -> bool {
|
async fn get_uda_selection_bold(data: &str) -> bool {
|
||||||
Self::get_config("uda.taskwarrior-tui.selection.bold")
|
Self::get_config("uda.taskwarrior-tui.selection.bold", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.get_bool()
|
.get_bool()
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_selection_italic() -> bool {
|
async fn get_uda_selection_italic(data: &str) -> bool {
|
||||||
Self::get_config("uda.taskwarrior-tui.selection.italic")
|
Self::get_config("uda.taskwarrior-tui.selection.italic", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.get_bool()
|
.get_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_selection_dim() -> bool {
|
async fn get_uda_selection_dim(data: &str) -> bool {
|
||||||
Self::get_config("uda.taskwarrior-tui.selection.dim")
|
Self::get_config("uda.taskwarrior-tui.selection.dim", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.get_bool()
|
.get_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_selection_blink() -> bool {
|
async fn get_uda_selection_blink(data: &str) -> bool {
|
||||||
Self::get_config("uda.taskwarrior-tui.selection.blink")
|
Self::get_config("uda.taskwarrior-tui.selection.blink", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.get_bool()
|
.get_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_uda_months_per_row() -> usize {
|
async fn get_uda_months_per_row(data: &str) -> usize {
|
||||||
Self::get_config("uda.taskwarrior-tui.calendar.months-per-row")
|
Self::get_config("uda.taskwarrior-tui.calendar.months-per-row", data)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.parse::<usize>()
|
.parse::<usize>()
|
||||||
|
@ -542,13 +508,6 @@ impl Config {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
|
||||||
fn test_uda_configuration() {
|
|
||||||
assert_eq!(
|
|
||||||
None,
|
|
||||||
task::block_on(Config::get_config("uda.taskwarrior-tui.unmark.indicator"))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_colors() {
|
fn test_colors() {
|
||||||
|
|
201
src/keyconfig.rs
201
src/keyconfig.rs
|
@ -1,11 +1,12 @@
|
||||||
use crate::util::Key;
|
use crate::util::Key;
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Result};
|
||||||
use anyhow::Result;
|
use async_std::process::Command;
|
||||||
|
use async_std::task;
|
||||||
|
use futures::join;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct KeyConfig {
|
pub struct KeyConfig {
|
||||||
|
@ -91,76 +92,119 @@ impl Default for KeyConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyConfig {
|
impl KeyConfig {
|
||||||
pub fn update(&mut self) -> Result<()> {
|
pub async fn new(data: &str) -> Result<Self> {
|
||||||
self.quit = self
|
let mut kc = Self::default();
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.quit")
|
kc.update(data).await?;
|
||||||
.unwrap_or(self.quit);
|
Ok(kc)
|
||||||
self.refresh = self
|
}
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.refresh")
|
|
||||||
.unwrap_or(self.refresh);
|
pub async fn update(&mut self, data: &str) -> Result<()> {
|
||||||
self.go_to_bottom = self
|
let quit = self.get_config("uda.taskwarrior-tui.keyconfig.quit", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.go-to-bottom")
|
let refresh = self.get_config("uda.taskwarrior-tui.keyconfig.refresh", data);
|
||||||
.unwrap_or(self.go_to_bottom);
|
let go_to_bottom = self.get_config("uda.taskwarrior-tui.keyconfig.go-to-bottom", data);
|
||||||
self.go_to_top = self
|
let go_to_top = self.get_config("uda.taskwarrior-tui.keyconfig.go-to-top", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.go-to-top")
|
let down = self.get_config("uda.taskwarrior-tui.keyconfig.down", data);
|
||||||
.unwrap_or(self.go_to_top);
|
let up = self.get_config("uda.taskwarrior-tui.keyconfig.up", data);
|
||||||
self.down = self
|
let page_down = self.get_config("uda.taskwarrior-tui.keyconfig.page-down", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.down")
|
let page_up = self.get_config("uda.taskwarrior-tui.keyconfig.page-up", data);
|
||||||
.unwrap_or(self.down);
|
let delete = self.get_config("uda.taskwarrior-tui.keyconfig.delete", data);
|
||||||
self.up = self.get_config("uda.taskwarrior-tui.keyconfig.up").unwrap_or(self.up);
|
let done = self.get_config("uda.taskwarrior-tui.keyconfig.done", data);
|
||||||
self.page_down = self
|
let start_stop = self.get_config("uda.taskwarrior-tui.keyconfig.start-stop", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.page-down")
|
let select = self.get_config("uda.taskwarrior-tui.keyconfig.select", data);
|
||||||
.unwrap_or(self.page_down);
|
let select_all = self.get_config("uda.taskwarrior-tui.keyconfig.select-all", data);
|
||||||
self.page_up = self
|
let undo = self.get_config("uda.taskwarrior-tui.keyconfig.undo", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.page-up")
|
let edit = self.get_config("uda.taskwarrior-tui.keyconfig.edit", data);
|
||||||
.unwrap_or(self.page_up);
|
let modify = self.get_config("uda.taskwarrior-tui.keyconfig.modify", data);
|
||||||
self.delete = self
|
let shell = self.get_config("uda.taskwarrior-tui.keyconfig.shell", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.delete")
|
let log = self.get_config("uda.taskwarrior-tui.keyconfig.log", data);
|
||||||
.unwrap_or(self.delete);
|
let add = self.get_config("uda.taskwarrior-tui.keyconfig.add", data);
|
||||||
self.done = self
|
let annotate = self.get_config("uda.taskwarrior-tui.keyconfig.annotate", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.done")
|
let filter = self.get_config("uda.taskwarrior-tui.keyconfig.filter", data);
|
||||||
.unwrap_or(self.done);
|
let zoom = self.get_config("uda.taskwarrior-tui.keyconfig.zoom", data);
|
||||||
self.start_stop = self
|
let context_menu = self.get_config("uda.taskwarrior-tui.keyconfig.context-menu", data);
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.start-stop")
|
let next_tab = self.get_config("uda.taskwarrior-tui.keyconfig.next-tab", data);
|
||||||
.unwrap_or(self.start_stop);
|
let previous_tab = self.get_config("uda.taskwarrior-tui.keyconfig.previous-tab", data);
|
||||||
self.select = self
|
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.select")
|
let (
|
||||||
.unwrap_or(self.select);
|
quit,
|
||||||
self.select_all = self
|
refresh,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.select-all")
|
go_to_bottom,
|
||||||
.unwrap_or(self.select_all);
|
go_to_top,
|
||||||
self.undo = self
|
down,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.undo")
|
up,
|
||||||
.unwrap_or(self.undo);
|
page_down,
|
||||||
self.edit = self
|
page_up,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.edit")
|
delete,
|
||||||
.unwrap_or(self.edit);
|
done,
|
||||||
self.modify = self
|
start_stop,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.modify")
|
select,
|
||||||
.unwrap_or(self.modify);
|
select_all,
|
||||||
self.shell = self
|
undo,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.shell")
|
edit,
|
||||||
.unwrap_or(self.shell);
|
modify,
|
||||||
self.log = self.get_config("uda.taskwarrior-tui.keyconfig.log").unwrap_or(self.log);
|
shell,
|
||||||
self.add = self.get_config("uda.taskwarrior-tui.keyconfig.add").unwrap_or(self.add);
|
log,
|
||||||
self.annotate = self
|
add,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.annotate")
|
annotate,
|
||||||
.unwrap_or(self.annotate);
|
filter,
|
||||||
self.filter = self
|
zoom,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.filter")
|
context_menu,
|
||||||
.unwrap_or(self.filter);
|
next_tab,
|
||||||
self.zoom = self
|
previous_tab,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.zoom")
|
) = join!(
|
||||||
.unwrap_or(self.zoom);
|
quit,
|
||||||
self.context_menu = self
|
refresh,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.context-menu")
|
go_to_bottom,
|
||||||
.unwrap_or(self.context_menu);
|
go_to_top,
|
||||||
self.next_tab = self
|
down,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.next-tab")
|
up,
|
||||||
.unwrap_or(self.next_tab);
|
page_down,
|
||||||
self.previous_tab = self
|
page_up,
|
||||||
.get_config("uda.taskwarrior-tui.keyconfig.previous-tab")
|
delete,
|
||||||
.unwrap_or(self.previous_tab);
|
done,
|
||||||
|
start_stop,
|
||||||
|
select,
|
||||||
|
select_all,
|
||||||
|
undo,
|
||||||
|
edit,
|
||||||
|
modify,
|
||||||
|
shell,
|
||||||
|
log,
|
||||||
|
add,
|
||||||
|
annotate,
|
||||||
|
filter,
|
||||||
|
zoom,
|
||||||
|
context_menu,
|
||||||
|
next_tab,
|
||||||
|
previous_tab,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.quit = quit.unwrap_or(self.quit);
|
||||||
|
self.refresh = refresh.unwrap_or(self.refresh);
|
||||||
|
self.go_to_bottom = go_to_bottom.unwrap_or(self.go_to_bottom);
|
||||||
|
self.go_to_top = go_to_top.unwrap_or(self.go_to_top);
|
||||||
|
self.down = down.unwrap_or(self.down);
|
||||||
|
self.up = up.unwrap_or(self.up);
|
||||||
|
self.page_down = page_down.unwrap_or(self.page_down);
|
||||||
|
self.page_up = page_up.unwrap_or(self.page_up);
|
||||||
|
self.delete = delete.unwrap_or(self.delete);
|
||||||
|
self.done = done.unwrap_or(self.done);
|
||||||
|
self.start_stop = start_stop.unwrap_or(self.start_stop);
|
||||||
|
self.select = select.unwrap_or(self.select);
|
||||||
|
self.select_all = select_all.unwrap_or(self.select_all);
|
||||||
|
self.undo = undo.unwrap_or(self.undo);
|
||||||
|
self.edit = edit.unwrap_or(self.edit);
|
||||||
|
self.modify = modify.unwrap_or(self.modify);
|
||||||
|
self.shell = shell.unwrap_or(self.shell);
|
||||||
|
self.log = log.unwrap_or(self.log);
|
||||||
|
self.add = add.unwrap_or(self.add);
|
||||||
|
self.annotate = annotate.unwrap_or(self.annotate);
|
||||||
|
self.filter = filter.unwrap_or(self.filter);
|
||||||
|
self.zoom = zoom.unwrap_or(self.zoom);
|
||||||
|
self.context_menu = context_menu.unwrap_or(self.context_menu);
|
||||||
|
self.next_tab = next_tab.unwrap_or(self.next_tab);
|
||||||
|
self.previous_tab = previous_tab.unwrap_or(self.previous_tab);
|
||||||
|
|
||||||
self.check()
|
self.check()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,16 +246,7 @@ impl KeyConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config(&mut self, config: &str) -> Option<Key> {
|
async fn get_config(&self, config: &str, data: &str) -> Option<Key> {
|
||||||
let output = Command::new("task")
|
|
||||||
.arg("rc.color=off")
|
|
||||||
.arg("show")
|
|
||||||
.arg(config)
|
|
||||||
.output()
|
|
||||||
.expect("Unable to run `task show`");
|
|
||||||
|
|
||||||
let data = String::from_utf8_lossy(&output.stdout);
|
|
||||||
|
|
||||||
for line in data.split('\n') {
|
for line in data.split('\n') {
|
||||||
if line.starts_with(config) {
|
if line.starts_with(config) {
|
||||||
let line = line.trim_start_matches(config).trim_start().trim_end().to_string();
|
let line = line.trim_start_matches(config).trim_start().trim_end().to_string();
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub struct TaskReportTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskReportTable {
|
impl TaskReportTable {
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new(data: &str) -> Result<Self> {
|
||||||
let virtual_tags = vec![
|
let virtual_tags = vec![
|
||||||
"PROJECT",
|
"PROJECT",
|
||||||
"BLOCKED",
|
"BLOCKED",
|
||||||
|
@ -86,16 +86,21 @@ impl TaskReportTable {
|
||||||
virtual_tags: virtual_tags.iter().map(|s| s.to_string()).collect::<Vec<_>>(),
|
virtual_tags: virtual_tags.iter().map(|s| s.to_string()).collect::<Vec<_>>(),
|
||||||
description_width: 100,
|
description_width: 100,
|
||||||
};
|
};
|
||||||
task_report_table.export_headers()?;
|
task_report_table.export_headers(Some(data))?;
|
||||||
Ok(task_report_table)
|
Ok(task_report_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export_headers(&mut self) -> Result<()> {
|
pub fn export_headers(&mut self, data: Option<&str>) -> Result<()> {
|
||||||
self.columns = vec![];
|
self.columns = vec![];
|
||||||
self.labels = vec![];
|
self.labels = vec![];
|
||||||
|
|
||||||
let output = Command::new("task").arg("show").arg("report.next.columns").output()?;
|
let data = match data {
|
||||||
let data = String::from_utf8_lossy(&output.stdout);
|
Some(s) => s.to_string(),
|
||||||
|
None => {
|
||||||
|
let output = Command::new("task").arg("show").arg("report.next.columns").output()?;
|
||||||
|
String::from_utf8_lossy(&output.stdout).into_owned()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for line in data.split('\n') {
|
for line in data.split('\n') {
|
||||||
if line.starts_with("report.next.columns") {
|
if line.starts_with("report.next.columns") {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue