Merge pull request #1035 from matthiasbeyer/tag-ui-feature-to-bin

Tag ui feature to bin
This commit is contained in:
Matthias Beyer 2017-09-02 14:10:01 +02:00 committed by GitHub
commit 8c69ed54e4
11 changed files with 56 additions and 189 deletions

View File

@ -48,10 +48,11 @@ use libimagrt::setup::generate_runtime_setup;
use libimagentrytag::tagable::Tagable;
use libimagentrytag::tag::Tag;
use libimagerror::trace::{trace_error, trace_error_exit};
use libimagentrytag::ui::{get_add_tags, get_remove_tags};
use libimagstore::storeid::StoreId;
use libimagutil::warn_exit::warn_exit;
use clap::ArgMatches;
mod ui;
use ui::build_ui;
@ -181,6 +182,42 @@ fn list(id: PathBuf, rt: &Runtime) {
}
}
/// Get the tags which should be added from the commandline
///
/// Returns none if the argument was not specified
fn get_add_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
let a = "add-tags";
extract_tags(matches, a, '+')
.or_else(|| matches.values_of(a).map(|values| values.map(String::from).collect()))
}
/// Get the tags which should be removed from the commandline
///
/// Returns none if the argument was not specified
fn get_remove_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
let r = "remove-tags";
extract_tags(matches, r, '+')
.or_else(|| matches.values_of(r).map(|values| values.map(String::from).collect()))
}
fn extract_tags(matches: &ArgMatches, specifier: &str, specchar: char) -> Option<Vec<Tag>> {
if let Some(submatch) = matches.subcommand_matches("tags") {
submatch.values_of(specifier)
.map(|values| values.map(String::from).collect())
} else {
matches.values_of("specify-tags")
.map(|argmatches| {
argmatches
.map(String::from)
.filter(|s| s.starts_with(specchar))
.map(|s| {
String::from(s.split_at(1).1)
})
.collect()
})
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
@ -190,12 +227,11 @@ mod tests {
use toml_query::read::TomlValueReadExt;
use toml_query::error::Result as TomlQueryResult;
use libimagentrytag::ui::{get_add_tags, get_remove_tags};
use libimagrt::runtime::Runtime;
use libimagstore::storeid::StoreId;
use libimagstore::store::{Result as StoreResult, FileLockEntry};
use super::alter;
use super::*;
make_mock_app! {
app "imag-tag";

View File

@ -19,7 +19,7 @@
use clap::{Arg, App, ArgGroup, SubCommand};
use libimagentrytag::ui::{tag_add_arg, tag_remove_arg};
use libimagentrytag::tag::is_tag;
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
app.arg(Arg::with_name("id")
@ -30,8 +30,22 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.help("Use this entry")
.value_name("ID"))
.arg(tag_add_arg())
.arg(tag_remove_arg())
.arg(Arg::with_name("add-tags")
.short("a")
.long("add")
.takes_value(true)
.value_name("tags")
.multiple(true)
.validator(is_tag)
.help("Add tags, seperated by comma or by specifying multiple times"))
.arg(Arg::with_name("remove-tags")
.short("r")
.long("remove")
.takes_value(true)
.value_name("tags")
.multiple(true)
.validator(is_tag)
.help("Remove tags, seperated by comma or by specifying multiple times"))
.subcommand(SubCommand::with_name("list")
.about("List tags (default)")

View File

@ -21,5 +21,4 @@ version = "2.0.1"
libimagrt = { version = "0.4.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
libimagbookmark = { version = "0.4.0", path = "../../../lib/domain/libimagbookmark" }
libimagentrytag = { version = "0.4.0", path = "../../../lib/entry/libimagentrytag" }
libimagutil = { version = "0.4.0", path = "../../../lib/etc/libimagutil" }

View File

@ -37,7 +37,6 @@ extern crate clap;
#[macro_use] extern crate version;
extern crate libimagbookmark;
extern crate libimagentrytag;
extern crate libimagrt;
extern crate libimagerror;
extern crate libimagutil;

View File

@ -19,7 +19,6 @@
use clap::{Arg, App, SubCommand};
use libimagentrytag::ui::tag_add_arg;
use libimagutil::cli_validators::*;
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
@ -44,7 +43,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.value_name("URL")
.validator(is_url)
.help("Add this URL, multiple possible"))
.arg(tag_add_arg())
)
.subcommand(SubCommand::with_name("remove")

View File

@ -23,5 +23,4 @@ libimagrt = { version = "0.4.0", path = "../../../lib/core/libimagrt" }
libimagerror = { version = "0.4.0", path = "../../../lib/core/libimagerror" }
libimagnotes = { version = "0.4.0", path = "../../../lib/domain/libimagnotes" }
libimagentryedit = { version = "0.4.0", path = "../../../lib/entry/libimagentryedit" }
libimagentrytag = { version = "0.4.0", path = "../../../lib/entry/libimagentrytag" }
libimagutil = { version = "0.4.0", path = "../../../lib/etc/libimagutil" }

View File

@ -25,7 +25,6 @@ extern crate itertools;
extern crate libimagnotes;
extern crate libimagrt;
extern crate libimagentryedit;
extern crate libimagentrytag;
extern crate libimagerror;
extern crate libimagutil;

View File

@ -19,8 +19,6 @@
use clap::{Arg, App, SubCommand};
use libimagentrytag::ui::tag_argument;
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
app
.subcommand(SubCommand::with_name("create")
@ -62,8 +60,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.required(true)
.help("Edit Note with this name")
.value_name("NAME"))
.arg(tag_argument())
)
.subcommand(SubCommand::with_name("list")

View File

@ -1,46 +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 clap::ArgMatches;
use libimagstore::store::FileLockEntry;
use result::Result;
use tagable::*;
use ui::{get_add_tags, get_remove_tags};
pub fn exec_cli_for_entry(matches: &ArgMatches, entry: &mut FileLockEntry) -> Result<()> {
if let Some(ts) = get_add_tags(matches) {
for t in ts {
if let Err(e) = entry.add_tag(t) {
return Err(e);
}
}
}
if let Some(ts) = get_remove_tags(matches) {
for t in ts {
if let Err(e) = entry.remove_tag(t) {
return Err(e);
}
}
}
Ok(())
}

View File

@ -46,9 +46,7 @@ extern crate libimagstore;
#[macro_use] extern crate libimagerror;
pub mod error;
pub mod exec;
pub mod result;
pub mod tag;
pub mod tagable;
pub mod ui;

View File

@ -1,125 +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 clap::{Arg, ArgMatches, App, SubCommand};
use tag::Tag;
use tag::is_tag;
/// Generates a `clap::SubCommand` to be integrated in the commandline-ui builder for building a
/// "tags --add foo --remove bar" subcommand to do tagging action.
pub fn tag_subcommand<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name(tag_subcommand_name())
.author("Matthias Beyer <mail@beyermatthias.de>")
.version("0.1")
.about("Add or remove tags")
.arg(tag_add_arg())
.arg(tag_remove_arg())
}
pub fn tag_add_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(tag_subcommand_add_arg_name())
.short("a")
.long("add")
.takes_value(true)
.value_name("tags")
.multiple(true)
.validator(is_tag)
.help("Add tags, seperated by comma or by specifying multiple times")
}
pub fn tag_remove_arg<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(tag_subcommand_remove_arg_name())
.short("r")
.long("remove")
.takes_value(true)
.value_name("tags")
.multiple(true)
.validator(is_tag)
.help("Remove tags, seperated by comma or by specifying multiple times")
}
pub fn tag_subcommand_name() -> &'static str {
"tags"
}
pub fn tag_subcommand_add_arg_name() -> &'static str {
"add-tags"
}
pub fn tag_subcommand_remove_arg_name() -> &'static str {
"remove-tags"
}
pub fn tag_subcommand_names() -> Vec<&'static str> {
vec![tag_subcommand_add_arg_name(), tag_subcommand_remove_arg_name()]
}
/// Generates a `clap::Arg` which can be integrated into the commandline-ui builder for building a
/// "-t" or "--tags" argument which takes values for tagging actions (add, remove)
pub fn tag_argument<'a, 'b>() -> Arg<'a, 'b> {
Arg::with_name(tag_argument_name())
.short("t")
.long("tags")
.takes_value(true)
.multiple(true)
.validator(is_tag)
.help("Add or remove tags, prefixed by '+' (for adding) or '-' (for removing)")
}
pub fn tag_argument_name() -> &'static str {
"specify-tags"
}
/// Get the tags which should be added from the commandline
///
/// Returns none if the argument was not specified
pub fn get_add_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
let add = tag_subcommand_add_arg_name();
extract_tags(matches, add, '+')
.or_else(|| matches.values_of(add).map(|values| values.map(String::from).collect()))
}
/// Get the tags which should be removed from the commandline
///
/// Returns none if the argument was not specified
pub fn get_remove_tags(matches: &ArgMatches) -> Option<Vec<Tag>> {
let rem = tag_subcommand_remove_arg_name();
extract_tags(matches, rem, '+')
.or_else(|| matches.values_of(rem).map(|values| values.map(String::from).collect()))
}
fn extract_tags(matches: &ArgMatches, specifier: &str, specchar: char) -> Option<Vec<Tag>> {
if let Some(submatch) = matches.subcommand_matches("tags") {
submatch.values_of(specifier)
.map(|values| values.map(String::from).collect())
} else {
matches.values_of("specify-tags")
.map(|argmatches| {
argmatches
.map(String::from)
.filter(|s| s.starts_with(specchar))
.map(|s| {
String::from(s.split_at(1).1)
})
.collect()
})
}
}