From bd8f01fb2627a9db4c5ca5c2f08dabb3b9f9cff4 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 11 Jan 2026 18:41:02 +0800 Subject: [PATCH] Add Nushell completion script generation support (#1756) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- Cargo.lock | 96 ++++++++++++++++++++++++++++++++++-- easytier/Cargo.toml | 1 + easytier/src/core.rs | 12 +++-- easytier/src/easytier-cli.rs | 11 +++-- easytier/src/lib.rs | 34 ++++++++++++- 5 files changed, 142 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e81c9eb4..b18b56c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,6 +508,29 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "aws-lc-rs" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +dependencies = [ + "bindgen 0.69.5", + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "axum" version = "0.7.7" @@ -761,6 +784,29 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags 2.8.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn 2.0.87", + "which 4.4.2", +] + [[package]] name = "bindgen" version = "0.71.1" @@ -774,7 +820,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "rustc-hash", + "rustc-hash 2.1.0", "shlex", "syn 2.0.87", ] @@ -1301,6 +1347,16 @@ dependencies = [ "clap", ] +[[package]] +name = "clap_complete_nushell" +version = "4.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685bc86fd34b7467e0532a4f8435ab107960d69a243785ef0275e571b35b641a" +dependencies = [ + "clap", + "clap_complete", +] + [[package]] name = "clap_derive" version = "4.5.28" @@ -1328,6 +1384,15 @@ dependencies = [ "error-code", ] +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "codepage" version = "0.1.2" @@ -2100,6 +2165,7 @@ dependencies = [ "cidr", "clap", "clap_complete", + "clap_complete_nushell", "console-subscriber", "crossbeam", "dashmap", @@ -2245,6 +2311,7 @@ dependencies = [ "gethostname 1.0.2", "libc", "once_cell", + "rustls", "security-framework-sys", "serde", "serde_json", @@ -2771,6 +2838,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -4253,7 +4326,7 @@ source = "git+https://github.com/EasyTier/kcp-sys?rev=71eff18c573a4a71bf99c7fabc dependencies = [ "anyhow", "auto_impl", - "bindgen", + "bindgen 0.71.1", "bitflags 2.8.0", "bytes", "cc", @@ -4300,6 +4373,12 @@ dependencies = [ "spin", ] +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libappindicator" version = "0.9.0" @@ -6425,7 +6504,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.0", "rustls", "socket2 0.5.10", "thiserror 2.0.11", @@ -6446,7 +6525,7 @@ dependencies = [ "lru-slab", "rand 0.9.1", "ring", - "rustc-hash", + "rustc-hash 2.1.0", "rustls", "rustls-pki-types", "rustls-platform-verifier", @@ -7037,6 +7116,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.1.0" @@ -7084,6 +7169,8 @@ version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ + "aws-lc-rs", + "log", "once_cell", "ring", "rustls-pki-types", @@ -7155,6 +7242,7 @@ version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 05ab4062..7f635dad 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -135,6 +135,7 @@ clap = { version = "4.5.30", features = [ "env", ] } clap_complete = { version = "4.5.55" } +clap_complete_nushell = { version = "4.5.10" } async-recursion = "1.0.5" diff --git a/easytier/src/core.rs b/easytier/src/core.rs index 573c8b42..350b9505 100644 --- a/easytier/src/core.rs +++ b/easytier/src/core.rs @@ -23,12 +23,11 @@ use crate::{ rpc_service::ApiRpcServer, tunnel::PROTO_PORT_OFFSET, utils::{init_logger, setup_panic_handler}, - web_client, + web_client, ShellType, }; use anyhow::Context; use cidr::IpCidr; use clap::{CommandFactory, Parser}; -use clap_complete::Shell; use rust_i18n::t; use tokio::io::AsyncReadExt; @@ -126,7 +125,7 @@ struct Cli { rpc_portal_options: RpcPortalOptions, #[clap(long, help = t!("core_clap.generate_completions").to_string())] - gen_autocomplete: Option, + gen_autocomplete: Option, #[clap(long, help = t!("core_clap.check_config").to_string())] check_config: bool, @@ -1380,7 +1379,12 @@ pub async fn main() -> ExitCode { if let Some(shell) = cli.gen_autocomplete { let mut cmd = Cli::command(); - crate::print_completions(shell, &mut cmd, "easytier-core"); + if let Some(shell) = shell.to_shell() { + crate::print_completions(shell, &mut cmd, "easytier-core"); + } else { + // Handle Nushell + crate::print_nushell_completions(&mut cmd, "easytier-core"); + } return ExitCode::SUCCESS; } diff --git a/easytier/src/easytier-cli.rs b/easytier/src/easytier-cli.rs index 1d8db9bf..544a9d65 100644 --- a/easytier/src/easytier-cli.rs +++ b/easytier/src/easytier-cli.rs @@ -10,8 +10,8 @@ use std::{ use anyhow::Context; use cidr::Ipv4Inet; use clap::{Args, CommandFactory, Parser, Subcommand}; -use clap_complete::Shell; use dashmap::DashMap; +use easytier::ShellType; use humansize::format_size; use rust_i18n::t; use service_manager::*; @@ -126,7 +126,7 @@ enum SubCommand { #[command(about = "manage logger configuration")] Logger(LoggerArgs), #[command(about = t!("core_clap.generate_completions").to_string())] - GenAutocomplete { shell: Shell }, + GenAutocomplete { shell: ShellType }, } #[derive(clap::ValueEnum, Debug, Clone, PartialEq)] @@ -1950,7 +1950,12 @@ async fn main() -> Result<(), Error> { }, SubCommand::GenAutocomplete { shell } => { let mut cmd = Cli::command(); - easytier::print_completions(shell, &mut cmd, "easytier-cli"); + if let Some(shell) = shell.to_shell() { + easytier::print_completions(shell, &mut cmd, "easytier-cli"); + } else { + // Handle Nushell + easytier::print_nushell_completions(&mut cmd, "easytier-cli"); + } } } diff --git a/easytier/src/lib.rs b/easytier/src/lib.rs index 882f6c93..92ef893a 100644 --- a/easytier/src/lib.rs +++ b/easytier/src/lib.rs @@ -3,7 +3,7 @@ use std::io; use clap::Command; -use clap_complete::Generator; +use clap_complete::{Generator, Shell}; mod arch; mod gateway; @@ -30,6 +30,38 @@ mod tests; pub const VERSION: &str = common::constants::EASYTIER_VERSION; rust_i18n::i18n!("locales", fallback = "en"); +#[derive(clap::ValueEnum, Debug, Clone, PartialEq)] +pub enum ShellType { + Bash, + Elvish, + Fish, + Powershell, + Zsh, + Nu, +} + +impl ShellType { + pub fn to_shell(&self) -> Option { + match self { + ShellType::Bash => Some(Shell::Bash), + ShellType::Elvish => Some(Shell::Elvish), + ShellType::Fish => Some(Shell::Fish), + ShellType::Powershell => Some(Shell::PowerShell), + ShellType::Zsh => Some(Shell::Zsh), + ShellType::Nu => None, + } + } +} + pub fn print_completions(generator: G, cmd: &mut Command, bin_name: &str) { clap_complete::generate(generator, cmd, bin_name, &mut io::stdout()); } + +pub fn print_nushell_completions(cmd: &mut Command, bin_name: &str) { + clap_complete::generate( + clap_complete_nushell::Nushell, + cmd, + bin_name, + &mut io::stdout(), + ); +}