Rewrite imag-view
The imag-view command was redesigned with this change. It now looks up view-templates in the config and calls them with the "in" subcommand. This way, an entry can be viewed with editor, browser or whatever one likes. Compiling markdown is not supported yet.
This commit is contained in:
parent
d26e8b62ac
commit
969211174a
5 changed files with 116 additions and 122 deletions
|
@ -16,7 +16,11 @@ homepage = "http://imag-pim.org"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = ">=2.17"
|
clap = ">=2.17"
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
|
toml = "0.4"
|
||||||
|
toml-query = "0.3"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
handlebars = "0.29.0"
|
||||||
|
tempfile = "2.1"
|
||||||
|
|
||||||
libimagstore = { version = "0.5.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.5.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagrt = { version = "0.5.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.5.0", path = "../../../lib/core/libimagrt" }
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
//
|
|
||||||
// imag - the personal information management suite for the commandline
|
|
||||||
// Copyright (C) 2015, 2016 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 libimagstore::store::FileLockEntry;
|
|
||||||
use libimagrt::runtime::Runtime;
|
|
||||||
use libimagentryview::builtin::editor::EditorView;
|
|
||||||
use libimagentryview::viewer::Viewer;
|
|
||||||
use libimagentryview::error::ViewError as VE;
|
|
||||||
|
|
||||||
pub struct Editor<'a> {
|
|
||||||
rt: &'a Runtime<'a>,
|
|
||||||
fle: &'a FileLockEntry<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Editor<'a> {
|
|
||||||
pub fn new(rt: &'a Runtime, fle: &'a FileLockEntry) -> Editor<'a> {
|
|
||||||
Editor{
|
|
||||||
rt: rt,
|
|
||||||
fle: fle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn show(self) -> Result<(), VE> {
|
|
||||||
EditorView::new(self.rt).view_entry(self.fle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -35,25 +35,35 @@
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
#[macro_use] extern crate version;
|
#[macro_use] extern crate version;
|
||||||
|
extern crate handlebars;
|
||||||
|
extern crate tempfile;
|
||||||
|
extern crate toml;
|
||||||
|
extern crate toml_query;
|
||||||
|
|
||||||
extern crate libimagentryview;
|
extern crate libimagentryview;
|
||||||
extern crate libimagerror;
|
extern crate libimagerror;
|
||||||
extern crate libimagrt;
|
extern crate libimagrt;
|
||||||
extern crate libimagstore;
|
extern crate libimagstore;
|
||||||
|
|
||||||
use std::process::exit;
|
use std::collections::BTreeMap;
|
||||||
|
use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
|
use handlebars::Handlebars;
|
||||||
|
use toml_query::read::TomlValueReadExt;
|
||||||
|
use toml::Value;
|
||||||
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
use libimagerror::trace::trace_error_exit;
|
use libimagerror::trace::trace_error_exit;
|
||||||
|
use libimagerror::trace::MapErrTrace;
|
||||||
use libimagentryview::builtin::stdout::StdoutViewer;
|
use libimagentryview::builtin::stdout::StdoutViewer;
|
||||||
use libimagentryview::viewer::Viewer;
|
use libimagentryview::viewer::Viewer;
|
||||||
|
use libimagentryview::error::ViewError as VE;
|
||||||
|
|
||||||
mod ui;
|
mod ui;
|
||||||
mod editor;
|
|
||||||
|
|
||||||
use ui::build_ui;
|
use ui::build_ui;
|
||||||
use editor::Editor;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let rt = generate_runtime_setup( "imag-view",
|
let rt = generate_runtime_setup( "imag-view",
|
||||||
|
@ -76,34 +86,98 @@ fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let res = {
|
if rt.cli().is_present("in") {
|
||||||
match rt.cli().subcommand_matches("view-in") {
|
let viewer = rt
|
||||||
None => {
|
.cli()
|
||||||
debug!("No commandline call");
|
.value_of("in")
|
||||||
debug!("Assuming to view in cli (stdout)");
|
.ok_or_else::<VE, _>(|| "No viewer given".to_owned().into())
|
||||||
|
.map_err_trace_exit(1)
|
||||||
|
.unwrap(); // saved by above call
|
||||||
|
|
||||||
|
let config = rt
|
||||||
|
.config()
|
||||||
|
.ok_or_else::<VE, _>(|| "No configuration, cannot continue".to_owned().into())
|
||||||
|
.map_err_trace_exit(1)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let query = format!("view.viewers.{}", viewer);
|
||||||
|
match config.config().read(&query) {
|
||||||
|
Err(e) => trace_error_exit(&e, 1),
|
||||||
|
Ok(None) => {
|
||||||
|
error!("Cannot find '{}' in config", query);
|
||||||
|
exit(1)
|
||||||
},
|
},
|
||||||
Some(s) => {
|
|
||||||
if s.is_present("view-in-stdout") {
|
Ok(Some(&Value::String(ref viewer_template))) => {
|
||||||
} else if s.is_present("view-in-ui") {
|
let mut handlebars = Handlebars::new();
|
||||||
warn!("Viewing in UI is currently not supported, switch to stdout");
|
handlebars.register_escape_fn(::handlebars::no_escape);
|
||||||
} else if s.is_present("view-in-browser") {
|
|
||||||
warn!("Viewing in browser is currently not supported, switch to stdout");
|
let _ = handlebars.register_template_string("template", viewer_template)
|
||||||
} else if s.is_present("view-in-texteditor") {
|
.map_err_trace_exit(1)
|
||||||
if let Err(e) = Editor::new(&rt, &entry).show() {
|
.unwrap();
|
||||||
error!("Cannot view in editor: {}", e);
|
|
||||||
trace_error_exit(&e, 1);
|
let file = {
|
||||||
|
let mut tmpfile = tempfile::NamedTempFile::new()
|
||||||
|
.map_err_trace_exit(1)
|
||||||
|
.unwrap();
|
||||||
|
if view_header {
|
||||||
|
let hdr = toml::ser::to_string_pretty(entry.get_header())
|
||||||
|
.map_err_trace_exit(1)
|
||||||
|
.unwrap();
|
||||||
|
let _ = tmpfile.write(format!("---\n{}---\n", hdr).as_bytes())
|
||||||
|
.map_err_trace_exit(1)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
} else if s.is_present("view-in-custom") {
|
|
||||||
warn!("Viewing in custom is currently not supported, switch to stdout");
|
if view_content {
|
||||||
|
let _ = tmpfile.write(entry.get_content().as_bytes())
|
||||||
|
.map_err_trace_exit(1)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
tmpfile
|
||||||
};
|
};
|
||||||
|
|
||||||
StdoutViewer::new(view_header, view_content).view_entry(&entry)
|
let file_path = file
|
||||||
|
.path()
|
||||||
|
.to_str()
|
||||||
|
.map(String::from)
|
||||||
|
.ok_or::<VE>("Cannot build path".to_owned().into())
|
||||||
|
.map_err_trace_exit(1).unwrap();
|
||||||
|
|
||||||
|
let mut command = {
|
||||||
|
let mut data = BTreeMap::new();
|
||||||
|
data.insert("entry", file_path);
|
||||||
|
|
||||||
|
let call = handlebars.render("template", &data).map_err_trace_exit(1).unwrap();
|
||||||
|
let mut elems = call.split_whitespace();
|
||||||
|
let command_string = elems
|
||||||
|
.next()
|
||||||
|
.ok_or::<VE>("No command".to_owned().into())
|
||||||
|
.map_err_trace_exit(1)
|
||||||
|
.unwrap();
|
||||||
|
let mut cmd = Command::new(command_string);
|
||||||
|
|
||||||
|
for arg in elems {
|
||||||
|
cmd.arg(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = res {
|
if !command.status().map_err_trace_exit(1).unwrap().success() {
|
||||||
trace_error_exit(&e, 1);
|
exit(1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ok(Some(_)) => {
|
||||||
|
error!("Type error: Expected String at {}, found non-string", query);
|
||||||
|
exit(1)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = StdoutViewer::new(view_header, view_content)
|
||||||
|
.view_entry(&entry)
|
||||||
|
.map_err_trace_exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
//
|
//
|
||||||
|
|
||||||
use clap::{Arg, App, ArgGroup, SubCommand};
|
use clap::{Arg, App, SubCommand};
|
||||||
|
|
||||||
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
app
|
app
|
||||||
|
@ -41,56 +41,12 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
.required(false)
|
.required(false)
|
||||||
.help("View content"))
|
.help("View content"))
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("view-in")
|
.arg(Arg::with_name("in")
|
||||||
.about("View the entry in ...")
|
.long("in")
|
||||||
.version("0.1")
|
.takes_value(true)
|
||||||
|
|
||||||
.arg(Arg::with_name("view-in-stdout")
|
|
||||||
.long("stdout")
|
|
||||||
.short("s")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
.required(false)
|
||||||
.help("View by printing to stdout"))
|
.multiple(false)
|
||||||
|
.help("View content. If no value is given, this fails. Possible viewers are configured via the config file."))
|
||||||
.arg(Arg::with_name("view-in-ui")
|
|
||||||
.long("ui")
|
|
||||||
.short("u")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("View by opening own curses-like UI (default)"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("view-in-browser")
|
|
||||||
.long("browser")
|
|
||||||
.short("b")
|
|
||||||
.takes_value(true) // optional, which browser
|
|
||||||
.required(false)
|
|
||||||
.help("View content in $BROWSER (fails if no env variable $BROWSER)")
|
|
||||||
.value_name("BROWSER"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("view-in-texteditor")
|
|
||||||
.long("in-editor")
|
|
||||||
.short("e")
|
|
||||||
.takes_value(false)
|
|
||||||
.required(false)
|
|
||||||
.help("View content in $EDITOR (can be passed via --editor)"))
|
|
||||||
|
|
||||||
.arg(Arg::with_name("view-in-custom")
|
|
||||||
.long("custom")
|
|
||||||
.short("c")
|
|
||||||
.takes_value(true) // non-optional, call-string
|
|
||||||
.required(false)
|
|
||||||
.help("View content in custom program, for example 'libreoffice %e', replace '%e' with entry path")
|
|
||||||
.value_name("PROGRAM"))
|
|
||||||
|
|
||||||
.group(ArgGroup::with_name("viewer")
|
|
||||||
.args(&["view-in-stdout",
|
|
||||||
"view-in-ui",
|
|
||||||
"view-in-browser",
|
|
||||||
"view-in-texteditor",
|
|
||||||
"view-in-custom",
|
|
||||||
])
|
|
||||||
.required(false))
|
|
||||||
)
|
|
||||||
|
|
||||||
.subcommand(SubCommand::with_name("compile")
|
.subcommand(SubCommand::with_name("compile")
|
||||||
.about("Compile content to other format for viewing, implies that the entry gets copied to /tmp")
|
.about("Compile content to other format for viewing, implies that the entry gets copied to /tmp")
|
||||||
|
|
|
@ -22,6 +22,9 @@ This section contains the changelog from the last release to the next release.
|
||||||
* `imag-counter` and `libimagcounter` was removed.
|
* `imag-counter` and `libimagcounter` was removed.
|
||||||
* `imag-mv` was introduced
|
* `imag-mv` was introduced
|
||||||
* `imag-view` uses positional args now
|
* `imag-view` uses positional args now
|
||||||
|
* `imag-view` uses the configuration file now to find the command to call
|
||||||
|
for viewing the entry. This way one can view the entry in an editor or the
|
||||||
|
browser or on the toaster.
|
||||||
|
|
||||||
## 0.4.0
|
## 0.4.0
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue