summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2018-04-14 15:13:27 +0200
committerGitHub <noreply@github.com>2018-04-14 15:13:27 +0200
commit90eb83a538885d8ea548e2f9d6842528d7164cf0 (patch)
tree8746a90c29106352ed43ae8ec5f5f1dce05e569b
parent687bdccac9541b3a8460dec510e62ae36f9cbe26 (diff)
parentfb4917d050f9ec505d140ae0ea26916254fd9a15 (diff)
downloadimag-90eb83a538885d8ea548e2f9d6842528d7164cf0.zip
imag-90eb83a538885d8ea548e2f9d6842528d7164cf0.tar.gz
Merge pull request #1398 from mario-kr/addsh2
Add shell completion via build script (again)
-rw-r--r--bin/core/imag-ids/src/main.rs22
-rw-r--r--bin/core/imag-ids/src/ui.rs40
-rw-r--r--bin/core/imag-init/src/main.rs6
-rw-r--r--bin/core/imag-init/src/ui.rs8
-rw-r--r--bin/core/imag/Cargo.toml9
-rw-r--r--bin/core/imag/build.rs138
-rw-r--r--bin/core/imag/src/main.rs3
-rw-r--r--build.rs2
-rw-r--r--lib/core/libimagrt/src/runtime.rs28
9 files changed, 197 insertions, 59 deletions
diff --git a/bin/core/imag-ids/src/main.rs b/bin/core/imag-ids/src/main.rs
index 5dada73..08beb46 100644
--- a/bin/core/imag-ids/src/main.rs
+++ b/bin/core/imag-ids/src/main.rs
@@ -42,7 +42,6 @@ extern crate libimagstore;
use std::io::Write;
use filters::filter::Filter;
-use clap::{Arg, App};
use libimagrt::setup::generate_runtime_setup;
use libimagerror::trace::MapErrTrace;
@@ -50,26 +49,9 @@ use libimagerror::exit::ExitUnwrap;
use libimagerror::io::ToExitCode;
use libimagstore::storeid::StoreId;
+mod ui;
+use ui::build_ui;
-/// No special CLI
-pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
- app
- .arg(Arg::with_name("print-storepath")
- .long("with-storepath")
- .takes_value(false)
- .required(false)
- .multiple(false)
- .help("Print the storepath for each id"))
-
- .arg(Arg::with_name("in-collection-filter")
- .long("in-collection")
- .short("c")
- .required(false)
- .takes_value(true)
- .multiple(true)
- .value_names(&["COLLECTION"])
- .help("Filter for ids which are only in these collections"))
-}
pub struct IsInCollectionsFilter<'a, A>(Option<A>, ::std::marker::PhantomData<&'a str>)
where A: AsRef<[&'a str]>;
diff --git a/bin/core/imag-ids/src/ui.rs b/bin/core/imag-ids/src/ui.rs
new file mode 100644
index 0000000..000539d
--- /dev/null
+++ b/bin/core/imag-ids/src/ui.rs
@@ -0,0 +1,40 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015-2018 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, App};
+
+pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
+ app
+ .arg(Arg::with_name("print-storepath")
+ .long("with-storepath")
+ .takes_value(false)
+ .required(false)
+ .multiple(false)
+ .help("Print the storepath for each id"))
+
+ .arg(Arg::with_name("in-collection-filter")
+ .long("in-collection")
+ .short("c")
+ .required(false)
+ .takes_value(true)
+ .multiple(true)
+ .value_names(&["COLLECTION"])
+ .help("Filter for ids which are only in these collections"))
+}
+
diff --git a/bin/core/imag-init/src/main.rs b/bin/core/imag-init/src/main.rs
index 2ad1572..de80912 100644
--- a/bin/core/imag-init/src/main.rs
+++ b/bin/core/imag-init/src/main.rs
@@ -50,6 +50,7 @@ use std::process::Command;
use libimagerror::exit::ExitUnwrap;
use libimagerror::io::ToExitCode;
+use libimagrt::runtime::Runtime;
const CONFIGURATION_STR : &'static str = include_str!("../imagrc.toml");
@@ -68,7 +69,10 @@ imagrc.toml
fn main() {
let version = make_imag_version!();
- let app = ui::build_ui(&version);
+ let app = ui::build_ui(Runtime::get_default_cli_builder(
+ "imag-init",
+ version.as_str(),
+ "Intializes the imag store, optionally with git"));
let matches = app.get_matches();
let mut out = ::std::io::stdout();
diff --git a/bin/core/imag-init/src/ui.rs b/bin/core/imag-init/src/ui.rs
index ff98529..7936cc9 100644
--- a/bin/core/imag-init/src/ui.rs
+++ b/bin/core/imag-init/src/ui.rs
@@ -19,12 +19,8 @@
use clap::{Arg, App};
-pub fn build_ui<'a>(version: &'a str) -> App<'a, 'a> {
- App::new("imag-init")
- .version(version)
- .author("Matthias Beyer <mail@beyermatthias.de>")
- .about("Initialize a ~/.imag repository. Optionally with git")
-
+pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
+ app
.arg(Arg::with_name("devel")
.long("dev")
.takes_value(false)
diff --git a/bin/core/imag/Cargo.toml b/bin/core/imag/Cargo.toml
index e0770a6..b8c4f8b 100644
--- a/bin/core/imag/Cargo.toml
+++ b/bin/core/imag/Cargo.toml
@@ -13,7 +13,14 @@ documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.h
repository = "https://github.com/matthiasbeyer/imag"
homepage = "http://imag-pim.org"
-build = "../../../build.rs"
+build = "build.rs"
+
+[build-dependencies]
+clap = ">=2.16.1"
+version = "2.0"
+libimagrt = { path = "../../../lib/core/libimagrt" }
+libimagentrytag = { path = "../../../lib/entry/libimagentrytag" }
+libimagutil = { path = "../../../lib/etc/libimagutil" }
[badges]
travis-ci = { repository = "matthiasbeyer/imag" }
diff --git a/bin/core/imag/build.rs b/bin/core/imag/build.rs
new file mode 100644
index 0000000..96dabc3
--- /dev/null
+++ b/bin/core/imag/build.rs
@@ -0,0 +1,138 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015-2018 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
+//
+
+extern crate clap;
+extern crate libimagrt;
+extern crate libimagentrytag;
+extern crate libimagutil;
+#[macro_use] extern crate version;
+
+use clap::Shell;
+use libimagrt::runtime::Runtime;
+
+mod toplevelbuildscript {
+ include!("../../../build.rs");
+ pub fn build() {
+ self::main();
+ }
+}
+
+/// This macro generates mods with the given '$modulename',
+/// whose content is the file given with `$path`.
+/// In this case, It is used specifically to include the
+/// `ui.rs` files of the imag binaries.
+/// The imag project (accidentally?) followed the convention
+/// to write a `ui.rs` containing the function
+/// `fn build_ui(app : App) -> App`.
+/// This macro allows us to use the same named functions by
+/// putting them each into their own module.
+macro_rules! gen_mods_buildui {
+ ($(($path:expr, $modulename:ident)$(,)*)*) => (
+ $(
+ mod $modulename {
+ include!($path);
+ }
+ )*
+ )
+}
+
+/// This macro reduces boilerplate code.
+///
+/// For example: `build_subcommand!("counter", imagcounter)`
+/// will result in the following code:
+/// ```ignore
+/// imagcounter::build_ui(Runtime::get_default_cli_builder(
+/// "counter",
+/// &version!()[..],
+/// "counter"))
+/// ```
+/// As for the `&version!()[..]` part, it does not matter
+/// which version the subcommand is getting here, as the
+/// output of this script is a completion script, which
+/// does not contain information about the version at all.
+macro_rules! build_subcommand {
+ ($name:expr, $module:ident) => (
+ $module::build_ui(Runtime::get_default_cli_builder($name, &version!()[..], $name))
+ )
+}
+
+// Actually generates the module.
+gen_mods_buildui!(
+ ("../../../bin/core/imag-annotate/src/ui.rs", imagannotate),
+ ("../../../bin/core/imag-diagnostics/src/ui.rs", imagdiagnostics),
+ ("../../../bin/core/imag-edit/src/ui.rs", imagedit),
+ ("../../../bin/core/imag-gps/src/ui.rs", imaggps),
+ ("../../../bin/core/imag-grep/src/ui.rs", imaggrep),
+ ("../../../bin/core/imag-ids/src/ui.rs", imagids),
+ ("../../../bin/core/imag-init/src/ui.rs", imaginit),
+ ("../../../bin/core/imag-link/src/ui.rs", imaglink),
+ ("../../../bin/core/imag-mv/src/ui.rs", imagmv),
+ ("../../../bin/core/imag-ref/src/ui.rs", imagref),
+ ("../../../bin/core/imag-store/src/ui.rs", imagstore),
+ ("../../../bin/core/imag-tag/src/ui.rs", imagtag),
+ ("../../../bin/core/imag-view/src/ui.rs", imagview)
+ ("../../../bin/domain/imag-bookmark/src/ui.rs", imagbookmark),
+ ("../../../bin/domain/imag-contact/src/ui.rs", imagcontact),
+ ("../../../bin/domain/imag-diary/src/ui.rs", imagdiary),
+ ("../../../bin/domain/imag-habit/src/ui.rs", imaghabit),
+ ("../../../bin/domain/imag-log/src/ui.rs", imaglog),
+ ("../../../bin/domain/imag-mail/src/ui.rs", imagmail),
+ ("../../../bin/domain/imag-notes/src/ui.rs", imagnotes),
+ ("../../../bin/domain/imag-timetrack/src/ui.rs", imagtimetrack),
+ ("../../../bin/domain/imag-todo/src/ui.rs", imagtodo),
+);
+
+fn main() {
+ // Make the `imag`-App...
+ let mut app = Runtime::get_default_cli_builder(
+ "imag",
+ &version!()[..],
+ "imag")
+ // and add all the subapps as subcommands.
+ .subcommand(build_subcommand!("annotate", imagannotate))
+ .subcommand(build_subcommand!("diagnostics", imagdiagnostics))
+ .subcommand(build_subcommand!("edit", imagedit))
+ .subcommand(build_subcommand!("gps", imaggps))
+ .subcommand(build_subcommand!("grep", imaggrep))
+ .subcommand(build_subcommand!("ids", imagids))
+ .subcommand(build_subcommand!("init", imaginit))
+ .subcommand(build_subcommand!("link", imaglink))
+ .subcommand(build_subcommand!("mv", imagmv))
+ .subcommand(build_subcommand!("ref", imagref))
+ .subcommand(build_subcommand!("store", imagstore))
+ .subcommand(build_subcommand!("tag", imagtag))
+ .subcommand(build_subcommand!("view", imagview))
+ .subcommand(build_subcommand!("bookmark", imagbookmark))
+ .subcommand(build_subcommand!("contact", imagcontact))
+ .subcommand(build_subcommand!("diary", imagdiary))
+ .subcommand(build_subcommand!("habit", imaghabit))
+ .subcommand(build_subcommand!("log", imaglog))
+ .subcommand(build_subcommand!("mail", imagmail))
+ .subcommand(build_subcommand!("notes", imagnotes))
+ .subcommand(build_subcommand!("timetrack", imagtimetrack))
+ .subcommand(build_subcommand!("todo", imagtodo));
+
+ // Actually generates the completion files
+ app.gen_completions("imag", Shell::Bash, "../../../target/");
+ app.gen_completions("imag", Shell::Fish, "../../../target/");
+ app.gen_completions("imag", Shell::Zsh, "../../../target/");
+
+ toplevelbuildscript::build();
+}
+
diff --git a/bin/core/imag/src/main.rs b/bin/core/imag/src/main.rs
index a83cc23..a847af0 100644
--- a/bin/core/imag/src/main.rs
+++ b/bin/core/imag/src/main.rs
@@ -407,9 +407,6 @@ fn forward_commandline_arguments(m: &ArgMatches, scmd: &mut Vec<String>) {
push(Some("editor"),
Runtime::arg_editor_name(), m , scmd);
- push(Some("generate-commandline-completion"),
- Runtime::arg_generate_compl(), m , scmd);
-
push(None , Runtime::arg_logdest_name() , m , scmd);
}
diff --git a/build.rs b/build.rs
index c2c4ec6..4aa730f 100644
--- a/build.rs
+++ b/build.rs
@@ -19,7 +19,7 @@
use std::process::Command;
fn main() {
- let profile = String::from(std::env::var("PROFILE").unwrap());
+ let profile = String::from(::std::env::var("PROFILE").unwrap());
let git_version = if profile == "debug" {
let output = Command::new("git")
.args(&["describe", "HEAD"])
diff --git a/lib/core/libimagrt/src/runtime.rs b/lib/core/libimagrt/src/runtime.rs
index c0e8488..a51fe8c 100644
--- a/lib/core/libimagrt/src/runtime.rs
+++ b/lib/core/libimagrt/src/runtime.rs
@@ -111,27 +111,14 @@ impl<'a> Runtime<'a> {
Runtime::_new(cli_app, matches, config)
}
- fn _new<C>(mut cli_app: C, matches: ArgMatches<'a>, config: Option<Value>)
+ fn _new<C>(cli_app: C, matches: ArgMatches<'a>, config: Option<Value>)
-> Result<Runtime<'a>, RuntimeError>
where C: Clone + CliSpec<'a> + InternalConfiguration
{
- use std::io::stdout;
- use clap::Shell;
-
if cli_app.enable_logging() {
Runtime::init_logger(&matches, config.as_ref())
}
- match matches.value_of(Runtime::arg_generate_compl()) {
- Some(shell) => {
- debug!("Generating shell completion script, writing to stdout");
- let shell = shell.parse::<Shell>().unwrap(); // clap has our back here.
- let appname = String::from(cli_app.name());
- cli_app.completions(appname, shell, &mut stdout());
- },
- _ => debug!("Not generating shell completion script"),
- }
-
let rtp = get_rtp_match(&matches);
let storepath = matches.value_of(Runtime::arg_storepath_name())
@@ -242,14 +229,6 @@ impl<'a> Runtime<'a> {
.required(false)
.takes_value(true))
- .arg(Arg::with_name(Runtime::arg_generate_compl())
- .long("generate-commandline-completion")
- .help("Generate the commandline completion for bash or zsh or fish")
- .required(false)
- .takes_value(true)
- .value_name("SHELL")
- .possible_values(&["bash", "fish", "zsh"]))
-
.arg(Arg::with_name(Runtime::arg_logdest_name())
.long(Runtime::arg_logdest_name())
.help("Override the logging destinations from the configuration: values can be seperated by ',', a value of '-' marks the stderr output, everything else is expected to be a path")
@@ -320,11 +299,6 @@ impl<'a> Runtime<'a> {
"editor"
}
- /// Get the argument name for generating the completion
- pub fn arg_generate_compl() -> &'static str {
- "generate-completion"
- }
-
/// Extract the Store object from the Runtime object, destroying the Runtime object
///
/// # Warning