Return error to the user

This commit is contained in:
Dheepak Krishnamurthy 2020-10-24 07:06:24 -06:00
parent de496153d1
commit dc0234fd0e
3 changed files with 96 additions and 92 deletions

View file

@ -6,6 +6,7 @@ use std::cmp::Ordering;
use std::convert::TryInto;
use std::process::Command;
use std::result::Result;
use std::error::Error;
use task_hookrs::date::Date;
use task_hookrs::import::import;
@ -156,7 +157,7 @@ pub struct TaskReportTable {
}
impl TaskReportTable {
pub fn new() -> Self {
pub fn new() -> Result<Self, Box<dyn Error>> {
let virtual_tags = vec![
"PROJECT",
"BLOCKED",
@ -196,21 +197,19 @@ impl TaskReportTable {
tasks: vec![vec![]],
virtual_tags: virtual_tags.iter().map(|s| s.to_string()).collect::<Vec<_>>(),
};
task_report_table.export_headers();
task_report_table
task_report_table.export_headers()?;
Ok(task_report_table)
}
pub fn export_headers(&mut self) {
pub fn export_headers(&mut self) -> Result<(), Box<dyn Error>> {
self.columns = vec![];
self.labels = vec![];
let output = Command::new("task")
.arg("show")
.arg("report.next.columns")
.output()
.expect("Unable to run `task show report.next.columns`. Check documentation for more information");
let data = String::from_utf8(output.stdout)
.expect("Unable to decode utf8 from stdout of `task show report.next.columns`");
.output()?;
let data = String::from_utf8(output.stdout)?;
for line in data.split('\n') {
if line.starts_with("report.next.columns") {
@ -224,10 +223,8 @@ impl TaskReportTable {
let output = Command::new("task")
.arg("show")
.arg("report.next.labels")
.output()
.expect("Unable to run `task show report.next.labels`. Check documentation for more information");
let data = String::from_utf8(output.stdout)
.expect("Unable to decode utf8 from stdout of `task show report.next.labels`");
.output()?;
let data = String::from_utf8(output.stdout)?;
for line in data.split('\n') {
if line.starts_with("report.next.labels") {
@ -237,6 +234,7 @@ impl TaskReportTable {
}
}
}
Ok(())
}
pub fn generate_table(&mut self, tasks: &[Task]) {
@ -372,7 +370,7 @@ pub struct TTApp {
}
impl TTApp {
pub fn new() -> Self {
pub fn new() -> Result<Self, Box<dyn Error>> {
let mut app = Self {
should_quit: false,
state: TableState::default(),
@ -384,45 +382,33 @@ impl TTApp {
modify: LineBuffer::with_capacity(MAX_LINE),
error: "".to_string(),
mode: AppMode::TaskReport,
config: TConfig::default(),
task_report_table: TaskReportTable::new(),
config: TConfig::default()?,
task_report_table: TaskReportTable::new()?,
calendar_year: Local::today().year(),
};
for c in "status:pending ".chars() {
app.filter.insert(c, 1);
}
app.get_context();
app.update();
app
app.get_context()?;
app.update()?;
Ok(app)
}
pub fn get_context(&mut self) {
self.context_name = String::from_utf8(
Command::new("task")
.arg("_get")
.arg("rc.context")
.output()
.expect("Unable to run `task _get rc.context`")
.stdout,
)
.expect("Unable to decode utf8 from stdout of `task _get rc.context`");
pub fn get_context(&mut self) -> Result<(), Box<dyn Error>> {
let output = Command::new("task")
.arg("_get")
.arg("rc.context")
.output()?;
self.context_name = String::from_utf8(output.stdout)?;
self.context_name = self.context_name.strip_suffix('\n').unwrap_or("").to_string();
self.context_filter = String::from_utf8(
Command::new("task")
.arg("_get")
.arg(format!("rc.context.{}", self.context_name))
.output()
.expect(format!("Unable to run `task _get rc.context.{}`", self.context_name).as_str())
.stdout,
)
.unwrap_or_else(|_| {
panic!(
"Unable to decode utf8 from stdout of `task _get rc.context.{}`",
self.context_name
)
});
let output = Command::new("task")
.arg("_get")
.arg(format!("rc.context.{}", self.context_name))
.output()?;
self.context_filter = String::from_utf8(output.stdout)?;
self.context_filter = self.context_filter.strip_suffix('\n').unwrap_or("").to_string();
Ok(())
}
pub fn draw(&mut self, f: &mut Frame<impl Backend>) {
@ -933,9 +919,10 @@ impl TTApp {
(tasks, headers)
}
pub fn update(&mut self) {
self.export_tasks();
pub fn update(&mut self) -> Result<(), Box<dyn Error>> {
self.export_tasks()?;
self.update_tags();
Ok(())
}
pub fn next(&mut self) {
@ -971,7 +958,7 @@ impl TTApp {
self.state.select(Some(i));
}
pub fn export_tasks(&self) {
pub fn export_tasks(&mut self) -> Result<(), Box<dyn Error>> {
let mut task = Command::new("task");
task.arg("rc.json.array=on");
@ -995,17 +982,12 @@ impl TTApp {
}
}
let output = task
.output()
.expect("Unable to run `task export`. Check documentation for more information.");
let data = String::from_utf8(output.stdout).unwrap_or_default();
let imported = import(data.as_bytes());
{
if let Ok(i) = imported {
*(self.tasks.lock().unwrap()) = i;
self.tasks.lock().unwrap().sort_by(cmp);
}
}
let output = task.output()?;
let data = String::from_utf8(output.stdout)?;
let imported = import(data.as_bytes())?;
*(self.tasks.lock().unwrap()) = imported;
self.tasks.lock().unwrap().sort_by(cmp);
Ok(())
}
pub fn task_subprocess(&mut self) -> Result<(), String> {
@ -1405,39 +1387,39 @@ impl TTApp {
}
}
pub fn handle_input(&mut self, input: Key, terminal: &mut Terminal<CrosstermBackend<io::Stdout>>, events: &Events) {
pub fn handle_input(&mut self, input: Key, terminal: &mut Terminal<CrosstermBackend<io::Stdout>>, events: &Events) -> Result<(), Box<dyn Error>> {
match self.mode {
AppMode::TaskReport => match input {
Key::Ctrl('c') | Key::Char('q') => self.should_quit = true,
Key::Char(']') => {
self.mode = AppMode::Calendar;
}
Key::Char('r') => self.update(),
Key::Char('r') => self.update()?,
Key::Down | Key::Char('j') => self.next(),
Key::Up | Key::Char('k') => self.previous(),
Key::Char('d') => match self.task_done() {
Ok(_) => self.update(),
Ok(_) => self.update()?,
Err(e) => {
self.mode = AppMode::TaskError;
self.error = e;
}
},
Key::Char('x') => match self.task_delete() {
Ok(_) => self.update(),
Ok(_) => self.update()?,
Err(e) => {
self.mode = AppMode::TaskError;
self.error = e;
}
},
Key::Char('s') => match self.task_start_or_stop() {
Ok(_) => self.update(),
Ok(_) => self.update()?,
Err(e) => {
self.mode = AppMode::TaskError;
self.error = e;
}
},
Key::Char('u') => match self.task_undo() {
Ok(_) => self.update(),
Ok(_) => self.update()?,
Err(e) => {
self.mode = AppMode::TaskError;
self.error = e;
@ -1448,7 +1430,7 @@ impl TTApp {
let r = self.task_edit();
events.resume_event_loop(terminal);
match r {
Ok(_) => self.update(),
Ok(_) => self.update()?,
Err(e) => {
self.mode = AppMode::TaskError;
self.error = e;
@ -1495,7 +1477,7 @@ impl TTApp {
Key::Char('\n') => match self.task_modify() {
Ok(_) => {
self.mode = AppMode::TaskReport;
self.update();
self.update()?;
}
Err(e) => {
self.mode = AppMode::TaskError;
@ -1512,7 +1494,7 @@ impl TTApp {
Key::Char('\n') => match self.task_subprocess() {
Ok(_) => {
self.mode = AppMode::TaskReport;
self.update();
self.update()?;
}
Err(e) => {
self.mode = AppMode::TaskError;
@ -1529,7 +1511,7 @@ impl TTApp {
Key::Char('\n') => match self.task_log() {
Ok(_) => {
self.mode = AppMode::TaskReport;
self.update();
self.update()?;
}
Err(e) => {
self.mode = AppMode::TaskError;
@ -1546,7 +1528,7 @@ impl TTApp {
Key::Char('\n') => match self.task_annotate() {
Ok(_) => {
self.mode = AppMode::TaskReport;
self.update();
self.update()?;
}
Err(e) => {
self.mode = AppMode::TaskError;
@ -1563,7 +1545,7 @@ impl TTApp {
Key::Char('\n') => match self.task_add() {
Ok(_) => {
self.mode = AppMode::TaskReport;
self.update();
self.update()?;
}
Err(e) => {
self.mode = AppMode::TaskError;
@ -1579,7 +1561,7 @@ impl TTApp {
AppMode::TaskFilter => match input {
Key::Char('\n') | Key::Esc => {
self.mode = AppMode::TaskReport;
self.update();
self.update()?;
}
_ => handle_movement(&mut self.filter, input),
},
@ -1596,6 +1578,7 @@ impl TTApp {
_ => {}
},
}
Ok(())
}
}

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::process::Command;
use std::str;
use tui::style::{Color, Modifier};
use std::error::Error;
#[derive(Debug, Clone)]
pub struct TColor {
@ -70,13 +71,13 @@ impl TaskWarriorBool for str {
}
impl TConfig {
pub fn default() -> Self {
pub fn default() -> Result<Self, Box<dyn Error>> {
let bool_collection = Self::get_bool_collection();
Self {
Ok(Self {
enabled: true,
obfuscate: bool_collection.get("obfuscate").cloned().unwrap_or(false),
print_empty_columns: bool_collection.get("print_empty_columns").cloned().unwrap_or(false),
color: Self::get_color_collection(),
color: Self::get_color_collection()?,
rule_precedence_color: Self::get_rule_precedence_color(),
uda_selection_indicator: Self::get_uda_selection_indicator(),
uda_selection_bold: Self::get_uda_selection_bold(),
@ -84,22 +85,21 @@ impl TConfig {
uda_selection_dim: Self::get_uda_selection_dim(),
uda_selection_blink: Self::get_uda_selection_blink(),
uda_calendar_months_per_row: Self::get_uda_months_per_row(),
}
})
}
fn get_bool_collection() -> HashMap<String, bool> {
HashMap::new()
}
fn get_color_collection() -> HashMap<String, TColor> {
fn get_color_collection() -> Result<HashMap<String, TColor>, Box<dyn Error>> {
let mut color_collection = HashMap::new();
let output = Command::new("task")
.arg("rc.color=off")
.arg("show")
.output()
.expect("Unable to run `task show`");
.output()?;
let data = String::from_utf8(output.stdout).expect("Unable to convert stdout to string");
let mut color_collection = HashMap::new();
for line in data.split('\n') {
if line.starts_with("color.") {
let mut i = line.split(' ');
@ -113,7 +113,8 @@ impl TConfig {
};
}
}
color_collection
Ok(color_collection)
}
fn get_tcolor(line: &str) -> TColor {

View file

@ -50,23 +50,43 @@ fn tui_main(_config: &str) -> Result<(), Box<dyn Error>> {
tick_rate: Duration::from_millis(1000),
});
let mut app = TTApp::new();
app.next();
let maybeapp = TTApp::new();
match maybeapp {
Ok(mut app) => {
app.next();
loop {
terminal.draw(|mut frame| app.draw(&mut frame)).unwrap();
loop {
terminal.draw(|mut frame| app.draw(&mut frame)).unwrap();
// Handle input
match events.next()? {
Event::Input(input) => app.handle_input(input, &mut terminal, &events),
Event::Tick => app.update(),
}
// Handle input
match events.next()? {
Event::Input(input) => {
let r = app.handle_input(input, &mut terminal, &events);
if r.is_err() {
destruct_terminal(terminal);
return r
}
},
Event::Tick => {
let r = app.update();
if r.is_err() {
destruct_terminal(terminal);
return r
}
},
}
if app.should_quit {
if app.should_quit {
destruct_terminal(terminal);
break;
}
}
Ok(())
},
Err(e) => {
destruct_terminal(terminal);
break;
}
Err(e)
},
}
Ok(())
}