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
+93
-19
No files matched your search
Generated
+22
@@ -3452,6 +3452,18 @@ dependencies = [
|
|||||||
"terminal_size",
|
"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]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.61"
|
version = "4.5.61"
|
||||||
@@ -4855,6 +4867,7 @@ dependencies = [
|
|||||||
"cargo_toml",
|
"cargo_toml",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
"codemap",
|
"codemap",
|
||||||
"console 0.16.3",
|
"console 0.16.3",
|
||||||
"console-subscriber",
|
"console-subscriber",
|
||||||
@@ -9142,6 +9155,15 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
|
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]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.2"
|
version = "1.70.2"
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ nucleo = "0.5.0"
|
|||||||
|
|
||||||
# 0.5.12 rust-version is too high
|
# 0.5.12 rust-version is too high
|
||||||
home = "=0.5.11"
|
home = "=0.5.11"
|
||||||
|
clap_complete = { version = "4.5.65", features = ["unstable-dynamic"] }
|
||||||
|
|
||||||
[target.'cfg(target_env = "musl")'.dependencies]
|
[target.'cfg(target_env = "musl")'.dependencies]
|
||||||
git2 = { version = "0.20.2", features = ["vendored-libgit2"] }
|
git2 = { version = "0.20.2", features = ["vendored-libgit2"] }
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ pub(crate) mod platform_override;
|
|||||||
pub(crate) mod print;
|
pub(crate) mod print;
|
||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
pub(crate) mod serve;
|
pub(crate) mod serve;
|
||||||
|
pub(crate) mod shell_completions;
|
||||||
pub(crate) mod target;
|
pub(crate) mod target;
|
||||||
pub(crate) mod translate;
|
pub(crate) mod translate;
|
||||||
pub(crate) mod update;
|
pub(crate) mod update;
|
||||||
@@ -84,6 +85,10 @@ pub(crate) enum Commands {
|
|||||||
#[clap(name = "doctor")]
|
#[clap(name = "doctor")]
|
||||||
Doctor(doctor::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
|
/// 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.
|
/// flags DX sets that might be useful in third-party tools.
|
||||||
#[clap(name = "print")]
|
#[clap(name = "print")]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::Anonymized;
|
use crate::{shell_completions::GENERATING_COMPLETIONS, Anonymized};
|
||||||
use clap::parser::ValueSource;
|
use clap::parser::ValueSource;
|
||||||
use clap::{ArgMatches, Args, CommandFactory, FromArgMatches, Parser, Subcommand};
|
use clap::{ArgMatches, Args, CommandFactory, FromArgMatches, Parser, Subcommand};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
@@ -159,9 +159,14 @@ where
|
|||||||
U: Subcommand,
|
U: Subcommand,
|
||||||
{
|
{
|
||||||
fn augment_args(cmd: clap::Command) -> clap::Command {
|
fn augment_args(cmd: clap::Command) -> clap::Command {
|
||||||
// We use the special `defer` method which lets us recursively call `augment_args` on the inner command
|
let cmd = T::augment_args(cmd).disable_help_subcommand(true);
|
||||||
// and thus `from_arg_matches`
|
if GENERATING_COMPLETIONS.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
T::augment_args(cmd).defer(|cmd| U::augment_subcommands(cmd.disable_help_subcommand(true)))
|
cmd
|
||||||
|
} else {
|
||||||
|
// We use the special `defer` method which lets us recursively call `augment_args` on the inner command
|
||||||
|
// and thus `from_arg_matches`
|
||||||
|
cmd.defer(|cmd| U::augment_subcommands(cmd))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn augment_args_for_update(_cmd: clap::Command) -> clap::Command {
|
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()
|
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.
|
/// 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.
|
/// Redirects TUI logs, writes to files, and queues telemetry events.
|
||||||
@@ -114,6 +99,7 @@ struct CapturedPanicError {
|
|||||||
thread_name: Option<String>,
|
thread_name: Option<String>,
|
||||||
location: Option<SavedLocation>,
|
location: Option<SavedLocation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for CapturedPanicError {
|
impl std::fmt::Display for CapturedPanicError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
@@ -132,6 +118,11 @@ struct SavedLocation {
|
|||||||
column: u32,
|
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 {
|
impl TraceController {
|
||||||
/// Initialize the CLI and set up the tracing infrastructure
|
/// Initialize the CLI and set up the tracing infrastructure
|
||||||
///
|
///
|
||||||
@@ -840,6 +831,12 @@ impl TraceController {
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
Commands::Doctor(_cmd) => ("doctor".to_string(), json!({})),
|
Commands::Doctor(_cmd) => ("doctor".to_string(), json!({})),
|
||||||
|
Commands::ShellCompletions(cmd) => (
|
||||||
|
"completions".to_string(),
|
||||||
|
json!({
|
||||||
|
"shell": cmd.shell.to_string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
Commands::Translate(cmd) => (
|
Commands::Translate(cmd) => (
|
||||||
"translate".to_string(),
|
"translate".to_string(),
|
||||||
json!({
|
json!({
|
||||||
@@ -1437,3 +1434,13 @@ impl PosthogEvent {
|
|||||||
Ok(())
|
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::Doctor(opts) => opts.doctor().await,
|
||||||
Commands::Print(opts) => opts.print().await,
|
Commands::Print(opts) => opts.print().await,
|
||||||
Commands::Components(opts) => opts.run().await,
|
Commands::Components(opts) => opts.run().await,
|
||||||
|
Commands::ShellCompletions(opts) => opts.generate_and_print(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user