Merge branch 'minor' into master
This commit is contained in:
commit
b4e25df98a
7 changed files with 27 additions and 301 deletions
|
@ -14,6 +14,27 @@ the changelog (though updating of dependencies is).
|
||||||
Please note that we do not have a "Breaking changes" section as we are in
|
Please note that we do not have a "Breaking changes" section as we are in
|
||||||
Version 0.y.z and thus we can break the API like we want and need to.
|
Version 0.y.z and thus we can break the API like we want and need to.
|
||||||
|
|
||||||
|
## 0.9.3
|
||||||
|
|
||||||
|
Bugfix release for fixing:
|
||||||
|
|
||||||
|
* Removed an import which was already there and fails with the current beta
|
||||||
|
compiler
|
||||||
|
* Fix a negation error in the config aggregation in imag-log
|
||||||
|
* Dependency specification fail in 0.9.2 where everything did not depend on
|
||||||
|
0.9.2 but 0.9.1
|
||||||
|
|
||||||
|
## 0.9.2
|
||||||
|
|
||||||
|
Bugfix release for fixing:
|
||||||
|
|
||||||
|
* Fix a function that checks a flag. If the flag is not there, it should be "not
|
||||||
|
set".
|
||||||
|
* Fix to not ignore errors when collecting links in libimagentrylink
|
||||||
|
* Remove buildscripts because imag was not installable from crates.io with
|
||||||
|
buildscripts.
|
||||||
|
|
||||||
|
|
||||||
## 0.9.1
|
## 0.9.1
|
||||||
|
|
||||||
Bugfix release for fixing:
|
Bugfix release for fixing:
|
||||||
|
|
|
@ -22,7 +22,6 @@ maintenance = { status = "actively-developed" }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
toml-query = "0.8"
|
toml-query = "0.8"
|
||||||
lazy_static = "1.2"
|
|
||||||
toml = "0.4"
|
toml = "0.4"
|
||||||
failure = "0.1"
|
failure = "0.1"
|
||||||
|
|
||||||
|
|
|
@ -44,12 +44,10 @@ pub trait EntryDate {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
const DATE_HEADER_LOCATION : &'static str = "datetime.value";
|
||||||
static ref DATE_HEADER_LOCATION : &'static str = "datetime.value";
|
const DATE_RANGE_START_HEADER_LOCATION : &'static str = "datetime.range.start";
|
||||||
static ref DATE_RANGE_START_HEADER_LOCATION : &'static str = "datetime.range.start";
|
const DATE_RANGE_END_HEADER_LOCATION : &'static str = "datetime.range.end";
|
||||||
static ref DATE_RANGE_END_HEADER_LOCATION : &'static str = "datetime.range.end";
|
const DATE_FMT : &'static str = "%Y-%m-%dT%H:%M:%S";
|
||||||
static ref DATE_FMT : &'static str = "%Y-%m-%dT%H:%M:%S";
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EntryDate for Entry {
|
impl EntryDate for Entry {
|
||||||
|
|
||||||
|
@ -93,7 +91,7 @@ impl EntryDate for Entry {
|
||||||
self.get_header_mut()
|
self.get_header_mut()
|
||||||
.insert(&DATE_HEADER_LOCATION, Value::String(date))
|
.insert(&DATE_HEADER_LOCATION, Value::String(date))
|
||||||
.context(format_err!("Failed to insert header '{}' in '{}'",
|
.context(format_err!("Failed to insert header '{}' in '{}'",
|
||||||
*DATE_HEADER_LOCATION,
|
DATE_HEADER_LOCATION,
|
||||||
self.get_location()))
|
self.get_location()))
|
||||||
.map_err(Error::from)
|
.map_err(Error::from)
|
||||||
.map(|opt| opt.map(|stri| {
|
.map(|opt| opt.map(|stri| {
|
||||||
|
|
|
@ -37,7 +37,6 @@
|
||||||
while_true,
|
while_true,
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[macro_use] extern crate lazy_static;
|
|
||||||
#[macro_use] extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
|
|
|
@ -21,17 +21,14 @@
|
||||||
|
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::result::Result as RResult;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ansi_term::Colour::*;
|
use ansi_term::Colour::*;
|
||||||
use interactor::*;
|
|
||||||
use failure::Error;
|
use failure::Error;
|
||||||
use failure::ResultExt;
|
use failure::ResultExt;
|
||||||
use failure::Fallible as Result;
|
use failure::Fallible as Result;
|
||||||
use failure::err_msg;
|
|
||||||
|
|
||||||
/// Ask the user for a Yes/No answer. Optionally provide a default value. If none is provided, this
|
/// Ask the user for a Yes/No answer. Optionally provide a default value. If none is provided, this
|
||||||
/// keeps loop{}ing
|
/// keeps loop{}ing
|
||||||
|
@ -67,111 +64,6 @@ fn ask_bool_<R: BufRead>(s: &str, default: Option<bool>, input: &mut R, output:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask the user for an unsigned number. Optionally provide a default value. If none is provided,
|
|
||||||
/// this keeps loop{}ing
|
|
||||||
pub fn ask_uint(s: &str, default: Option<u64>, input: &mut Read, output: &mut Write) -> Result<u64> {
|
|
||||||
ask_uint_(s, default, &mut BufReader::new(input), output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ask_uint_<R: BufRead>(s: &str, default: Option<u64>, input: &mut R, output: &mut Write) -> Result<u64> {
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
ask_question(s, false, output)?;
|
|
||||||
|
|
||||||
let mut s = String::new();
|
|
||||||
let _ = input.read_line(&mut s);
|
|
||||||
|
|
||||||
let u : RResult<u64, _> = FromStr::from_str(&s[..]);
|
|
||||||
match u {
|
|
||||||
Ok(u) => { return Ok(u); },
|
|
||||||
Err(_) => {
|
|
||||||
if default.is_some() {
|
|
||||||
return Ok(default.unwrap());
|
|
||||||
} // else keep looping
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ask the user for a String.
|
|
||||||
///
|
|
||||||
/// If `permit_empty` is set to false, the default value will be returned if the user inserts an
|
|
||||||
/// empty string.
|
|
||||||
///
|
|
||||||
/// If the `permit_empty` value is true, the `default` value is never returned.
|
|
||||||
///
|
|
||||||
/// If the `permit_multiline` is set to true, the `prompt` will be displayed before each input line.
|
|
||||||
///
|
|
||||||
/// If the `eof` parameter is `None`, the input ends as soon as there is an empty line input from
|
|
||||||
/// the user. If the parameter is `Some(text)`, the input ends if the input line is equal to `text`.
|
|
||||||
pub fn ask_string(s: &str,
|
|
||||||
default: Option<String>,
|
|
||||||
permit_empty: bool,
|
|
||||||
permit_multiline: bool,
|
|
||||||
eof: Option<&str>,
|
|
||||||
prompt: &str,
|
|
||||||
input: &mut Read,
|
|
||||||
output: &mut Write)
|
|
||||||
-> Result<String>
|
|
||||||
{
|
|
||||||
ask_string_(s,
|
|
||||||
default,
|
|
||||||
permit_empty,
|
|
||||||
permit_multiline,
|
|
||||||
eof,
|
|
||||||
prompt,
|
|
||||||
&mut BufReader::new(input),
|
|
||||||
output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ask_string_<R: BufRead>(s: &str,
|
|
||||||
default: Option<String>,
|
|
||||||
permit_empty: bool,
|
|
||||||
permit_multiline: bool,
|
|
||||||
eof: Option<&str>,
|
|
||||||
prompt: &str,
|
|
||||||
input: &mut R,
|
|
||||||
output: &mut Write)
|
|
||||||
-> Result<String>
|
|
||||||
{
|
|
||||||
let mut v = vec![];
|
|
||||||
loop {
|
|
||||||
ask_question(s, true, output)?;
|
|
||||||
write!(output, "{}", prompt)?;
|
|
||||||
|
|
||||||
let mut s = String::new();
|
|
||||||
let _ = input.read_line(&mut s);
|
|
||||||
|
|
||||||
if permit_multiline {
|
|
||||||
if permit_multiline && eof.map_or(false, |e| e == s) {
|
|
||||||
return Ok(v.join("\n"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if permit_empty || !v.is_empty() {
|
|
||||||
v.push(s);
|
|
||||||
}
|
|
||||||
write!(output, "{}", prompt)?;
|
|
||||||
} else if s.is_empty() && permit_empty {
|
|
||||||
return Ok(s);
|
|
||||||
} else if s.is_empty() && !permit_empty {
|
|
||||||
if default.is_some() {
|
|
||||||
return Ok(default.unwrap());
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Ok(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ask_select_from_list(list: &[&str]) -> Result<String> {
|
|
||||||
pick_from_list(default_menu_cmd().as_mut(), list, "Selection: ")
|
|
||||||
.context(err_msg("Unknown interaction error"))
|
|
||||||
.map_err(Error::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper function to print a imag question string. The `question` argument may not contain a
|
/// Helper function to print a imag question string. The `question` argument may not contain a
|
||||||
/// trailing questionmark.
|
/// trailing questionmark.
|
||||||
///
|
///
|
||||||
|
@ -191,7 +83,6 @@ mod test {
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
|
||||||
use super::ask_bool_;
|
use super::ask_bool_;
|
||||||
use super::ask_uint_;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ask_bool_nodefault_yes() {
|
fn test_ask_bool_nodefault_yes() {
|
||||||
|
@ -313,64 +204,4 @@ mod test {
|
||||||
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
assert!(true == ask_bool_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ask_uint_nodefault() {
|
|
||||||
let question = "Is this 1";
|
|
||||||
let default = None;
|
|
||||||
let answers = "1";
|
|
||||||
let mut sink: Vec<u8> = vec![];
|
|
||||||
|
|
||||||
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ask_uint_default() {
|
|
||||||
let question = "Is this 1";
|
|
||||||
let default = Some(1);
|
|
||||||
let answers = "1";
|
|
||||||
let mut sink: Vec<u8> = vec![];
|
|
||||||
|
|
||||||
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ask_uint_default_2_input_1() {
|
|
||||||
let question = "Is this 1";
|
|
||||||
let default = Some(2);
|
|
||||||
let answers = "1";
|
|
||||||
let mut sink: Vec<u8> = vec![];
|
|
||||||
|
|
||||||
assert!(1 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ask_uint_default_2_noinput() {
|
|
||||||
let question = "Is this 1";
|
|
||||||
let default = Some(2);
|
|
||||||
let answers = "\n";
|
|
||||||
let mut sink: Vec<u8> = vec![];
|
|
||||||
|
|
||||||
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ask_uint_default_2_several_noinput() {
|
|
||||||
let question = "Is this 1";
|
|
||||||
let default = Some(2);
|
|
||||||
let answers = "\n\n\n\n";
|
|
||||||
let mut sink: Vec<u8> = vec![];
|
|
||||||
|
|
||||||
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ask_uint_default_2_wrong_input() {
|
|
||||||
let question = "Is this 1";
|
|
||||||
let default = Some(2);
|
|
||||||
let answers = "\n\n\nasfb\nsakjf\naskjf\n-2";
|
|
||||||
let mut sink: Vec<u8> = vec![];
|
|
||||||
|
|
||||||
assert!(2 == ask_uint_(question, default, &mut BufReader::new(answers.as_bytes()), &mut sink).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
//
|
|
||||||
// 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 failure::ResultExt;
|
|
||||||
use toml::Value;
|
|
||||||
|
|
||||||
use rustyline::{Config, Editor};
|
|
||||||
|
|
||||||
pub struct Readline {
|
|
||||||
editor: Editor,
|
|
||||||
history_file: PathBuf,
|
|
||||||
prompt: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Readline {
|
|
||||||
|
|
||||||
pub fn new(rt: &Runtime) -> Result<Readline> {
|
|
||||||
let c = rt.config().ok_or(IEK::NoConfigError)?;
|
|
||||||
|
|
||||||
let histfile = c.lookup("ui.cli.readline_history_file").ok_or(IEK::ConfigError)?;
|
|
||||||
let histsize = c.lookup("ui.cli.readline_history_size").ok_or(IEK::ConfigError)?;
|
|
||||||
let histigndups = c.lookup("ui.cli.readline_history_ignore_dups").ok_or(IEK::ConfigError)?;
|
|
||||||
let histignspace = c.lookup("ui.cli.readline_history_ignore_space").ok_or(IEK::ConfigError)?;
|
|
||||||
let prompt = c.lookup("ui.cli.readline_prompt").ok_or(IEK::ConfigError)?;
|
|
||||||
|
|
||||||
let histfile = histfile
|
|
||||||
.as_str()
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.ok_or(IE::from_kind(IEK::ConfigTypeError))
|
|
||||||
.context(IEK::ConfigError)
|
|
||||||
.context(IEK::ReadlineError)?;
|
|
||||||
|
|
||||||
let histsize = histsize
|
|
||||||
.as_int()
|
|
||||||
.ok_or(IE::from_kind(IEK::ConfigTypeError))
|
|
||||||
.context(IEK::ConfigError)
|
|
||||||
.context(IEK::ReadlineError)?;
|
|
||||||
|
|
||||||
let histigndups = histigndups
|
|
||||||
.as_bool()
|
|
||||||
.ok_or(IE::from_kind(IEK::ConfigTypeError))
|
|
||||||
.context(IEK::ConfigError)
|
|
||||||
.context(IEK::ReadlineError)?;
|
|
||||||
|
|
||||||
let histignspace = histignspace
|
|
||||||
.as_bool()
|
|
||||||
.ok_or(IE::from_kind(IEK::ConfigTypeError))
|
|
||||||
.context(IEK::ConfigError)
|
|
||||||
.context(IEK::ReadlineError)?;
|
|
||||||
|
|
||||||
let prompt = prompt
|
|
||||||
.as_str()
|
|
||||||
.ok_or(IE::from_kind(IEK::ConfigTypeError))
|
|
||||||
.context(IEK::ConfigError)
|
|
||||||
.context(IEK::ReadlineError)?;
|
|
||||||
|
|
||||||
let config = Config::builder().
|
|
||||||
.max_history_size(histsize)
|
|
||||||
.history_ignore_dups(histigndups)
|
|
||||||
.history_ignore_space(histignspace)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let mut editor = Editor::new(config);
|
|
||||||
|
|
||||||
if !histfile.exists() {
|
|
||||||
let _ = File::create(histfile.clone())
|
|
||||||
.context(IEK::ReadlineHistoryFileCreationError)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = editor.load_history(&histfile).context(ReadlineError)?;
|
|
||||||
|
|
||||||
Ok(Readline {
|
|
||||||
editor: editor,
|
|
||||||
history_file: histfile,
|
|
||||||
prompt: prompt,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_line(&mut self) -> Result<Option<String>> {
|
|
||||||
use rustyline::ReadlineError;
|
|
||||||
use libimagutil::warn_result::*;
|
|
||||||
|
|
||||||
match self.editor.readline(&self.prompt) {
|
|
||||||
Ok(line) => {
|
|
||||||
self.editor.add_history_line(&line);
|
|
||||||
self.editor
|
|
||||||
.save_history(&self.history_file)
|
|
||||||
.map_warn_err_str(|e| format!("Could not save history file {} -> {:?}",
|
|
||||||
self.history_file.display(), e));
|
|
||||||
return line;
|
|
||||||
},
|
|
||||||
Err(ReadlineError::Interrupted) => {
|
|
||||||
info!("CTRL-C");
|
|
||||||
Ok(None)
|
|
||||||
},
|
|
||||||
Err(ReadlineError::Eof) => {
|
|
||||||
info!("CTRL-D");
|
|
||||||
Ok(None)
|
|
||||||
},
|
|
||||||
Err(err) => Err(err).map_err_into(ReadlineError),
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ CRATES=(
|
||||||
./bin/domain/imag-todo
|
./bin/domain/imag-todo
|
||||||
./bin/domain/imag-log
|
./bin/domain/imag-log
|
||||||
./bin/domain/imag-wiki
|
./bin/domain/imag-wiki
|
||||||
|
./bin/core/imag-markdown
|
||||||
./bin/core/imag-ref
|
./bin/core/imag-ref
|
||||||
./bin/core/imag-gps
|
./bin/core/imag-gps
|
||||||
./bin/core/imag-diagnostics
|
./bin/core/imag-diagnostics
|
||||||
|
|
Loading…
Reference in a new issue