add options to generate completions (#1103)

* add options to generate completions

use clap-complete crate to generate completions scripts: easytier-core --generate fish > ~/.config/fish/completions/easytier-core.fish

---------

Co-authored-by: Sijie.Sun <sunsijie@buaa.edu.cn>
This commit is contained in:
Jiangqiu Shen
2025-07-17 08:35:49 -04:00
committed by GitHub
parent 940238f158
commit 0b729b99e7
8 changed files with 59 additions and 6 deletions

10
Cargo.lock generated
View File

@@ -1197,6 +1197,15 @@ dependencies = [
"unicode-width 0.2.0",
]
[[package]]
name = "clap_complete"
version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.28"
@@ -1961,6 +1970,7 @@ dependencies = [
"chrono",
"cidr",
"clap",
"clap_complete",
"crossbeam",
"dashmap",
"dbus",

View File

@@ -67,6 +67,11 @@ brew install --cask easytier-gui
# 6. OpenWrt Luci Web UI
# Visit https://github.com/EasyTier/luci-app-easytier
# 7. (Optional) Install shell completions:
easytier-core --gen-autocomplete fish > ~/.config/fish/completions/easytier-core.fish
easytier-cli gen-autocomplete fish > ~/.config/fish/completions/easytier-cli.fish
```
### 🚀 Basic Usage

View File

@@ -67,6 +67,12 @@ brew install --cask easytier-gui
# 6. OpenWrt Luci Web 界面
# 访问 https://github.com/EasyTier/luci-app-easytier
# 7.(可选)安装 Shell 补全功能:
# Fish 补全
easytier-core --gen-autocomplete fish > ~/.config/fish/completions/easytier-core.fish
easytier-cli gen-autocomplete fish > ~/.config/fish/completions/easytier-cli.fish
```
### 🚀 基本用法

View File

@@ -132,6 +132,7 @@ clap = { version = "4.5.30", features = [
"wrap_help",
"env",
] }
clap_complete = { version = "4.5.55" }
async-recursion = "1.0.5"

View File

@@ -18,6 +18,9 @@ core_clap:
config_file:
en: "path to the config file, NOTE: the options set by cmdline args will override options in config file"
zh-CN: "配置文件路径,注意:命令行中的配置的选项会覆盖配置文件中的选项"
generate_completions:
en: "generate shell completions"
zh-CN: "生成 shell 补全脚本"
network_name:
en: "network name to identify this vpn network"
zh-CN: "用于标识此VPN网络的网络名称"

View File

@@ -11,8 +11,10 @@ use std::{
use anyhow::Context;
use cidr::Ipv4Inet;
use clap::{command, Args, Parser, Subcommand};
use clap::{command, Args, CommandFactory, Parser, Subcommand};
use clap_complete::Shell;
use humansize::format_size;
use rust_i18n::t;
use service_manager::*;
use tabled::settings::Style;
use tokio::time::timeout;
@@ -86,6 +88,10 @@ enum SubCommand {
Service(ServiceArgs),
#[command(about = "show tcp/kcp proxy status")]
Proxy,
#[command(about = t!("core_clap.generate_completions").to_string())]
GenAutocomplete{
shell:Shell
},
}
#[derive(clap::ValueEnum, Debug, Clone, PartialEq)]
@@ -985,7 +991,10 @@ where
#[tokio::main]
#[tracing::instrument]
async fn main() -> Result<(), Error> {
let locale = sys_locale::get_locale().unwrap_or_else(|| String::from("en-US"));
rust_i18n::set_locale(&locale);
let cli = Cli::parse();
let client = RpcClient::new(TcpTunnelConnector::new(
format!("tcp://{}:{}", cli.rpc_portal.ip(), cli.rpc_portal.port())
.parse()
@@ -1315,6 +1324,10 @@ async fn main() -> Result<(), Error> {
print_output(&table_rows, &cli.output_format)?;
}
SubCommand::GenAutocomplete { shell } => {
let mut cmd = Cli::command();
easytier::print_completions(shell, &mut cmd, "easytier-cli");
}
}
Ok(())

View File

@@ -4,16 +4,14 @@
extern crate rust_i18n;
use std::{
net::{Ipv4Addr, SocketAddr},
path::PathBuf,
process::ExitCode,
sync::Arc,
net::{Ipv4Addr, SocketAddr}, path::PathBuf, process::ExitCode, sync::Arc
};
use anyhow::Context;
use cidr::IpCidr;
use clap::Parser;
use clap::{CommandFactory, Parser};
use clap_complete::Shell;
use easytier::{
common::{
config::{
@@ -122,6 +120,9 @@ struct Cli {
#[command(flatten)]
logging_options: LoggingOptions,
#[clap(long, help = t!("core_clap.generate_completions").to_string())]
gen_autocomplete: Option<Shell>,
}
#[derive(Parser, Debug)]
@@ -1158,6 +1159,11 @@ async fn main() -> ExitCode {
let _monitor = std::thread::spawn(memory_monitor);
let cli = Cli::parse();
if let Some(shell) = cli.gen_autocomplete {
let mut cmd = Cli::command();
easytier::print_completions(shell, &mut cmd, "easytier-core");
return ExitCode::SUCCESS;
}
let mut ret_code = 0;
if let Err(e) = run_main(cli).await {

View File

@@ -1,5 +1,10 @@
#![allow(dead_code)]
use std::io;
use clap::Command;
use clap_complete::Generator;
mod arch;
mod gateway;
mod instance;
@@ -21,3 +26,7 @@ mod tests;
pub const VERSION: &str = common::constants::EASYTIER_VERSION;
rust_i18n::i18n!("locales", fallback = "en");
pub fn print_completions<G: Generator>(generator: G, cmd: &mut Command, bin_name:&str) {
clap_complete::generate(generator, cmd, bin_name, &mut io::stdout());
}