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 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]>;
|
||||
|
|
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::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();
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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" }
|
||||
|
|
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"),
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
2
build.rs
2
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"])
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue