From 7cc680d82c5908b9c90a618901882064c3e8a0cf Mon Sep 17 00:00:00 2001 From: XS Date: Thu, 2 Apr 2026 13:10:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(keyman):=20=E6=9B=B4=E6=96=B0=20README=20?= =?UTF-8?q?=E5=92=8C=E6=8F=92=E4=BB=B6=E6=96=87=E6=A1=A3=EF=BC=8C=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=91=BD=E4=BB=A4=E6=A0=BC=E5=BC=8F=E5=B9=B6=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E5=B8=AE=E5=8A=A9=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/keyman/README.md | 122 +++++++--- plugins/keyman/keyman.plugin.zsh | 394 +++++++++++++++++++++---------- 2 files changed, 359 insertions(+), 157 deletions(-) diff --git a/plugins/keyman/README.md b/plugins/keyman/README.md index 32b55aab9..704fc3d77 100644 --- a/plugins/keyman/README.md +++ b/plugins/keyman/README.md @@ -1,39 +1,89 @@ # keyman plugin -Provides convenient commands for managing SSH and GPG keys from the terminal. +Provides a unified `keyman` command for managing SSH and GPG keys from the terminal. Works on macOS, Linux (X11/Wayland), and WSL. +> **Relationship to other plugins:** The [`ssh-agent`](../ssh-agent) and +> [`gpg-agent`](../gpg-agent) plugins manage agent *daemons* (auto-starting, +> identity loading, forwarding). `keyman` focuses on key *lifecycle* — creating, +> listing, copying, and deleting keys. They are complementary and can be used +> together. + To enable it, add `keyman` to your plugins: ```zsh plugins=(... keyman) ``` -Then type `keyman` to see all available commands. +Then type `keyman help` to see all available commands. + +## Requirements + +At least one of the following must be available: + +- `ssh-keygen` — for SSH key commands +- `gpg` — for GPG key commands + +### Clipboard support + +For clipboard commands (`keyman ssh copy`, `keyman gpg copy`), one of the tools +below must be installed: + +| Platform | Tool | Notes | +| --------------- | ---------- | -------------------------- | +| macOS | `pbcopy` | Built-in | +| Linux (X11) | `xclip` | `apt install xclip` | +| Linux (Wayland) | `wl-copy` | `apt install wl-clipboard` | +| WSL | `clip.exe` | Built-in (Windows side) | ## Commands ### SSH -| Command | Description | -|---|---| -| `km-ssh-new [comment] [file] [type]` | Create a new SSH key (default: ed25519) | -| `km-ssh-ls` | List all SSH public keys in `~/.ssh` | -| `km-ssh-copy [pubkey_file]` | Copy a public key to clipboard | -| `km-ssh-rm ` | Delete an SSH key pair | +| Command | Description | +| --------------------------------------------- | --------------------------------------- | +| `keyman ssh new [comment] [file] [type]` | Create a new SSH key (default: ed25519) | +| `keyman ssh ls` | List all SSH public keys in `~/.ssh` | +| `keyman ssh copy [pubkey_file]` | Copy a public key to clipboard | +| `keyman ssh rm ` | Delete an SSH key pair | ### GPG -| Command | Description | -|---|---| -| `km-gpg-new` | Create a GPG key (interactive, via `gpg --full-generate-key`) | -| `km-gpg-quick-new "Name" "Email" [expiry]` | Create a GPG key non-interactively (ed25519, default 2y expiry) | -| `km-gpg-ls [-s\|--secret]` | List public keys, or secret keys with `-s` | -| `km-gpg-pub ` | Export a GPG public key (armored) | -| `km-gpg-priv ` | Export a GPG secret key (armored, with confirmation) | -| `km-gpg-copy ` | Copy a GPG public key to clipboard | -| `km-gpg-fp ` | Show a GPG key fingerprint | -| `km-gpg-rm ` | Delete a GPG key (secret + public) | +| Command | Description | +| -------------------------------------------------- | --------------------------------------------------------------- | +| `keyman gpg new` | Create a GPG key (interactive, via `gpg --full-generate-key`) | +| `keyman gpg quick-new "Name" "Email" [expiry]` | Create a GPG key non-interactively (ed25519, default 2y expiry) | +| `keyman gpg ls [-s\|--secret]` | List public keys, or secret keys with `-s` | +| `keyman gpg pub ` | Export a GPG public key (armored) | +| `keyman gpg priv ` | Export a GPG secret key (armored, with confirmation) | +| `keyman gpg copy ` | Copy a GPG public key to clipboard | +| `keyman gpg fp ` | Show a GPG key fingerprint | +| `keyman gpg rm ` | Delete a GPG key (secret + public) | + +### General + +| Command | Description | +| -------------- | ----------------- | +| `keyman help` | Show help message | + +## Tab Completion + +All commands support multi-level Zsh tab completion: + +``` +keyman → ssh | gpg | help +keyman ssh → new | ls | copy | rm +keyman gpg → new | quick-new | ls | pub | priv | copy | fp | rm +``` + +At the argument level: + +- **`keyman ssh new`** — completes key types (`ed25519`, `rsa`, `ecdsa`) and file paths +- **`keyman ssh copy`** — completes `~/.ssh/*.pub` files +- **`keyman ssh rm`** — completes private key files in `~/.ssh` +- **`keyman gpg ls`** — completes `--secret` / `-s` options +- **`keyman gpg quick-new`** — completes common expiry values (`1y`, `2y`, `3y`, `5y`, `0`) +- **`keyman gpg pub`**, **`priv`**, **`copy`**, **`fp`**, **`rm`** — complete GPG key IDs and emails from your keyring ## Settings @@ -57,7 +107,7 @@ zstyle :omz:plugins:keyman debug true ### `default-ssh-type` -Set the default SSH key type for `km-ssh-new`. Supported values: +Set the default SSH key type for `keyman ssh new`. Supported values: `ed25519` (default), `rsa`, `ecdsa`. ```zsh @@ -68,30 +118,32 @@ zstyle :omz:plugins:keyman default-ssh-type rsa ```zsh # Create a default ed25519 key -km-ssh-new +keyman ssh new # Create an RSA key with a custom comment and path -km-ssh-new "me@work" ~/.ssh/work_key rsa +keyman ssh new "me@work" ~/.ssh/work_key rsa # List all SSH keys -km-ssh-ls +keyman ssh ls # Copy the default public key to clipboard -km-ssh-copy +keyman ssh copy + +# Delete an SSH key +keyman ssh rm ~/.ssh/id_ed25519 + +# Create a GPG key interactively +keyman gpg new # Create a GPG key quickly -km-gpg-quick-new "John Doe" "john@example.com" 1y +keyman gpg quick-new "John Doe" "john@example.com" 1y + +# List GPG secret keys +keyman gpg ls --secret # Export and copy a GPG public key -km-gpg-copy john@example.com +keyman gpg copy john@example.com + +# Show GPG key fingerprint +keyman gpg fp john@example.com ``` - -## Requirements - -At least one of the following must be available: - -- `ssh-keygen` -- for SSH key commands -- `gpg` -- for GPG key commands - -For clipboard support, one of: `pbcopy` (macOS), `xclip` (Linux X11), -`wl-copy` (Linux Wayland), or `clip.exe` (WSL). diff --git a/plugins/keyman/keyman.plugin.zsh b/plugins/keyman/keyman.plugin.zsh index d628588c0..2fbd448c3 100644 --- a/plugins/keyman/keyman.plugin.zsh +++ b/plugins/keyman/keyman.plugin.zsh @@ -1,7 +1,14 @@ #!/usr/bin/env zsh # keyman.plugin.zsh -- SSH & GPG key management plugin for oh-my-zsh # +# Author: keyman contributors +# Version: 0.2.0 +# License: MIT (same as oh-my-zsh) +# # Usage: add 'keyman' to plugins in ~/.zshrc +# keyman ssh [args...] +# keyman gpg [args...] +# keyman help # # Configuration (in .zshrc, before plugins=(...)): # zstyle ':omz:plugins:keyman' lang en # en (default) | zh @@ -21,6 +28,7 @@ typeset -g _km_green=$'\033[0;32m' typeset -g _km_yellow=$'\033[0;33m' typeset -g _km_blue=$'\033[0;34m' typeset -g _km_cyan=$'\033[0;36m' +typeset -g _km_bold=$'\033[1m' typeset -g _km_reset=$'\033[0m' _km_info() { print -r -- "${_km_blue}[keyman]${_km_reset} $*" } @@ -69,7 +77,7 @@ function { label_type "类型:" label_fingerprint "指纹:" label_comment "注释:" - # -- km-ssh-new -- + # -- ssh new -- ssh_dir_created "已创建 ~/.ssh 目录" file_exists "文件已存在" confirm_overwrite "是否覆盖?(y/N) " @@ -78,19 +86,19 @@ function { key_created "密钥已创建" added_to_agent "已添加到 ssh-agent" key_creation_failed "密钥创建失败" - # -- km-ssh-ls -- + # -- ssh ls -- ssh_dir_not_found "~/.ssh 目录不存在" no_ssh_keys_found "未找到任何 SSH 公钥" - # -- km-ssh-copy -- + # -- ssh copy -- pubkey_not_found "公钥文件不存在" available_pubkeys "可用的公钥:" none "(无)" pubkey_copied "公钥已复制到剪贴板" - # -- km-ssh-rm -- - usage_ssh_rm "用法: km-ssh-rm " + # -- ssh rm -- + usage_ssh_rm "用法: keyman ssh rm " key_not_found "密钥不存在" - # -- km-gpg-quick-new -- - usage_gpg_quick_new "用法: km-gpg-quick-new \"姓名\" \"邮箱\" [过期时间]" + # -- gpg quick-new -- + usage_gpg_quick_new "用法: keyman gpg quick-new \"姓名\" \"邮箱\" [过期时间]" email_has_gpg_key "该邮箱已有 GPG 密钥:" confirm_create_new "继续创建新密钥?(y/N) " creating_gpg_key "正在创建 GPG 密钥..." @@ -99,54 +107,56 @@ function { label_expiry " 过期:" gpg_key_created "GPG 密钥已创建" gpg_key_creation_failed "GPG 密钥创建失败" - # -- km-gpg-ls -- + # -- gpg ls -- gpg_secret_key_list "GPG 私钥列表:" gpg_public_key_list "GPG 公钥列表:" - # -- km-gpg-pub -- - usage_gpg_pub "用法: km-gpg-pub <邮箱或KeyID>" + # -- gpg pub -- + usage_gpg_pub "用法: keyman gpg pub <邮箱或KeyID>" gpg_key_not_found "未找到密钥" gpg_public_key "GPG 公钥" - # -- km-gpg-priv -- - usage_gpg_priv "用法: km-gpg-priv <邮箱或KeyID>" + # -- gpg priv -- + usage_gpg_priv "用法: keyman gpg priv <邮箱或KeyID>" gpg_secret_not_found "未找到私钥" warn_export_secret "即将导出私钥!请确保在安全环境下操作" confirm_export "确认导出?(y/N) " - # -- km-gpg-copy -- - usage_gpg_copy "用法: km-gpg-copy <邮箱或KeyID>" + # -- gpg copy -- + usage_gpg_copy "用法: keyman gpg copy <邮箱或KeyID>" gpg_pubkey_copied "GPG 公钥已复制到剪贴板" - # -- km-gpg-fp -- - usage_gpg_fp "用法: km-gpg-fp <邮箱或KeyID>" - # -- km-gpg-rm -- - usage_gpg_rm "用法: km-gpg-rm <邮箱或KeyID>" + # -- gpg fp -- + usage_gpg_fp "用法: keyman gpg fp <邮箱或KeyID>" + # -- gpg rm -- + usage_gpg_rm "用法: keyman gpg rm <邮箱或KeyID>" about_to_delete_gpg "即将删除 GPG 密钥" key_info "密钥信息:" + # -- errors -- + unknown_group "未知命令组: %s (可用: ssh, gpg)" + unknown_ssh_action "未知 SSH 操作: %s (可用: new, ls, copy, rm)" + unknown_gpg_action "未知 GPG 操作: %s (可用: new, quick-new, ls, pub, priv, copy, fp, rm)" # -- debug -- - loaded "已加载,输入 keyman 查看帮助" + loaded "已加载,输入 keyman help 查看帮助" # -- help -- help_text \ -"╔═══════════════════════════════════════════════════════════════╗ -║ keyman 密钥管理 ║ -╠═══════════════════════════════════════════════════════════════╣ -║ ║ -║ SSH 命令: ║ -║ ────────────────────────────────────────────────────── ║ -║ km-ssh-new [comment] [file] [type] 创建 SSH 密钥 ║ -║ km-ssh-ls 列出所有 SSH 公钥 ║ -║ km-ssh-copy [pubkey_file] 复制公钥到剪贴板 ║ -║ km-ssh-rm 删除 SSH 密钥对 ║ -║ ║ -║ GPG 命令: ║ -║ ────────────────────────────────────────────────────── ║ -║ km-gpg-new 创建密钥(交互式) ║ -║ km-gpg-quick-new \"姓名\" \"邮箱\" [期限] 创建密钥(快速) ║ -║ km-gpg-ls [-s|--secret] 列出密钥 ║ -║ km-gpg-pub 导出公钥 ║ -║ km-gpg-priv 导出私钥 ║ -║ km-gpg-copy 复制公钥到剪贴板 ║ -║ km-gpg-fp 查看指纹 ║ -║ km-gpg-rm 删除密钥 ║ -║ ║ -╚═══════════════════════════════════════════════════════════════╝" +"${_km_bold}keyman${_km_reset} — SSH & GPG 密钥管理 + +${_km_cyan}用法:${_km_reset} + keyman <命令组> <操作> [参数...] + keyman help + +${_km_cyan}SSH 命令:${_km_reset} + keyman ssh new [comment] [file] [type] 创建 SSH 密钥 + keyman ssh ls 列出所有 SSH 公钥 + keyman ssh copy [pubkey_file] 复制公钥到剪贴板 + keyman ssh rm 删除 SSH 密钥对 + +${_km_cyan}GPG 命令:${_km_reset} + keyman gpg new 创建密钥(交互式) + keyman gpg quick-new \"姓名\" \"邮箱\" [期限] 创建密钥(快速) + keyman gpg ls [-s|--secret] 列出密钥 + keyman gpg pub 导出公钥 + keyman gpg priv 导出私钥 + keyman gpg copy 复制公钥到剪贴板 + keyman gpg fp 查看指纹 + keyman gpg rm 删除密钥" ) ;; *) @@ -165,7 +175,7 @@ function { label_type "Type:" label_fingerprint "Fingerprint:" label_comment "Comment:" - # -- km-ssh-new -- + # -- ssh new -- ssh_dir_created "Created ~/.ssh directory" file_exists "File already exists" confirm_overwrite "Overwrite? (y/N) " @@ -174,19 +184,19 @@ function { key_created "Key created" added_to_agent "Added to ssh-agent" key_creation_failed "Key creation failed" - # -- km-ssh-ls -- + # -- ssh ls -- ssh_dir_not_found "~/.ssh directory does not exist" no_ssh_keys_found "No SSH public keys found" - # -- km-ssh-copy -- + # -- ssh copy -- pubkey_not_found "Public key file not found" available_pubkeys "Available public keys:" none "(none)" pubkey_copied "Public key copied to clipboard" - # -- km-ssh-rm -- - usage_ssh_rm "Usage: km-ssh-rm " + # -- ssh rm -- + usage_ssh_rm "Usage: keyman ssh rm " key_not_found "Key not found" - # -- km-gpg-quick-new -- - usage_gpg_quick_new "Usage: km-gpg-quick-new \"Name\" \"Email\" [expiry]" + # -- gpg quick-new -- + usage_gpg_quick_new "Usage: keyman gpg quick-new \"Name\" \"Email\" [expiry]" email_has_gpg_key "This email already has a GPG key:" confirm_create_new "Continue creating new key? (y/N) " creating_gpg_key "Creating GPG key..." @@ -195,54 +205,56 @@ function { label_expiry " Expiry:" gpg_key_created "GPG key created" gpg_key_creation_failed "GPG key creation failed" - # -- km-gpg-ls -- + # -- gpg ls -- gpg_secret_key_list "GPG secret key list:" gpg_public_key_list "GPG public key list:" - # -- km-gpg-pub -- - usage_gpg_pub "Usage: km-gpg-pub " + # -- gpg pub -- + usage_gpg_pub "Usage: keyman gpg pub " gpg_key_not_found "Key not found" gpg_public_key "GPG public key" - # -- km-gpg-priv -- - usage_gpg_priv "Usage: km-gpg-priv " + # -- gpg priv -- + usage_gpg_priv "Usage: keyman gpg priv " gpg_secret_not_found "Secret key not found" warn_export_secret "About to export secret key! Make sure you are in a secure environment" confirm_export "Confirm export? (y/N) " - # -- km-gpg-copy -- - usage_gpg_copy "Usage: km-gpg-copy " + # -- gpg copy -- + usage_gpg_copy "Usage: keyman gpg copy " gpg_pubkey_copied "GPG public key copied to clipboard" - # -- km-gpg-fp -- - usage_gpg_fp "Usage: km-gpg-fp " - # -- km-gpg-rm -- - usage_gpg_rm "Usage: km-gpg-rm " + # -- gpg fp -- + usage_gpg_fp "Usage: keyman gpg fp " + # -- gpg rm -- + usage_gpg_rm "Usage: keyman gpg rm " about_to_delete_gpg "About to delete GPG key" key_info "Key info:" + # -- errors -- + unknown_group "Unknown command group: %s (available: ssh, gpg)" + unknown_ssh_action "Unknown SSH action: %s (available: new, ls, copy, rm)" + unknown_gpg_action "Unknown GPG action: %s (available: new, quick-new, ls, pub, priv, copy, fp, rm)" # -- debug -- - loaded "Loaded. Type 'keyman' for help" + loaded "Loaded. Type 'keyman help' for help" # -- help -- help_text \ -"╔═══════════════════════════════════════════════════════════════╗ -║ keyman - Key Manager ║ -╠═══════════════════════════════════════════════════════════════╣ -║ ║ -║ SSH Commands: ║ -║ ────────────────────────────────────────────────────── ║ -║ km-ssh-new [comment] [file] [type] Create SSH key ║ -║ km-ssh-ls List SSH public keys ║ -║ km-ssh-copy [pubkey_file] Copy pubkey to clipboard║ -║ km-ssh-rm Delete SSH key pair ║ -║ ║ -║ GPG Commands: ║ -║ ────────────────────────────────────────────────────── ║ -║ km-gpg-new Create key (interactive)║ -║ km-gpg-quick-new \"Name\" \"Email\" [exp] Create key (quick) ║ -║ km-gpg-ls [-s|--secret] List keys ║ -║ km-gpg-pub Export public key ║ -║ km-gpg-priv Export secret key ║ -║ km-gpg-copy Copy pubkey to clipboard║ -║ km-gpg-fp Show fingerprint ║ -║ km-gpg-rm Delete key ║ -║ ║ -╚═══════════════════════════════════════════════════════════════╝" +"${_km_bold}keyman${_km_reset} — SSH & GPG Key Manager + +${_km_cyan}Usage:${_km_reset} + keyman [args...] + keyman help + +${_km_cyan}SSH Commands:${_km_reset} + keyman ssh new [comment] [file] [type] Create SSH key + keyman ssh ls List SSH public keys + keyman ssh copy [pubkey_file] Copy pubkey to clipboard + keyman ssh rm Delete SSH key pair + +${_km_cyan}GPG Commands:${_km_reset} + keyman gpg new Create key (interactive) + keyman gpg quick-new \"Name\" \"Email\" [exp] Create key (quick) + keyman gpg ls [-s|--secret] List keys + keyman gpg pub Export public key + keyman gpg priv Export secret key + keyman gpg copy Copy pubkey to clipboard + keyman gpg fp Show fingerprint + keyman gpg rm Delete key" ) ;; esac @@ -252,12 +264,11 @@ function { } # ===================================================== -# SSH Commands +# SSH Actions # ===================================================== -# Create SSH key -# Usage: km-ssh-new [comment] [keyfile] [type] -km-ssh-new() { +# keyman ssh new [comment] [keyfile] [type] +_km_ssh_new() { local comment="${1:-${USER:-$(whoami)}@${HOST:-$(hostname)}}" local keyfile="${2:-}" local keytype="${3:-}" @@ -338,8 +349,8 @@ km-ssh-new() { fi } -# List all SSH public keys -km-ssh-ls() { +# keyman ssh ls +_km_ssh_ls() { local found=0 if [[ ! -d "$HOME/.ssh" ]]; then @@ -373,9 +384,8 @@ km-ssh-ls() { fi } -# Copy SSH public key to clipboard -# Usage: km-ssh-copy [keyfile] -km-ssh-copy() { +# keyman ssh copy [keyfile] +_km_ssh_copy() { local pubkey="${1:-$HOME/.ssh/id_ed25519.pub}" [[ "$pubkey" != *.pub ]] && pubkey="${pubkey}.pub" @@ -393,9 +403,8 @@ km-ssh-copy() { fi } -# Delete SSH key pair -# Usage: km-ssh-rm -km-ssh-rm() { +# keyman ssh rm +_km_ssh_rm() { if [[ -z "${1:-}" ]]; then _km_err "${_km_msg[usage_ssh_rm]}" return 1 @@ -426,15 +435,16 @@ km-ssh-rm() { } # ===================================================== -# GPG Commands +# GPG Actions # ===================================================== -# Create GPG key (interactive) -alias km-gpg-new='gpg --full-generate-key' +# keyman gpg new (interactive) +_km_gpg_new() { + gpg --full-generate-key +} -# Create GPG key (non-interactive) -# Usage: km-gpg-quick-new "Name" "Email" [expiry] -km-gpg-quick-new() { +# keyman gpg quick-new "Name" "Email" [expiry] +_km_gpg_quick_new() { if [[ -z "${1:-}" || -z "${2:-}" ]]; then _km_err "${_km_msg[usage_gpg_quick_new]}" return 1 @@ -479,9 +489,8 @@ EOF fi } -# List GPG keys -# Usage: km-gpg-ls [--secret|-s] -km-gpg-ls() { +# keyman gpg ls [--secret|-s] +_km_gpg_ls() { if [[ "$1" == "--secret" || "$1" == "-s" ]]; then _km_info "${_km_msg[gpg_secret_key_list]}" echo "" @@ -493,9 +502,8 @@ km-gpg-ls() { fi } -# Export GPG public key -# Usage: km-gpg-pub -km-gpg-pub() { +# keyman gpg pub +_km_gpg_pub() { if [[ -z "${1:-}" ]]; then _km_err "${_km_msg[usage_gpg_pub]}" return 1 @@ -512,9 +520,8 @@ km-gpg-pub() { gpg --armor --export "$key_id" } -# Export GPG secret key -# Usage: km-gpg-priv -km-gpg-priv() { +# keyman gpg priv +_km_gpg_priv() { if [[ -z "${1:-}" ]]; then _km_err "${_km_msg[usage_gpg_priv]}" return 1 @@ -537,9 +544,8 @@ km-gpg-priv() { fi } -# Copy GPG public key to clipboard -# Usage: km-gpg-copy -km-gpg-copy() { +# keyman gpg copy +_km_gpg_copy() { if [[ -z "${1:-}" ]]; then _km_err "${_km_msg[usage_gpg_copy]}" return 1 @@ -557,9 +563,8 @@ km-gpg-copy() { fi } -# Show GPG key fingerprint -# Usage: km-gpg-fp -km-gpg-fp() { +# keyman gpg fp +_km_gpg_fp() { if [[ -z "${1:-}" ]]; then _km_err "${_km_msg[usage_gpg_fp]}" return 1 @@ -567,9 +572,8 @@ km-gpg-fp() { gpg --fingerprint "$1" } -# Delete GPG key -# Usage: km-gpg-rm -km-gpg-rm() { +# keyman gpg rm +_km_gpg_rm() { if [[ -z "${1:-}" ]]; then _km_err "${_km_msg[usage_gpg_rm]}" return 1 @@ -593,8 +597,154 @@ km-gpg-rm() { } # ===================================================== -# Help +# Main dispatcher # ===================================================== keyman() { - print -r -- "${_km_msg[help_text]}" + local group="${1:-help}" + local action="${2:-}" + shift 2 2>/dev/null + + case "$group" in + help|-h|--help) + print -r -- "${_km_msg[help_text]}" + ;; + ssh) + case "$action" in + new) _km_ssh_new "$@" ;; + ls) _km_ssh_ls "$@" ;; + copy) _km_ssh_copy "$@" ;; + rm) _km_ssh_rm "$@" ;; + *) + _km_err "$(printf "${_km_msg[unknown_ssh_action]}" "$action")" + return 1 + ;; + esac + ;; + gpg) + case "$action" in + new) _km_gpg_new "$@" ;; + quick-new) _km_gpg_quick_new "$@" ;; + ls) _km_gpg_ls "$@" ;; + pub) _km_gpg_pub "$@" ;; + priv) _km_gpg_priv "$@" ;; + copy) _km_gpg_copy "$@" ;; + fp) _km_gpg_fp "$@" ;; + rm) _km_gpg_rm "$@" ;; + *) + _km_err "$(printf "${_km_msg[unknown_gpg_action]}" "$action")" + return 1 + ;; + esac + ;; + *) + _km_err "$(printf "${_km_msg[unknown_group]}" "$group")" + return 1 + ;; + esac } + +# ===================================================== +# Zsh Completions +# ===================================================== +_keyman() { + local curcontext="$curcontext" state line + typeset -A opt_args + + _arguments -C \ + '1:command group:->group' \ + '*::args:->args' + + case "$state" in + group) + local -a groups=( + 'ssh:Manage SSH keys' + 'gpg:Manage GPG keys' + 'help:Show help message' + ) + _describe 'command group' groups + ;; + args) + case "${line[1]}" in + ssh) + _arguments -C \ + '1:ssh action:->ssh_action' \ + '*::ssh_args:->ssh_args' + + case "$state" in + ssh_action) + local -a actions=( + 'new:Create SSH key' + 'ls:List SSH public keys' + 'copy:Copy public key to clipboard' + 'rm:Delete SSH key pair' + ) + _describe 'ssh action' actions + ;; + ssh_args) + case "${line[1]}" in + new) + _arguments \ + '1:comment:' \ + '2:keyfile:_files -W "$HOME/.ssh"' \ + '3:key type:(ed25519 rsa ecdsa)' + ;; + copy) + _arguments '1:public key file:_files -W "$HOME/.ssh" -g "*.pub"' + ;; + rm) + local -a keys + if [[ -d "$HOME/.ssh" ]]; then + keys=("$HOME"/.ssh/id_*(N:t)) + keys=(${keys:#*.pub}) + fi + _describe 'SSH key' keys + ;; + esac + ;; + esac + ;; + gpg) + _arguments -C \ + '1:gpg action:->gpg_action' \ + '*::gpg_args:->gpg_args' + + case "$state" in + gpg_action) + local -a actions=( + 'new:Create GPG key (interactive)' + 'quick-new:Create GPG key (quick)' + 'ls:List GPG keys' + 'pub:Export public key' + 'priv:Export secret key' + 'copy:Copy public key to clipboard' + 'fp:Show fingerprint' + 'rm:Delete GPG key' + ) + _describe 'gpg action' actions + ;; + gpg_args) + case "${line[1]}" in + ls) + _arguments '1:option:(--secret -s)' + ;; + quick-new) + _arguments \ + '1:name:' \ + '2:email:' \ + '3:expiry:(1y 2y 3y 5y 0)' + ;; + pub|priv|copy|fp|rm) + local -a key_ids + key_ids=(${(f)"$(gpg --list-keys --with-colons 2>/dev/null \ + | awk -F: '/^uid/{print $10}; /^pub/{print $5}')"}) + _describe 'GPG key ID or email' key_ids + ;; + esac + ;; + esac + ;; + esac + ;; + esac +} +compdef _keyman keyman