Introduce CLI completion support

This is yet another attempt to bring CLI completion to this workspace
project.

It uses the subcommand-libraries implementing the ImagApplication
trait to expose the clap CLI interface. This way, no file import magic
happens, it's all just regular dependencies, which should also work
with a regular `cargo install`.

Signed-off-by: Leon Schuermann <leon@is.currently.online>
This commit is contained in:
Leon Schuermann 2019-09-14 19:02:17 +02:00 committed by Matthias Beyer
parent e840d4502c
commit 82e209bea8
2 changed files with 233 additions and 0 deletions

View file

@ -23,6 +23,31 @@ libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
failure = "0.1.5"
log = "0.4.6"
# Build time dependencies for cli completion
imag-annotate = { optional = true, path = "../imag-annotate" }
imag-diagnostics = { optional = true, path = "../imag-diagnostics" }
imag-edit = { optional = true, path = "../imag-edit" }
imag-gps = { optional = true, path = "../imag-gps" }
imag-grep = { optional = true, path = "../imag-grep" }
imag-ids = { optional = true, path = "../imag-ids" }
imag-init = { optional = true, path = "../imag-init" }
imag-link = { optional = true, path = "../imag-link" }
imag-mv = { optional = true, path = "../imag-mv" }
imag-ref = { optional = true, path = "../imag-ref" }
imag-store = { optional = true, path = "../imag-store" }
imag-tag = { optional = true, path = "../imag-tag" }
imag-view = { optional = true, path = "../imag-view" }
imag-bookmark = { optional = true, path = "../../domain/imag-bookmark" }
imag-contact = { optional = true, path = "../../domain/imag-contact" }
imag-diary = { optional = true, path = "../../domain/imag-diary" }
imag-habit = { optional = true, path = "../../domain/imag-habit" }
imag-log = { optional = true, path = "../../domain/imag-log" }
imag-mail = { optional = true, path = "../../domain/imag-mail" }
imag-notes = { optional = true, path = "../../domain/imag-notes" }
imag-timetrack = { optional = true, path = "../../domain/imag-timetrack" }
imag-todo = { optional = true, path = "../../domain/imag-todo" }
imag-wiki = { optional = true, path = "../../domain/imag-wiki" }
[badges]
travis-ci = { repository = "matthiasbeyer/imag" }
is-it-maintained-issue-resolution = { repository = "matthiasbeyer/imag" }
@ -48,3 +73,55 @@ version = "0.10.0"
path = "../../../lib/core/libimagrt"
features = ["pub_logging_initialization"]
[features]
default = [ "cc-all" ]
# Features for enabling cli completion files for individual subcommands
cc-all = [
"cc-imag-annotate",
"cc-imag-diagnostics",
"cc-imag-edit",
"cc-imag-gps",
"cc-imag-grep",
"cc-imag-ids",
"cc-imag-init",
"cc-imag-link",
"cc-imag-mv",
"cc-imag-ref",
"cc-imag-store",
"cc-imag-tag",
"cc-imag-view",
"cc-imag-bookmark",
"cc-imag-contact",
"cc-imag-diary",
"cc-imag-habit",
"cc-imag-log",
"cc-imag-mail",
"cc-imag-notes",
"cc-imag-timetrack",
"cc-imag-todo",
"cc-imag-wiki",
]
cc-imag-annotate = [ "imag-annotate" ]
cc-imag-diagnostics = [ "imag-diagnostics" ]
cc-imag-edit = [ "imag-edit" ]
cc-imag-gps = [ "imag-gps" ]
cc-imag-grep = [ "imag-grep" ]
cc-imag-ids = [ "imag-ids" ]
cc-imag-init = [ "imag-init" ]
cc-imag-link = [ "imag-link" ]
cc-imag-mv = [ "imag-mv" ]
cc-imag-ref = [ "imag-ref" ]
cc-imag-store = [ "imag-store" ]
cc-imag-tag = [ "imag-tag" ]
cc-imag-view = [ "imag-view" ]
cc-imag-bookmark = [ "imag-bookmark" ]
cc-imag-contact = [ "imag-contact" ]
cc-imag-diary = [ "imag-diary" ]
cc-imag-habit = [ "imag-habit" ]
cc-imag-log = [ "imag-log" ]
cc-imag-mail = [ "imag-mail" ]
cc-imag-notes = [ "imag-notes" ]
cc-imag-timetrack = [ "imag-timetrack" ]
cc-imag-todo = [ "imag-todo" ]
cc-imag-wiki = [ "imag-wiki" ]

156
bin/core/imag/build.rs Normal file
View file

