summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2019-12-01 12:54:11 +0100
committerMatthias Beyer <mail@beyermatthias.de>2019-12-01 12:54:11 +0100
commitcadd9f894478b4c5a9c173655e506c5f4794e04a (patch)
tree5844cb3559cd664ef4ef7b8e3153b031f10efcf9
parentc2d4ec5fefe5de8871d974e7dd61af0fa618ae91 (diff)
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>
-rw-r--r--bin/domain/imag-todo/Cargo.toml2
-rw-r--r--bin/domain/imag-todo/src/lib.rs66
-rw-r--r--bin/domain/imag-todo/src/ui.rs8
-rw-r--r--bin/domain/imag-todo/src/util.rs87
4 files changed, 115 insertions, 48 deletions
diff --git a/bin/domain/imag-todo/Cargo.toml b/bin/domain/imag-todo/Cargo.toml
index bbb5667a..3cb37b5a 100644
--- a/bin/domain/imag-todo/Cargo.toml
+++ b/bin/domain/imag-todo/Cargo.toml
@@ -29,6 +29,7 @@ chrono = "0.4"
filters = "0.3"
kairos = "0.3"
resiter = "0.4.0"
+handlebars = "2"
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
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" }
libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
libimagentryview = { version = "0.10.0", path = "../../../lib/entry/libimagentryview" }
+libimaginteraction = { version = "0.10.0", path = "../../../lib/etc/libimaginteraction" }
[dependencies.clap]
version = "2.33.0"
diff --git a/bin/domain/imag-todo/src/lib.rs b/bin/domain/imag-todo/src/lib.rs
index 1ee53439..0943e8c7 100644
--- a/bin/domain/imag-todo/src/lib.rs
+++ b/bin/domain/imag-todo/src/lib.rs
@@ -43,6 +43,7 @@ extern crate kairos;
#[macro_use] extern crate log;
#[macro_use] extern crate failure;
extern crate resiter;
+extern crate handlebars;
#[cfg(feature = "import-taskwarrior")]
extern crate task_hookrs;
@@ -63,7 +64,9 @@ extern crate libimagentryedit;
extern crate libimagtodo;
extern crate libimagutil;
extern crate libimagentryview;
+extern crate libimaginteraction;
+use std::ops::Deref;
use std::io::Write;
use std::result::Result as RResult;
@@ -77,7 +80,6 @@ use resiter::AndThen;
use resiter::IterInnerOkOrElse;
use libimagentryedit::edit::Edit;
-use libimagentryview::viewer::ViewFromIter;
use libimagentryview::viewer::Viewer;
use libimagrt::application::ImagApplication;
use libimagrt::runtime::Runtime;
@@ -88,10 +90,10 @@ use libimagtodo::entry::Todo;
use libimagtodo::priority::Priority;
use libimagtodo::status::Status;
use libimagtodo::store::TodoStore;
-use libimagutil::date::datetime_to_string;
mod ui;
mod import;
+mod util;
/// Marker enum for implementing ImagApplication on
///
@@ -287,9 +289,9 @@ fn list_todos(rt: &Runtime, matcher: &StatusMatcher, show_hidden: bool) -> Resul
status = status,
first_line = first_line)
} else {
- 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 sched = util::get_dt_str(entry.get_scheduled(), "Not scheduled")?;
+ let hidden = util::get_dt_str(entry.get_hidden(), "Not hidden")?;
+ 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())
.unwrap_or("No prio".to_string());
@@ -357,41 +359,10 @@ fn list(rt: &Runtime) -> Result<()> {
}
fn show(rt: &Runtime) -> Result<()> {
- #[derive(Default)]
- struct TodoShow;
- impl Viewer for TodoShow {
-
- 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)
- }
- }
+ let scmd = rt.cli().subcommand_matches("show").unwrap();
+ let show_format = util::get_todo_print_format("todo.show_format", rt, &scmd)?;
+ let out = rt.stdout();
+ let mut outlock = out.lock();
rt.ids::<crate::ui::PathProvider>()?
.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))
.collect::<Result<Vec<_>>>()?
.into_iter()
- .view::<TodoShow, _>(&mut rt.stdout())
- .map_err(Error::from)
+ .enumerate()
+ .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()))
-}
-
diff --git a/bin/domain/imag-todo/src/ui.rs b/bin/domain/imag-todo/src/ui.rs
index 8ed92dba..0b55b2aa 100644
--- a/bin/domain/imag-todo/src/ui.rs
+++ b/bin/domain/imag-todo/src/ui.rs
@@ -138,6 +138,14 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
)
.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")
.index(1)
.takes_value(true)
diff --git a/bin/domain/imag-todo/src/util.rs b/bin/domain/imag-todo/src/util.rs
new file mode 100644
index 00000000..6e3fd669
--- /dev/null
+++ b/bin/domain/imag-todo/src/util.rs
@@ -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)
+}
+