From 8a7a201daaba3ab35e4bec322d8b6016e0a86e08 Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Sun, 23 Aug 2026 23:52:59 -0700 Subject: [PATCH] Adds shell completion generation. --- Cargo.lock | 10 ++++++++++ Tasks.md | 14 +++++++------- cli/Cargo.toml | 1 + cli/src/main.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef1c12a..7598294 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -558,6 +558,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be2ad0423bdbbb0e25bc89add796f3559706d4a95e1bc98e4d9662a957b6a19" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.6.4" @@ -2492,6 +2501,7 @@ name = "nut" version = "0.1.0" dependencies = [ "clap", + "clap_complete", "indicatif", "nextcloud_client", "open", diff --git a/Tasks.md b/Tasks.md index 6419506..0b04f67 100644 --- a/Tasks.md +++ b/Tasks.md @@ -71,7 +71,6 @@ This document defines the complete project roadmap and task tracking system for | ID | Title | Status | Type | |---|---|---|---| | [NUT-019](#nut-019) | Implement Homebrew/Winget/Chocolatey Manifests | Triage | Chore | -| [NUT-022](#nut-022) | Implement CLI Shell Completions Generation | Triage | Feature | | [NUT-023](#nut-023) | Write Comprehensive CLI Documentation and Automation Guides | Triage | Chore | | [NUT-024](#nut-024) | Create Docker/Podman Nextcloud Integration Test Harness | Triage | Foundation | | [NUT-001](#nut-001) | Establish Repository Structure | Fixed | Foundation | @@ -94,6 +93,7 @@ This document defines the complete project roadmap and task tracking system for | [NUT-018](#nut-018) | Implement Packaging for macOS, Windows, Linux | Fixed | Chore | | [NUT-020](#nut-020) | Write Documentation + Examples | Fixed | Chore | | [NUT-021](#nut-021) | Support Headless & SSH Remote Authentication Modes | Fixed | Feature | +| [NUT-022](#nut-022) | Implement CLI Shell Completions Generation | Fixed | Feature | --- @@ -522,20 +522,20 @@ Ensure smooth authentication experiences when running the CLI over SSH or in hea - NUT-008 - + ### Implement CLI Shell Completions Generation **ID:** NUT-022 -**Status:** Triage +**Status:** Fixed **Type:** Feature **Description:** Add automated shell completion script generation using `clap_complete` for major shells (`bash`, `zsh`, `fish`, `powershell`, `elvish`). **Requirements:** -- [ ] Add `clap_complete` crate dependency -- [ ] Implement `nut completions ` subcommand -- [ ] Support `bash`, `zsh`, `fish`, `powershell`, and `elvish` output to stdout -- [ ] Include quick installation instructions in command help +- [x] Add `clap_complete` crate dependency +- [x] Implement `nut completions ` subcommand +- [x] Support `bash`, `zsh`, `fish`, `powershell`, and `elvish` output to stdout +- [x] Include quick installation instructions in command help **Dependencies:** - NUT-008 diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 3d7c0d7..55b361b 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] nextcloud_client = { path = "../nextcloud_client" } clap = { version = "4.5", features = ["derive", "cargo"] } +clap_complete = "4.5" tokio = { version = "1", features = ["full"] } reqwest = { version = "0.12", default-features = false, features = ["json", "default-tls"] } open = "5.3" diff --git a/cli/src/main.rs b/cli/src/main.rs index 6a1e0d8..8543342 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,4 +1,5 @@ -use clap::{Args, Parser, Subcommand}; +use clap::{Args, CommandFactory, Parser, Subcommand}; +use clap_complete::{generate, Shell}; use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; use serde::Serialize; use std::fs; @@ -39,6 +40,13 @@ enum Commands { /// Quick alias to list all configured accounts Accounts(AccountListArgs), + + /// Generate shell completion scripts for bash, zsh, fish, powershell, or elvish + Completions { + /// Target shell to generate completions for + #[arg(value_enum)] + shell: Shell, + }, } #[derive(Args, Debug, PartialEq)] @@ -207,6 +215,10 @@ async fn main() { handle_account_set_default(&account) } Commands::Account(AccountCommands::Delete { account }) => handle_account_delete(&account), + Commands::Completions { shell } => { + handle_completions(shell); + Ok(()) + } }; if let Err(err) = result { @@ -215,6 +227,12 @@ async fn main() { } } +/// Generate shell completion scripts for supported shells. +fn handle_completions(shell: Shell) { + let mut cmd = Cli::command(); + generate(shell, &mut cmd, "nut", &mut io::stdout()); +} + /// Handle interactive or non-interactive login flows. async fn handle_login(args: LoginArgs) -> Result<()> { let server_url = ClientConfig::normalize_url(&args.server_url)?; @@ -822,4 +840,35 @@ mod tests { _ => panic!("Expected Accounts list command"), } } + + #[test] + fn test_cli_completions_parsing() { + let shells = [ + ("bash", Shell::Bash), + ("zsh", Shell::Zsh), + ("fish", Shell::Fish), + ("powershell", Shell::PowerShell), + ("elvish", Shell::Elvish), + ]; + + for (name, expected_shell) in shells { + let parsed = Cli::try_parse_from(&["nut", "completions", name]).unwrap(); + match parsed.command { + Commands::Completions { shell } => { + assert_eq!(shell, expected_shell); + } + _ => panic!("Expected Completions command for shell {name}"), + } + + let mut buf = Vec::new(); + let mut cmd = Cli::command(); + generate(expected_shell, &mut cmd, "nut", &mut buf); + assert!(!buf.is_empty(), "Generated completion for {name} should not be empty"); + let output_str = String::from_utf8(buf).expect("Completions should be valid UTF-8"); + assert!( + output_str.contains("nut"), + "Completion output should contain 'nut'" + ); + } + } }