From 84caa8301a590ad40b6a4c959c44e3480841275e Mon Sep 17 00:00:00 2001 From: shannmu Date: Mon, 9 Sep 2024 23:36:42 +0800 Subject: [PATCH] feat: Add native completions with `CompleteEnv` and under the nightly features --- src/bin/cargo/main.rs | 8 ++ src/doc/src/reference/unstable.md | 25 +++++ tests/testsuite/shell_completions.rs | 131 ++++++++++++++++++++++++++- 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo/main.rs b/src/bin/cargo/main.rs index 5dbf9363460..12c3e0735e1 100644 --- a/src/bin/cargo/main.rs +++ b/src/bin/cargo/main.rs @@ -1,5 +1,6 @@ #![allow(clippy::self_named_module_files)] // false positive in `commands/build.rs` +use cargo::core::features; use cargo::core::shell::Shell; use cargo::util::network::http::http_handle; use cargo::util::network::http::needs_custom_http_transport; @@ -28,6 +29,13 @@ fn main() { } }; + let nightly_features_allowed = matches!(&*features::channel(), "nightly" | "dev"); + if nightly_features_allowed { + clap_complete::CompleteEnv::with_factory(|| cli::cli(&mut gctx)) + .var("CARGO_COMPLETE") + .complete(); + } + let result = if let Some(lock_addr) = cargo::ops::fix_get_proxy_lock_addr() { cargo::ops::fix_exec_rustc(&gctx, &lock_addr).map_err(|e| CliError::from(e)) } else { diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index d9db865403f..ce985b41039 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -117,6 +117,7 @@ Each new feature described below should explain how to use it. * [script](#script) --- Enable support for single-file `.rs` packages. * [lockfile-path](#lockfile-path) --- Allows to specify a path to lockfile other than the default path `/Cargo.lock`. * [package-workspace](#package-workspace) --- Allows for packaging and publishing multiple crates in a workspace. + * [native-completions](#native-completions) --- Move cargo shell completions to native completions. ## allow-features @@ -1686,6 +1687,30 @@ cargo +nightly -Zpackage-workspace --registry=my-registry package -p foo -p dep cargo +nightly -Zpackage-workspace --index=https://example.com package -p foo -p dep ``` +## native-completions +* Original Issue: [#6645](https://github.com/rust-lang/cargo/issues/6645) +* Tracking Issue: [#14520](https://github.com/rust-lang/cargo/issues/14520) + +This feature moves the handwritten completion scripts to Rust native, making it +easier for us to add, extend and test new completions. This feature is enabled with the +nightly channel, without requiring additional `-Z` options. + +### How to use native-completions feature: +- bash: + Add `source <(CARGO_COMPLETE=bash cargo)` to your .bashrc. + +- zsh: + Add `source <(CARGO_COMPLETE=zsh cargo)` to your .zshrc. + +- fish: + Add `source (CARGO_COMPLETE=fish cargo | psub)` to `$XDG_CONFIG_HOME/fish/completions/cargo.fish` + +- elvish: + Add `eval (E:CARGO_COMPLETE=elvish cargo | slurp)` to `$XDG_CONFIG_HOME/elvish/rc.elv` + +- powershell: + Add `CARGO_COMPLETE=powershell cargo | Invoke-Expression` to `$PROFILE`. + # Stabilized and removed features ## Compile progress diff --git a/tests/testsuite/shell_completions.rs b/tests/testsuite/shell_completions.rs index c86dca8aa45..a6802213a25 100644 --- a/tests/testsuite/shell_completions.rs +++ b/tests/testsuite/shell_completions.rs @@ -1,4 +1,134 @@ +#![cfg(unix)] + +use cargo_test_support::cargo_test; use completest_pty::Runtime; +use snapbox::assert_data_eq; + +#[cargo_test] +fn bash() { + let input = "cargo \t\t"; + let expected = snapbox::str![ + "% +--version --help check install read-manifest update +--list -V clean locate-project remove vendor +--explain -v config login report verify-project +--verbose -q doc logout run version +--quiet -C fetch metadata rustc yank +--color -Z fix new rustdoc +--locked -h generate-lockfile owner search +--offline add help package test +--frozen bench info pkgid tree +--config build init publish uninstall " + ]; + let actual = complete(input, "bash"); + assert_data_eq!(actual, expected); +} + +#[cargo_test] +fn elvish() { + let input = "cargo \t\t"; + let expected = snapbox::str![ + "% cargo --config +_COMPLETING argument +--color --version check install read-manifest update +--config -C clean locate-project remove vendor +--explain -V config login report verify-project +--frozen -Z doc logout run version +--help -h fetch metadata rustc yank +--list -q fix new rustdoc +--locked -v generate-lockfile owner search +--offline add help package test +--quiet bench info pkgid tree +--verbose build init publish uninstall " + ]; + let actual = complete(input, "elvish"); + assert_data_eq!(actual, expected); +} + +#[cargo_test] +fn fish() { + let input = "cargo \t\t"; + let expected = snapbox::str![ + "% cargo +--version (Print version info and exit) +--list (List installed commands) +--explain (Provide a detailed explanation of a rustc error message) +--verbose (Use verbose output (-vv very verbose/build.rs output)) +--quiet (Do not print cargo log messages) +--color (Coloring: auto, always, never) +--locked (Assert that `Cargo.lock` will remain unchanged) +--offline (Run without accessing the network) +--frozen (Equivalent to specifying both --locked and --offline) +--config (Override a configuration value) +--help (Print help) +-V (Print version info and exit) +-v (Use verbose output (-vv very verbose/build.rs output)) +-q (Do not print cargo log messages) +-C (Change to DIRECTORY before doing anything (nightly-only)) +-Z (Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details) +-h (Print help) +add (Add dependencies to a Cargo.toml manifest file) +bench (Execute all benchmarks of a local package) +build (Compile a local package and all of its dependencies) +check (Check a local package and all of its dependencies for errors) +clean (Remove artifacts that cargo has generated in the past) +config (Inspect configuration values) +doc (Build a package's documentation) +fetch (Fetch dependencies of a package from the network) +fix (Automatically fix lint warnings reported by rustc) +generate-lockfile (Generate the lockfile for a package) +help (Displays help for a cargo subcommand) +info (Display information about a package in the registry) +init (Create a new cargo package in an existing directory) +install (Install a Rust binary) +locate-project (Print a JSON representation of a Cargo.toml file's location) +login (Log in to a registry.) +logout (Remove an API token from the registry locally) +metadata (Output the resolved dependencies of a package, the concrete used versions including overrides, in machine-r…) +new (Create a new cargo package at ) +owner (Manage the owners of a crate on the registry) +package (Assemble the local package into a distributable tarball) +pkgid (Print a fully qualified package specification) +publish (Upload a package to the registry) +read-manifest (Print a JSON representation of a Cargo.toml manifest.) +remove (Remove dependencies from a Cargo.toml manifest file) +report (Generate and display various kinds of reports) +run (Run a binary or example of the local package) +rustc (Compile a package, and pass extra options to the compiler) +rustdoc (Build a package's documentation, using specified custom flags.) +search (Search packages in the registry. Default registry is crates.io) +test (Execute all unit and integration tests and build examples of a local package) +tree (Display a tree visualization of a dependency graph) +uninstall (Remove a Rust binary) +update (Update dependencies as recorded in the local lock file) +vendor (Vendor all dependencies for a project locally) +verify-project (Check correctness of crate manifest) +version (Show version information) +yank (Remove a pushed crate from the index)"]; + + let actual = complete(input, "fish"); + assert_data_eq!(actual, expected); +} + +#[cargo_test] +fn zsh() { + let input = "cargo \t\t"; + let expected = snapbox::str![ + "% cargo +--color --version check install read-manifest update +--config -C clean locate-project remove vendor +--explain -V config login report verify-project +--frozen -Z doc logout run version +--help -h fetch metadata rustc yank +--list -q fix new rustdoc +--locked -v generate-lockfile owner search +--offline add help package test +--quiet bench info pkgid tree +--verbose build init publish uninstall " + ]; + let actual = complete(input, "zsh"); + assert_data_eq!(actual, expected); +} fn complete(input: &str, shell: &str) -> String { let shell = shell.into(); @@ -53,4 +183,3 @@ source <(CARGO_COMPLETE=zsh cargo)", runtime } -