Add shell completion generation

This commit is contained in:
Eric Wendland 2026-05-23 02:40:03 +02:00
commit 5b2c30f817
7 changed files with 98 additions and 3 deletions

View file

@ -9,6 +9,7 @@ license.workspace = true
anyhow.workspace = true
base64.workspace = true
clap.workspace = true
clap_complete.workspace = true
serde_json.workspace = true
tokio.workspace = true
geth-config = { path = "../geth-config" }

View file

@ -1,16 +1,18 @@
use anyhow::{Context, Result, bail};
use base64::Engine;
use clap::{Args, Parser, Subcommand, ValueEnum};
use clap::{Args, CommandFactory, Parser, Subcommand, ValueEnum};
use clap_complete::{Shell, generate};
use geth_config::GethPaths;
use geth_control::{ControlRequest, ControlResponse};
use geth_node::service::{ServiceInstallOptions, ServiceManager, ServiceReport};
use std::io::Read;
use std::io::{Read, stdout};
use std::path::PathBuf;
const TOP_LEVEL_AFTER_HELP: &str = r#"Common starts:
geth guide init
geth guide owner-setup
geth guide overlay
geth guide completions
geth init
geth init --admin-key ~/.ssh/id_ed25519_sk.pub --signing-key ~/.ssh/id_ed25519_sk --node-name laptop
geth daemon run
@ -73,6 +75,7 @@ Topics:
keys Meaning of --admin-key and --signing-key.
overlay Optional Iroh overlay network planning.
service Install and manage geth as a user service.
completions Shell completion installation examples.
smoke-test Minimal commands to verify a node and daemon."#;
const GUIDE_INIT: &str = r#"geth init has two modes.
@ -178,6 +181,34 @@ Preview definitions without installing:
geth daemon service print
"#;
const GUIDE_COMPLETIONS: &str = r#"Shell completions:
geth can print completions for bash, zsh, fish, PowerShell, and elvish. The
generated scripts are produced from the same Clap command tree as `geth --help`,
so subcommands and flags stay in sync with the executable.
Bash:
mkdir -p ~/.local/share/bash-completion/completions
geth completions bash > ~/.local/share/bash-completion/completions/geth
Zsh:
mkdir -p ~/.zfunc
geth completions zsh > ~/.zfunc/_geth
# Ensure ~/.zfunc is in fpath, then run: compinit
Fish:
mkdir -p ~/.config/fish/completions
geth completions fish > ~/.config/fish/completions/geth.fish
PowerShell:
geth completions powershell > geth.ps1
# Source geth.ps1 from your PowerShell profile.
Elvish:
mkdir -p ~/.elvish/lib
geth completions elvish > ~/.elvish/lib/geth.elv
"#;
const GUIDE_OVERLAY: &str = r#"Optional overlay network:
geth has an experimental overlay-network design inspired by iroh-lan. The
@ -256,6 +287,10 @@ pub enum Command {
#[arg(value_enum)]
topic: Option<GuideTopic>,
},
Completions {
#[arg(value_enum)]
shell: Shell,
},
#[command(long_about = INIT_LONG_ABOUT, after_long_help = INIT_AFTER_HELP)]
Init {
#[arg(
@ -366,6 +401,7 @@ pub enum GuideTopic {
Keys,
Overlay,
Service,
Completions,
SmokeTest,
}
@ -1063,6 +1099,10 @@ pub struct EmptyArgs {}
pub async fn run() -> Result<()> {
let cli = Cli::parse();
if let Command::Completions { shell } = &cli.command {
print_completions(*shell);
return Ok(());
}
let paths = GethPaths::resolve().context("resolve geth paths")?;
match cli.command {
Command::Guide { topic } => {
@ -1169,6 +1209,7 @@ fn print_guide(topic: Option<GuideTopic>, json: bool) -> Result<()> {
Some(GuideTopic::Keys) => ("keys", GUIDE_KEYS),
Some(GuideTopic::Overlay) => ("overlay", GUIDE_OVERLAY),
Some(GuideTopic::Service) => ("service", GUIDE_SERVICE),
Some(GuideTopic::Completions) => ("completions", GUIDE_COMPLETIONS),
Some(GuideTopic::SmokeTest) => ("smoke-test", GUIDE_SMOKE_TEST),
};
if json {
@ -1185,8 +1226,14 @@ fn print_guide(topic: Option<GuideTopic>, json: bool) -> Result<()> {
Ok(())
}
fn print_completions(shell: Shell) {
let mut command = Cli::command();
generate(shell, &mut command, "geth", &mut stdout());
}
fn request_for_command(command: Command) -> Result<ControlRequest> {
Ok(match command {
Command::Completions { .. } => bail!("completion generation does not use the daemon"),
Command::Status => ControlRequest::Status,
Command::Sync {
command: SyncCommand::Status,