diff --git a/Cargo.lock b/Cargo.lock index 2dbe8fc..f89cee2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,6 +149,15 @@ dependencies = [ "textwrap", ] +[[package]] +name = "clap_complete" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678db4c39c013cc68b54d372bce2efc58e30a0337c497c9032fd196802df3bc3" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "3.0.14" @@ -1036,6 +1045,7 @@ name = "xremap" version = "0.2.5" dependencies = [ "clap", + "clap_complete", "env_logger", "evdev", "indoc", diff --git a/Cargo.toml b/Cargo.toml index 99ab99a..524c485 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT" [dependencies] clap = { version = "3.0.14", features = ["derive"] } +clap_complete = "3.0.6" env_logger = "0.9.0" evdev = "0.11.3" indoc = "1.0" diff --git a/src/main.rs b/src/main.rs index c61c991..9ee3f1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,15 @@ use crate::config::Config; use crate::device::{device_watcher, input_devices, output_device}; use crate::event_handler::EventHandler; -use clap::{ArgEnum, Parser}; +use clap::{AppSettings, ArgEnum, IntoApp, Parser}; +use clap_complete::Shell; use evdev::uinput::VirtualDevice; use evdev::{Device, EventType}; use nix::sys::inotify::Inotify; use nix::sys::select::select; use nix::sys::select::FdSet; use std::error::Error; +use std::io::stdout; use std::os::unix::io::AsRawFd; use std::path::PathBuf; use std::process::exit; @@ -18,7 +20,7 @@ mod device; mod event_handler; #[derive(Parser, Debug)] -#[clap(version)] +#[clap(version, global_setting(AppSettings::DeriveDisplayOrder))] struct Opts { /// Include a device name or path #[clap(long, use_delimiter = true)] @@ -26,6 +28,10 @@ struct Opts { /// Ignore a device name or path #[clap(long, use_delimiter = true)] ignore: Vec, + /// Targets to watch + /// + /// - Device to add new devices automatically + /// - Config to reload the config automatically #[clap( long, arg_enum, @@ -39,13 +45,17 @@ struct Opts { // https://github.com/clap-rs/clap/issues/3312 help = "Targets to watch [possible values: device, config]" )] - /// Targets to watch - /// - /// - Device to add new devices automatically - /// - Config to reload the config automatically watch: Vec, + /// Generate shell completions + /// + /// You can use them by storing in your shells completion file or by running + /// - in bash: eval "$(xremap --completions bash)" + /// - in fish: xremap --completions fish | source + #[clap(long, arg_enum, display_order = 1000, value_name = "SHELL", verbatim_doc_comment)] + completions: Option, /// Config file - config: PathBuf, + #[clap(required_unless_present = "completions")] + config: Option, } #[derive(ArgEnum, Clone, Copy, Debug, PartialEq, Eq)] @@ -64,8 +74,15 @@ fn main() { ignore, watch, config, + completions, } = Opts::parse(); + if let Some(shell) = completions { + return clap_complete::generate(shell, &mut Opts::into_app(), "xremap", &mut stdout()); + } + + let config = config.expect("config is set, if not completions"); + let config = match config::load_config(&config) { Ok(config) => config, Err(e) => abort(&format!("Failed to load config '{}': {}", config.display(), e)),