@ -0,0 +1,156 @@
//
// 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
//
extern crate clap;
extern crate libimagrt;
extern crate libimagentrytag;
extern crate libimagutil;
use clap::Shell;
use libimagrt::runtime::Runtime;
#[allow(unused_imports)]
use libimagrt::application::ImagApplication;
#[cfg(feature = "cc-imag-annotate")]
extern crate libimagannotatecmd;
#[cfg(feature = "cc-imag-diagnostics")]
extern crate libimagdiagnosticscmd;
#[cfg(feature = "cc-imag-edit")]
extern crate libimageditcmd;
#[cfg(feature = "cc-imag-gps")]
extern crate libimaggpscmd;
#[cfg(feature = "cc-imag-grep")]
extern crate libimaggrepcmd;
#[cfg(feature = "cc-imag-ids")]
extern crate libimagidscmd;
#[cfg(feature = "cc-imag-init")]
extern crate libimaginitcmd;
#[cfg(feature = "cc-imag-link")]
extern crate libimaglinkcmd;
#[cfg(feature = "cc-imag-mv")]
extern crate libimagmvcmd;
#[cfg(feature = "cc-imag-ref")]
extern crate libimagrefcmd;
#[cfg(feature = "cc-imag-store")]
extern crate libimagstorecmd;
#[cfg(feature = "cc-imag-tag")]
extern crate libimagtagcmd;
#[cfg(feature = "cc-imag-view")]
extern crate libimagviewcmd;
#[cfg(feature = "cc-imag-bookmark")]
extern crate libimagbookmarkfrontend;
#[cfg(feature = "cc-imag-contact")]
extern crate libimagcontactfrontend;
#[cfg(feature = "cc-imag-diary")]
extern crate libimagdiaryfrontend;
#[cfg(feature = "cc-imag-habit")]
extern crate libimaghabitfrontend;
#[cfg(feature = "cc-imag-log")]
extern crate libimaglogfrontend;
#[cfg(feature = "cc-imag-mail")]
extern crate libimagmailfrontend;
#[cfg(feature = "cc-imag-notes")]
extern crate libimagnotesfrontend;
#[cfg(feature = "cc-imag-timetrack")]
extern crate libimagtimetrackfrontend;
#[cfg(feature = "cc-imag-todo")]
extern crate libimagtodofrontend;
/// This macro reduces boilerplate code.
///
/// For example: `build_subcommand!("counter", libbinimagcounter, ImagCounter)`
/// will result in the following code:
/// ```ignore
/// ImagCounter::build_cli(Runtime::get_default_cli_builder(
/// "counter",
/// "abc",
/// "counter"))
/// ```
/// As for the `"abc"` 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.
#[allow(unused_macros)]
macro_rules! build_subcommand {
($name:expr, $lib:ident, $implementor:ident) => (
$lib::$implementor::build_cli(Runtime::get_default_cli_builder($name, "abc", $name))
)
}
fn main() {
// Make the `imag`-App...
let app = Runtime::get_default_cli_builder(
"imag",
"abc",
"imag");
// and add all the subapps as subcommands.
// TODO: This feels tedious, can we automate this?
#[cfg(feature = "cc-imag-annotate")]
let app = app.subcommand(build_subcommand!("annotate", libimagannotatecmd, ImagAnnotate));
#[cfg(feature = "cc-imag-diagnostics")]
let app = app.subcommand(build_subcommand!("diagnostics", libimagdiagnosticscmd, ImagDiagnostics));
#[cfg(feature = "cc-imag-edit")]
let app = app.subcommand(build_subcommand!("edit", libimageditcmd, ImagEdit));
#[cfg(feature = "cc-imag-gps")]
let app = app.subcommand(build_subcommand!("gps", libimaggpscmd, ImagGps));
#[cfg(feature = "cc-imag-grep")]
let app = app.subcommand(build_subcommand!("grep", libimaggrepcmd, ImagGrep));
#[cfg(feature = "cc-imag-ids")]
let app = app.subcommand(build_subcommand!("ids", libimagidscmd, ImagIds));
#[cfg(feature = "cc-imag-init")]
let app = app.subcommand(build_subcommand!("init", libimaginitcmd, ImagInit));
#[cfg(feature = "cc-imag-link")]
let app = app.subcommand(build_subcommand!("link", libimaglinkcmd, ImagLink));
#[cfg(feature = "cc-imag-mv")]
let app = app.subcommand(build_subcommand!("mv", libimagmvcmd, ImagMv));
#[cfg(feature = "cc-imag-ref")]
let app = app.subcommand(build_subcommand!("ref", libimagrefcmd, ImagRef));
#[cfg(feature = "cc-imag-store")]
let app = app.subcommand(build_subcommand!("store", libimagstorecmd, ImagStore));
#[cfg(feature = "cc-imag-tag")]
let app = app.subcommand(build_subcommand!("tag", libimagtagcmd, ImagTag));
#[cfg(feature = "cc-imag-view")]
let app = app.subcommand(build_subcommand!("view", libimagviewcmd, ImagView));
#[cfg(feature = "cc-imag-bookmark")]
let app = app.subcommand(build_subcommand!("bookmark", libimagbookmarkfrontend, ImagBookmark));
#[cfg(feature = "cc-imag-contact")]
let app = app.subcommand(build_subcommand!("contact", libimagcontactfrontend, ImagContact));
#[cfg(feature = "cc-imag-diary")]
let app = app.subcommand(build_subcommand!("diary", libimagdiaryfrontend, ImagDiary));
#[cfg(feature = "cc-imag-habit")]
let app = app.subcommand(build_subcommand!("habit", libimaghabitfrontend, ImagHabit));
#[cfg(feature = "cc-imag-log")]
let app = app.subcommand(build_subcommand!("log", libimaglogfrontend, ImagLog));
#[cfg(feature = "cc-imag-mail")]
let app = app.subcommand(build_subcommand!("mail", libimagmailfrontend, ImagMail));
#[cfg(feature = "cc-imag-notes")]
let app = app.subcommand(build_subcommand!("notes", libimagnotesfrontend, ImagNotes));
#[cfg(feature = "cc-imag-timetrack")]
let app = app.subcommand(build_subcommand!("timetrack", libimagtimetrackfrontend, ImagTimetrack));
#[cfg(feature = "cc-imag-todo")]
let app = app.subcommand(build_subcommand!("todo", libimagtodofrontend, ImagTodo));
let mut app = app;
// 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/");
}