Merge pull request #1398 from mario-kr/addsh2
Add shell completion via build script (again)
This commit is contained in:
commit
90eb83a538
9 changed files with 197 additions and 59 deletions
|
@ -42,7 +42,6 @@ extern crate libimagstore;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use filters::filter::Filter;
|
use filters::filter::Filter;
|
||||||
use clap::{Arg, App};
|
|
||||||
|
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
use libimagerror::trace::MapErrTrace;
|
use libimagerror::trace::MapErrTrace;
|
||||||
|
@ -50,26 +49,9 @@ use libimagerror::exit::ExitUnwrap;
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
use libimagstore::storeid::StoreId;
|
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>)
|
pub struct IsInCollectionsFilter<'a, A>(Option<A>, ::std::marker::PhantomData<&'a str>)
|
||||||
where A: AsRef<[&'a str]>;
|
where A: AsRef<[&'a str]>;
|
||||||
|
|
40
bin/core/imag-ids/src/ui.rs
Normal file
40
bin/core/imag-ids/src/ui.rs
Normal file
|
@ -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"))
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ use std::process::Command;
|
||||||
|
|
||||||
use libimagerror::exit::ExitUnwrap;
|
use libimagerror::exit::ExitUnwrap;
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
|
use libimagrt::runtime::Runtime;
|
||||||
|
|
||||||
const CONFIGURATION_STR : &'static str = include_str!("../imagrc.toml");
|
const CONFIGURATION_STR : &'static str = include_str!("../imagrc.toml");
|
||||||
|
|
||||||
|
@ -68,7 +69,10 @@ imagrc.toml
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let version = make_imag_version!();
|
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 matches = app.get_matches();
|
||||||
let mut out = ::std::io::stdout();
|
let mut out = ::std::io::stdout();
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,8 @@
|
||||||
|
|
||||||
use clap::{Arg, App};
|
use clap::{Arg, App};
|
||||||
|
|
||||||
pub fn build_ui<'a>(version: &'a str) -> App<'a, 'a> {
|
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
App::new("imag-init")
|
app
|
||||||
.version(version)
|
|
||||||
.author("Matthias Beyer <mail@beyermatthias.de>")
|
|
||||||
.about("Initialize a ~/.imag repository. Optionally with git")
|
|
||||||
|
|
||||||
.arg(Arg::with_name("devel")
|
.arg(Arg::with_name("devel")
|
||||||
.long("dev")
|
.long("dev")
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
|
|
|
@ -13,7 +13,14 @@ documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.h
|
||||||
repository = "https://github.com/matthiasbeyer/imag"
|
repository = "https://github.com/matthiasbeyer/imag"
|
||||||
homepage = "http://imag-pim.org"
|
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]
|
[badges]
|
||||||
travis-ci = { repository = "matthiasbeyer/imag" }
|
travis-ci = { repository = "matthiasbeyer/imag" }
|
||||||
|
|
138
bin/core/imag/build.rs
Normal file
138
bin/core/imag/build.rs
Normal file
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -407,9 +407,6 @@ fn forward_commandline_arguments(m: &ArgMatches, scmd: &mut Vec<String>) {
|
||||||
push(Some("editor"),
|
push(Some("editor"),
|
||||||
Runtime::arg_editor_name(), m , scmd);
|
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);
|
push(None , Runtime::arg_logdest_name() , m , scmd);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
2
build.rs
2
build.rs
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
fn main() {
|
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 git_version = if profile == "debug" {
|
||||||
let output = Command::new("git")
|
let output = Command::new("git")
|
||||||
.args(&["describe", "HEAD"])
|
.args(&["describe", "HEAD"])
|
||||||
|
|
|
@ -111,27 +111,14 @@ impl<'a> Runtime<'a> {
|
||||||
Runtime::_new(cli_app, matches, config)
|
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>
|
-> Result<Runtime<'a>, RuntimeError>
|
||||||
where C: Clone + CliSpec<'a> + InternalConfiguration
|
where C: Clone + CliSpec<'a> + InternalConfiguration
|
||||||
{
|
{
|
||||||
use std::io::stdout;
|
|
||||||
use clap::Shell;
|
|
||||||
|
|
||||||
if cli_app.enable_logging() {
|
if cli_app.enable_logging() {
|
||||||
Runtime::init_logger(&matches, config.as_ref())
|
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 rtp = get_rtp_match(&matches);
|
||||||
|
|
||||||
let storepath = matches.value_of(Runtime::arg_storepath_name())
|
let storepath = matches.value_of(Runtime::arg_storepath_name())
|
||||||
|
@ -242,14 +229,6 @@ impl<'a> Runtime<'a> {
|
||||||
.required(false)
|
.required(false)
|
||||||
.takes_value(true))
|
.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())
|
.arg(Arg::with_name(Runtime::arg_logdest_name())
|
||||||
.long(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")
|
.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"
|
"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
|
/// Extract the Store object from the Runtime object, destroying the Runtime object
|
||||||
///
|
///
|
||||||
/// # Warning
|
/// # Warning
|
||||||
|
|
Loading…
Reference in a new issue