Rewrite show functionality of imag-todo
This implementation uses the handlebars crate so that the show format can be specified in the configuration file. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
c2d4ec5fef
commit
cadd9f8944
4 changed files with 115 additions and 48 deletions
|
@ -29,6 +29,7 @@ chrono = "0.4"
|
||||||
filters = "0.3"
|
filters = "0.3"
|
||||||
kairos = "0.3"
|
kairos = "0.3"
|
||||||
resiter = "0.4.0"
|
resiter = "0.4.0"
|
||||||
|
handlebars = "2"
|
||||||
|
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
@ -37,6 +38,7 @@ libimagentryedit = { version = "0.10.0", path = "../../../lib/entry/libimagentry
|
||||||
libimagtodo = { version = "0.10.0", path = "../../../lib/domain/libimagtodo" }
|
libimagtodo = { version = "0.10.0", path = "../../../lib/domain/libimagtodo" }
|
||||||
libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
|
libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
|
||||||
libimagentryview = { version = "0.10.0", path = "../../../lib/entry/libimagentryview" }
|
libimagentryview = { version = "0.10.0", path = "../../../lib/entry/libimagentryview" }
|
||||||
|
libimaginteraction = { version = "0.10.0", path = "../../../lib/etc/libimaginteraction" }
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "2.33.0"
|
version = "2.33.0"
|
||||||
|
|
|
@ -43,6 +43,7 @@ extern crate kairos;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
extern crate resiter;
|
extern crate resiter;
|
||||||
|
extern crate handlebars;
|
||||||
|
|
||||||
#[cfg(feature = "import-taskwarrior")]
|
#[cfg(feature = "import-taskwarrior")]
|
||||||
extern crate task_hookrs;
|
extern crate task_hookrs;
|
||||||
|
@ -63,7 +64,9 @@ extern crate libimagentryedit;
|
||||||
extern crate libimagtodo;
|
extern crate libimagtodo;
|
||||||
extern crate libimagutil;
|
extern crate libimagutil;
|
||||||
extern crate libimagentryview;
|
extern crate libimagentryview;
|
||||||
|
extern crate libimaginteraction;
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::result::Result as RResult;
|
use std::result::Result as RResult;
|
||||||
|
|
||||||
|
@ -77,7 +80,6 @@ use resiter::AndThen;
|
||||||
use resiter::IterInnerOkOrElse;
|
use resiter::IterInnerOkOrElse;
|
||||||
|
|
||||||
use libimagentryedit::edit::Edit;
|
use libimagentryedit::edit::Edit;
|
||||||
use libimagentryview::viewer::ViewFromIter;
|
|
||||||
use libimagentryview::viewer::Viewer;
|
use libimagentryview::viewer::Viewer;
|
||||||
use libimagrt::application::ImagApplication;
|
use libimagrt::application::ImagApplication;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
|
@ -88,10 +90,10 @@ use libimagtodo::entry::Todo;
|
||||||
use libimagtodo::priority::Priority;
|
use libimagtodo::priority::Priority;
|
||||||
use libimagtodo::status::Status;
|
use libimagtodo::status::Status;
|
||||||
use libimagtodo::store::TodoStore;
|
use libimagtodo::store::TodoStore;
|
||||||
use libimagutil::date::datetime_to_string;
|
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
mod import;
|
mod import;
|
||||||
|
mod util;
|
||||||
|
|
||||||
/// Marker enum for implementing ImagApplication on
|
/// Marker enum for implementing ImagApplication on
|
||||||
///
|
///
|
||||||
|
@ -287,9 +289,9 @@ fn list_todos(rt: &Runtime, matcher: &StatusMatcher, show_hidden: bool) -> Resul
|
||||||
status = status,
|
status = status,
|
||||||
first_line = first_line)
|
first_line = first_line)
|
||||||
} else {
|
} else {
|
||||||
let sched = get_dt_str(entry.get_scheduled(), "Not scheduled")?;
|
let sched = util::get_dt_str(entry.get_scheduled(), "Not scheduled")?;
|
||||||
let hidden = get_dt_str(entry.get_hidden(), "Not hidden")?;
|
let hidden = util::get_dt_str(entry.get_hidden(), "Not hidden")?;
|
||||||
let due = get_dt_str(entry.get_due(), "No due")?;
|
let due = util::get_dt_str(entry.get_due(), "No due")?;
|
||||||
let priority = entry.get_priority().map_err(E::from)?.map(|p| p.as_str().to_string())
|
let priority = entry.get_priority().map_err(E::from)?.map(|p| p.as_str().to_string())
|
||||||
.unwrap_or("No prio".to_string());
|
.unwrap_or("No prio".to_string());
|
||||||
|
|
||||||
|
@ -357,41 +359,10 @@ fn list(rt: &Runtime) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(rt: &Runtime) -> Result<()> {
|
fn show(rt: &Runtime) -> Result<()> {
|
||||||
#[derive(Default)]
|
let scmd = rt.cli().subcommand_matches("show").unwrap();
|
||||||
struct TodoShow;
|
let show_format = util::get_todo_print_format("todo.show_format", rt, &scmd)?;
|
||||||
impl Viewer for TodoShow {
|
let out = rt.stdout();
|
||||||
|
let mut outlock = out.lock();
|
||||||
fn view_entry<W>(&self, entry: &Entry, sink: &mut W) -> RResult<(), libimagentryview::error::Error>
|
|
||||||
where W: Write
|
|
||||||
{
|
|
||||||
use libimagentryview::error::Error as E;
|
|
||||||
|
|
||||||
if !entry.is_todo().map_err(E::from)? {
|
|
||||||
return Err(format_err!("Not a Todo: {}", entry.get_location())).map_err(E::from);
|
|
||||||
}
|
|
||||||
|
|
||||||
let uuid = entry.get_uuid().map_err(E::from)?;
|
|
||||||
let status = entry.get_status().map_err(E::from)?;
|
|
||||||
let status = status.as_str();
|
|
||||||
let text = entry.get_content();
|
|
||||||
let sched = get_dt_str(entry.get_scheduled(), "Not scheduled")?;
|
|
||||||
let hidden = get_dt_str(entry.get_hidden(), "Not hidden")?;
|
|
||||||
let due = get_dt_str(entry.get_due(), "No due")?;
|
|
||||||
let priority = entry.get_priority().map_err(E::from)?.map(|p| p.as_str().to_string())
|
|
||||||
.unwrap_or("No prio".to_string());
|
|
||||||
|
|
||||||
writeln!(sink, "{uuid}\nStatus: {status}\nPriority: {prio}\nScheduled: {sched}\nHidden: {hidden}\nDue: {due}\n\n{text}",
|
|
||||||
uuid = uuid,
|
|
||||||
status = status,
|
|
||||||
sched = sched,
|
|
||||||
hidden = hidden,
|
|
||||||
due = due,
|
|
||||||
prio = priority,
|
|
||||||
text = text)
|
|
||||||
.map_err(Error::from)
|
|
||||||
.map_err(libimagentryview::error::Error::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rt.ids::<crate::ui::PathProvider>()?
|
rt.ids::<crate::ui::PathProvider>()?
|
||||||
.ok_or_else(|| err_msg("No ids supplied"))?
|
.ok_or_else(|| err_msg("No ids supplied"))?
|
||||||
|
@ -402,8 +373,13 @@ fn show(rt: &Runtime) -> Result<()> {
|
||||||
.and_then_ok(|e| rt.report_touched(e.get_location()).map_err(Error::from).map(|_| e))
|
.and_then_ok(|e| rt.report_touched(e.get_location()).map_err(Error::from).map(|_| e))
|
||||||
.collect::<Result<Vec<_>>>()?
|
.collect::<Result<Vec<_>>>()?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.view::<TodoShow, _>(&mut rt.stdout())
|
.enumerate()
|
||||||
.map_err(Error::from)
|
.map(|(i, elem)| {
|
||||||
|
let data = util::build_data_object_for_handlebars(i, elem.deref())?;
|
||||||
|
let s = show_format.render("format", &data)?;
|
||||||
|
writeln!(outlock, "{}", s).map_err(Error::from)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -437,9 +413,3 @@ fn prio_from_str<S: AsRef<str>>(s: S) -> Result<Priority> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_dt_str(d: Result<Option<NaiveDateTime>>, s: &str) -> RResult<String, libimagentryview::error::Error> {
|
|
||||||
Ok(d.map_err(libimagentryview::error::Error::from)?
|
|
||||||
.map(|v| datetime_to_string(&v))
|
|
||||||
.unwrap_or(s.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,14 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
)
|
)
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("show")
|
.subcommand(SubCommand::with_name("show")
|
||||||
|
.arg(Arg::with_name("format")
|
||||||
|
.long("format")
|
||||||
|
.short("F")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(false)
|
||||||
|
.help("Output format string")
|
||||||
|
)
|
||||||
|
|
||||||
.arg(Arg::with_name("todos")
|
.arg(Arg::with_name("todos")
|
||||||
.index(1)
|
.index(1)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
|
|
87
bin/domain/imag-todo/src/util.rs
Normal file
87
bin/domain/imag-todo/src/util.rs
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
//
|
||||||
|
// imag - the personal information management suite for the commandline
|
||||||
|
// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; version
|
||||||
|
// 2.1 of the License.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::result::Result as RResult;
|
||||||
|
|
||||||
|
use failure::Fallible as Result;
|
||||||
|
use failure::Error;
|
||||||
|
use failure::err_msg;
|
||||||
|
use handlebars::Handlebars;
|
||||||
|
use clap::ArgMatches;
|
||||||
|
use chrono::NaiveDateTime;
|
||||||
|
use toml_query::read::TomlValueReadTypeExt;
|
||||||
|
|
||||||
|
use libimagrt::runtime::Runtime;
|
||||||
|
use libimagstore::store::Entry;
|
||||||
|
use libimagtodo::entry::Todo;
|
||||||
|
use libimagutil::date::datetime_to_string;
|
||||||
|
|
||||||
|
pub fn get_dt_str(d: Result<Option<NaiveDateTime>>, s: &str) -> RResult<String, libimagentryview::error::Error> {
|
||||||
|
Ok(d.map_err(libimagentryview::error::Error::from)?
|
||||||
|
.map(|v| datetime_to_string(&v))
|
||||||
|
.unwrap_or(s.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_todo_print_format(config_value_path: &'static str, rt: &Runtime, scmd: &ArgMatches) -> Result<Handlebars> {
|
||||||
|
let fmt = match scmd.value_of("format").map(String::from) {
|
||||||
|
Some(s) => Ok(s),
|
||||||
|
None => {
|
||||||
|
rt.config()
|
||||||
|
.ok_or_else(|| err_msg("No configuration file"))?
|
||||||
|
.read_string(config_value_path)
|
||||||
|
.map_err(Error::from)?
|
||||||
|
.ok_or_else(|| format_err!("Configuration '{}' does not exist", config_value_path))
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let mut hb = Handlebars::new();
|
||||||
|
hb.register_template_string("format", fmt)?;
|
||||||
|
|
||||||
|
hb.register_escape_fn(::handlebars::no_escape);
|
||||||
|
::libimaginteraction::format::register_all_color_helpers(&mut hb);
|
||||||
|
::libimaginteraction::format::register_all_format_helpers(&mut hb);
|
||||||
|
Ok(hb)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_data_object_for_handlebars(i: usize, todo: &Entry) -> Result<BTreeMap<&'static str, String>> {
|
||||||
|
let mut data = BTreeMap::new();
|
||||||
|
|
||||||
|
data.insert("i", format!("{}", i));
|
||||||
|
let uuid = todo.get_uuid().map_err(Error::from)?.to_string();
|
||||||
|
let status = todo.get_status().map_err(Error::from)?;
|
||||||
|
let status = status.as_str().to_string();
|
||||||
|
let text = todo.get_content().to_string();
|
||||||
|
let sched = get_dt_str(todo.get_scheduled(), "Not scheduled")?;
|
||||||
|
let hidden = get_dt_str(todo.get_hidden(), "Not hidden")?;
|
||||||
|
let due = get_dt_str(todo.get_due(), "No due")?;
|
||||||
|
let priority = todo.get_priority().map_err(Error::from)?.map(|p| p.as_str().to_string())
|
||||||
|
.unwrap_or("No prio".to_string());
|
||||||
|
|
||||||
|
data.insert("uuid" , uuid);
|
||||||
|
data.insert("status" , status);
|
||||||
|
data.insert("text" , text);
|
||||||
|
data.insert("sched" , sched);
|
||||||
|
data.insert("hidden" , hidden);
|
||||||
|
data.insert("due" , due);
|
||||||
|
data.insert("priority" , priority);
|
||||||
|
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue