Merge pull request #1125 from matthiasbeyer/imag-view/cli-rewrite

Imag view/cli rewrite
This commit is contained in:
Matthias Beyer 2017-10-08 16:42:30 +02:00 committed by GitHub
commit e5155cacca
6 changed files with 121 additions and 122 deletions

View file

@ -16,7 +16,11 @@ homepage = "http://imag-pim.org"
[dependencies]
clap = ">=2.17"
log = "0.3"
toml = "0.4"
toml-query = "0.3"
version = "2.0.1"
handlebars = "0.29.0"
tempfile = "2.1"
libimagstore = { version = "0.5.0", path = "../../../lib/core/libimagstore" }
libimagrt = { version = "0.5.0", path = "../../../lib/core/libimagrt" }

View file

@ -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)
}
}

View file

@ -35,25 +35,35 @@
extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate version;
extern crate handlebars;
extern crate tempfile;
extern crate toml;
extern crate toml_query;
extern crate libimagentryview;
extern crate libimagerror;
extern crate libimagrt;
extern crate libimagstore;
use std::process::exit;
use std::collections::BTreeMap;
use std::io::Write;
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 libimagerror::trace::trace_error_exit;
use libimagerror::trace::MapErrTrace;
use libimagentryview::builtin::stdout::StdoutViewer;
use libimagentryview::viewer::Viewer;
use libimagentryview::error::ViewError as VE;
mod ui;
mod editor;
use ui::build_ui;
use editor::Editor;
fn main() {
let rt = generate_runtime_setup( "imag-view",
@ -76,34 +86,98 @@ fn main() {
}
};
let res = {
match rt.cli().subcommand_matches("view-in") {
None => {
debug!("No commandline call");
debug!("Assuming to view in cli (stdout)");
if rt.cli().is_present("in") {
let viewer = rt
.cli()
.value_of("in")
.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") {
} else if s.is_present("view-in-ui") {
warn!("Viewing in UI is currently not supported, switch to stdout");
} else if s.is_present("view-in-browser") {
warn!("Viewing in browser is currently not supported, switch to stdout");
} else if s.is_present("view-in-texteditor") {
if let Err(e) = Editor::new(&rt, &entry).show() {
error!("Cannot view in editor: {}", e);
trace_error_exit(&e, 1);
Ok(Some(&Value::String(ref viewer_template))) => {
let mut handlebars = Handlebars::new();
handlebars.register_escape_fn(::handlebars::no_escape);
let _ = handlebars.register_template_string("template", viewer_template)
.map_err_trace_exit(1)
.unwrap();
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
};
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 !command.status().map_err_trace_exit(1).unwrap().success() {
exit(1)
}
},
};
StdoutViewer::new(view_header, view_content).view_entry(&entry)
};
if let Err(e) = res {
trace_error_exit(&e, 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);
}
}

View file

@ -17,7 +17,7 @@
// 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> {
app
@ -41,56 +41,12 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.required(false)
.help("View content"))
.subcommand(SubCommand::with_name("view-in")
.about("View the entry in ...")
.version("0.1")
.arg(Arg::with_name("view-in-stdout")
.long("stdout")
.short("s")
.takes_value(false)
.required(false)
.help("View by printing to stdout"))
.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))
)
.arg(Arg::with_name("in")
.long("in")
.takes_value(true)
.required(false)
.multiple(false)
.help("View content. If no value is given, this fails. Possible viewers are configured via the config file."))
.subcommand(SubCommand::with_name("compile")
.about("Compile content to other format for viewing, implies that the entry gets copied to /tmp")

View file

@ -22,6 +22,9 @@ This section contains the changelog from the last release to the next release.
* `imag-counter` and `libimagcounter` was removed.
* `imag-mv` was introduced
* `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

View file

@ -205,3 +205,8 @@ timed = "minutely"
[bookmark]
default_collection = "default"
[view.viewers]
# Configure which viewers there are for `imag view <entry> in <viewer>`.
editor = "vim -R {{entry}}"
web = "chromium {{entry}}"