Add shell-completions for dx (#5232)
* add naive shell completion using clap_complete * first pass completions * simpler toggle --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
d8026f8824
commit
689e39b3f6
7 files changed
+91
-17
No files matched your search
Generated
+22
@@ -3452,6 +3452,18 @@ dependencies = [
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19c9f1dde76b736e3681f28cec9d5a61299cbaae0fce80a68e43724ad56031eb"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_lex",
|
||||
"is_executable",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.61"
|
||||
@@ -4855,6 +4867,7 @@ dependencies = [
|
||||
"cargo_toml",
|
||||
"chrono",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"codemap",
|
||||
"console 0.16.3",
|
||||
"console-subscriber",
|
||||
@@ -9142,6 +9155,15 @@ version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
|
||||
|
||||
[[package]]
|
||||
name = "is_executable"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
|
||||
@@ -169,6 +169,7 @@ nucleo = "0.5.0"
|
||||
|
||||
# 0.5.12 rust-version is too high
|
||||
home = "=0.5.11"
|
||||
clap_complete = { version = "4.5.65", features = ["unstable-dynamic"] }
|
||||
|
||||
[target.'cfg(target_env = "musl")'.dependencies]
|
||||
git2 = { version = "0.20.2", features = ["vendored-libgit2"] }
|
||||
|
||||
@@ -14,6 +14,7 @@ pub(crate) mod platform_override;
|
||||
pub(crate) mod print;
|
||||
pub(crate) mod run;
|
||||
pub(crate) mod serve;
|
||||
pub(crate) mod shell_completions;
|
||||
pub(crate) mod target;
|
||||
pub(crate) mod translate;
|
||||
pub(crate) mod update;
|
||||
@@ -84,6 +85,10 @@ pub(crate) enum Commands {
|
||||
#[clap(name = "doctor")]
|
||||
Doctor(doctor::Doctor),
|
||||
|
||||
/// Print shell completions for the given shell.
|
||||
#[clap(name = "completions")]
|
||||
ShellCompletions(shell_completions::ShellCompletions),
|
||||
|
||||
/// Print project information in a structured format, like cargo args, linker args, and other
|
||||
/// flags DX sets that might be useful in third-party tools.
|
||||
#[clap(name = "print")]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
use crate::Anonymized;
|
||||
use crate::{shell_completions::GENERATING_COMPLETIONS, Anonymized};
|
||||
use clap::parser::ValueSource;
|
||||
use clap::{ArgMatches, Args, CommandFactory, FromArgMatches, Parser, Subcommand};
|
||||
use serde_json::{json, Value};
|
||||
@@ -159,9 +159,14 @@ where
|
||||
U: Subcommand,
|
||||
{
|
||||
fn augment_args(cmd: clap::Command) -> clap::Command {
|
||||
let cmd = T::augment_args(cmd).disable_help_subcommand(true);
|
||||
if GENERATING_COMPLETIONS.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
cmd
|
||||
} else {
|
||||
// We use the special `defer` method which lets us recursively call `augment_args` on the inner command
|
||||
// and thus `from_arg_matches`
|
||||
T::augment_args(cmd).defer(|cmd| U::augment_subcommands(cmd.disable_help_subcommand(true)))
|
||||
cmd.defer(|cmd| U::augment_subcommands(cmd))
|
||||
}
|
||||
}
|
||||
|
||||
fn augment_args_for_update(_cmd: clap::Command) -> clap::Command {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
use super::*;
|
||||
use crate::{cli, Result};
|
||||
use clap::CommandFactory;
|
||||
use clap_complete::{generate, Shell};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// Generate shell completions for the specified shell.
|
||||
#[derive(Clone, Debug, Parser)]
|
||||
pub(crate) struct ShellCompletions {
|
||||
/// The shell to generate completions for.
|
||||
#[clap(value_enum)]
|
||||
pub shell: Shell,
|
||||
}
|
||||
|
||||
/// An annoying, code smelly, way of setting the CLI recursive depth parser to limit early, useful for
|
||||
/// generating completions here.
|
||||
///
|
||||
/// This should be set before calling clap_complete's generation function
|
||||
pub static GENERATING_COMPLETIONS: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
impl ShellCompletions {
|
||||
pub fn generate_and_print(self) -> Result<StructuredOutput> {
|
||||
let mut cmd = cli::Cli::command();
|
||||
GENERATING_COMPLETIONS.swap(true, std::sync::atomic::Ordering::Relaxed);
|
||||
generate(
|
||||
self.shell,
|
||||
&mut cmd,
|
||||
env!("CARGO_BIN_NAME"),
|
||||
&mut std::io::stdout(),
|
||||
);
|
||||
Ok(StructuredOutput::Success)
|
||||
}
|
||||
}
|
||||
+22
-15
@@ -73,21 +73,6 @@ pub fn verbosity_or_default() -> Verbosity {
|
||||
crate::VERBOSITY.get().cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn reset_cursor() {
|
||||
use std::io::IsTerminal;
|
||||
|
||||
// if we are running in a terminal, reset the cursor. The tui_active flag is not set for
|
||||
// the cargo generate TUI, but we still want to reset the cursor.
|
||||
if std::io::stdout().is_terminal() {
|
||||
_ = console::Term::stdout().show_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait that emits an anonymous JSON representation of the object, suitable for telemetry.
|
||||
pub(crate) trait Anonymized {
|
||||
fn anonymized(&self) -> serde_json::Value;
|
||||
}
|
||||
|
||||
/// A custom layer that wraps our special interception logic based on the mode of the CLI and its verbosity.
|
||||
///
|
||||
/// Redirects TUI logs, writes to files, and queues telemetry events.
|
||||
@@ -114,6 +99,7 @@ struct CapturedPanicError {
|
||||
thread_name: Option<String>,
|
||||
location: Option<SavedLocation>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CapturedPanicError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
@@ -132,6 +118,11 @@ struct SavedLocation {
|
||||
column: u32,
|
||||
}
|
||||
|
||||
/// A trait that emits an anonymous JSON representation of the object, suitable for telemetry.
|
||||
pub(crate) trait Anonymized {
|
||||
fn anonymized(&self) -> serde_json::Value;
|
||||
}
|
||||
|
||||
impl TraceController {
|
||||
/// Initialize the CLI and set up the tracing infrastructure
|
||||
///
|
||||
@@ -840,6 +831,12 @@ impl TraceController {
|
||||
}),
|
||||
),
|
||||
Commands::Doctor(_cmd) => ("doctor".to_string(), json!({})),
|
||||
Commands::ShellCompletions(cmd) => (
|
||||
"completions".to_string(),
|
||||
json!({
|
||||
"shell": cmd.shell.to_string(),
|
||||
}),
|
||||
),
|
||||
Commands::Translate(cmd) => (
|
||||
"translate".to_string(),
|
||||
json!({
|
||||
@@ -1437,3 +1434,13 @@ impl PosthogEvent {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn reset_cursor() {
|
||||
use std::io::IsTerminal;
|
||||
|
||||
// if we are running in a terminal, reset the cursor. The tui_active flag is not set for
|
||||
// the cargo generate TUI, but we still want to reset the cursor.
|
||||
if std::io::stdout().is_terminal() {
|
||||
_ = console::Term::stdout().show_cursor();
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ async fn main() -> ExitCode {
|
||||
Commands::Doctor(opts) => opts.doctor().await,
|
||||
Commands::Print(opts) => opts.print().await,
|
||||
Commands::Components(opts) => opts.run().await,
|
||||
Commands::ShellCompletions(opts) => opts.generate_and_print(),
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user