From 6dd16415317dd44a019ae3c98fa3b78f027875f9 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Fri, 13 Jun 2025 21:17:41 -0400 Subject: [PATCH 1/2] feat: Add shell completion via clap_complete --- Cargo.lock | 30 ++++++++++++++++++++---------- Cargo.toml | 1 + src/bin/nix-channel-index.rs | 13 ++++++++++++- src/bin/nix-index.rs | 12 +++++++++++- src/bin/nix-locate.rs | 19 +++++++++++++++++-- 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 669c6c0..82a0c67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" @@ -249,9 +249,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.4" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -259,9 +259,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -269,11 +269,20 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", @@ -283,9 +292,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" @@ -1050,6 +1059,7 @@ dependencies = [ "bincode", "byteorder", "clap", + "clap_complete", "error-chain", "futures", "grep", diff --git a/Cargo.toml b/Cargo.toml index 46e3718..0e6220c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ xdg = "2.5.2" xml-rs = "0.8.20" xz2 = "0.1.7" zstd = { version = "0.12.4", features = [ "zstdmt" ] } +clap_complete = "4.5.54" [dependencies.hyper] features = ["client", "http1", "http2", "runtime", "stream"] diff --git a/src/bin/nix-channel-index.rs b/src/bin/nix-channel-index.rs index 75de785..f46a238 100644 --- a/src/bin/nix-channel-index.rs +++ b/src/bin/nix-channel-index.rs @@ -5,7 +5,8 @@ use std::os::unix::ffi::OsStringExt; use std::path::PathBuf; use std::process; -use clap::Parser; +use clap::{CommandFactory, Parser}; +use clap_complete::{generate, Shell}; use error_chain::ChainedError; use futures::{future, StreamExt}; use nix_index::files::FileNode; @@ -179,11 +180,21 @@ struct Args { /// Show a stack trace in the case of a Nix evaluation error #[clap(long)] show_trace: bool, + + /// Generate shell completions to stdout. + #[clap(long)] + completions: Option } #[tokio::main] async fn main() { let args = Args::parse(); + + if let Some(shell) = args.completions { + generate(shell, &mut Args::command(), "nix-channel-index", &mut io::stdout()); + return; + } + if let Err(e) = update_index(&args).await { eprintln!("error: {}", e); diff --git a/src/bin/nix-index.rs b/src/bin/nix-index.rs index 004e0e0..5bb69e8 100644 --- a/src/bin/nix-index.rs +++ b/src/bin/nix-index.rs @@ -5,7 +5,8 @@ use std::io::{self, Write}; use std::path::PathBuf; use std::process; -use clap::Parser; +use clap::{CommandFactory, Parser}; +use clap_complete::{generate, Shell}; use error_chain::ChainedError; use futures::future::Either; use futures::{future, StreamExt}; @@ -153,12 +154,21 @@ struct Args { /// Note: does not check if the cached data is up to date! Use only for development. #[clap(long)] path_cache: bool, + + /// Generate shell completions to stdout. + #[clap(long)] + completions: Option } #[tokio::main] async fn main() { let args = Args::parse(); + if let Some(shell) = args.completions { + generate(shell, &mut Args::command(), "nix-index", &mut io::stdout()); + return; + } + if let Err(e) = update_index(&args).await { eprintln!("error: {}", e); diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index 2c18747..c3c4d29 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -1,13 +1,17 @@ //! Tool for searching for files in nixpkgs packages use std::collections::HashSet; use std::ffi::OsStr; +use std::io; use std::path::PathBuf; use std::process; use std::result; use std::str; use std::str::FromStr; +use clap::CommandFactory; use clap::{value_parser, Parser}; +use clap_complete::generate; +use clap_complete::Shell; use error_chain::error_chain; use nix_index::database; use nix_index::files::{self, FileTreeEntry, FileType}; @@ -153,7 +157,9 @@ fn locate(args: &Args) -> Result<()> { /// /// Handles parsing the values of more complex arguments. fn process_args(matches: Opts) -> result::Result { - let pattern_arg = matches.pattern; + let pattern_arg = matches + .pattern + .ok_or(Opts::command().error(clap::error::ErrorKind::MissingRequiredArgument, "The argument is missing"))?; let package_arg = matches.package; let start_anchor = if matches.at_root { "^" } else { "" }; @@ -237,7 +243,7 @@ fn cache_dir() -> &'static OsStr { struct Opts { /// Pattern for which to search // #[clap(name = "PATTERN")] - pattern: String, + pattern: Option, /// Directory where the index is stored #[clap(short, long = "db", default_value_os = cache_dir(), env = "NIX_INDEX_DATABASE")] @@ -293,6 +299,10 @@ struct Opts { /// store path are omitted. This is useful for scripts that use the output of nix-locate. #[clap(long)] minimal: bool, + + /// Generate shell completions to stdout. + #[clap(long)] + completions: Option, } #[derive(clap::ValueEnum, Clone, Copy, Debug)] @@ -318,6 +328,11 @@ impl FromStr for Color { fn main() { let args = Opts::parse(); + if let Some(shell) = args.completions { + generate(shell, &mut Opts::command(), "nix-locate", &mut io::stdout()); + return; + } + let args = process_args(args).unwrap_or_else(|e| e.exit()); if let Err(e) = locate(&args) { From 9689bfc49edb513591c7d8334d743816cabaf6c5 Mon Sep 17 00:00:00 2001 From: sadan <117494111+sadan4@users.noreply.github.com> Date: Fri, 13 Jun 2025 21:27:45 -0400 Subject: [PATCH 2/2] fix format --- src/bin/nix-channel-index.rs | 12 ++++++++---- src/bin/nix-index.rs | 2 +- src/bin/nix-locate.rs | 7 ++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/bin/nix-channel-index.rs b/src/bin/nix-channel-index.rs index f46a238..e847e23 100644 --- a/src/bin/nix-channel-index.rs +++ b/src/bin/nix-channel-index.rs @@ -183,19 +183,23 @@ struct Args { /// Generate shell completions to stdout. #[clap(long)] - completions: Option + completions: Option, } #[tokio::main] async fn main() { let args = Args::parse(); - + if let Some(shell) = args.completions { - generate(shell, &mut Args::command(), "nix-channel-index", &mut io::stdout()); + generate( + shell, + &mut Args::command(), + "nix-channel-index", + &mut io::stdout(), + ); return; } - if let Err(e) = update_index(&args).await { eprintln!("error: {}", e); diff --git a/src/bin/nix-index.rs b/src/bin/nix-index.rs index 5bb69e8..627b14e 100644 --- a/src/bin/nix-index.rs +++ b/src/bin/nix-index.rs @@ -157,7 +157,7 @@ struct Args { /// Generate shell completions to stdout. #[clap(long)] - completions: Option + completions: Option, } #[tokio::main] diff --git a/src/bin/nix-locate.rs b/src/bin/nix-locate.rs index c3c4d29..5986041 100644 --- a/src/bin/nix-locate.rs +++ b/src/bin/nix-locate.rs @@ -157,9 +157,10 @@ fn locate(args: &Args) -> Result<()> { /// /// Handles parsing the values of more complex arguments. fn process_args(matches: Opts) -> result::Result { - let pattern_arg = matches - .pattern - .ok_or(Opts::command().error(clap::error::ErrorKind::MissingRequiredArgument, "The argument is missing"))?; + let pattern_arg = matches.pattern.ok_or(Opts::command().error( + clap::error::ErrorKind::MissingRequiredArgument, + "The argument is missing", + ))?; let package_arg = matches.package; let start_anchor = if matches.at_root { "^" } else { "" };