summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-cli/src/meshbay_cli/commands/completion.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-15 12:32:24 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-15 12:32:24 +0200
commit988a0eecd522431980174910db28e45a63ff2710 (patch)
tree80b16f8cfe907f084fac931fa35326c7f2892a9d /packages/meshbay-cli/src/meshbay_cli/commands/completion.py
parente0a1036e0fee15b3c6c83f3e935d50f472a2e776 (diff)
downloadmeshbay-988a0eecd522431980174910db28e45a63ff2710.tar.gz
feat(cli): account, rm -r and mkdir, Tab completion
account shows the account and does what the sign-up form and the Profile page do: register (the passphrase floor and the hub's proof of work checked here, the recovery key printed once), verify, change the passphrase, reset a forgotten one, change the e-mail address, sign out everywhere, delete. A new passphrase carries the copy of the account's keys each node keeps for browsers first — opened under the old M, the same keys sealed under the new one — and only then tells the hub; a refusal sets the copies back. A reset restores them from the recovery copy. The connections that do it never make keys nor ask for a device approval. This machine keeps the M it changed away from, so a node out of reach is carried at its next connection; a copy under an M it does not know is no longer rewritten, which locked the browsers out after a passphrase changed elsewhere. rm -r removes a folder and all it holds, from the node's operator key: the files, then the folders deepest first, one confirmation that counts them. mkdir makes folders, --parents the missing ones (not -p, the passphrase). completion bash|powershell prints the script that makes Tab complete actions, verbs, options and the paths of the groups this machine is signed in to, cached two minutes; the deb and rpm packages install the bash one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-cli/src/meshbay_cli/commands/completion.py')
-rw-r--r--packages/meshbay-cli/src/meshbay_cli/commands/completion.py96
1 files changed, 96 insertions, 0 deletions
diff --git a/packages/meshbay-cli/src/meshbay_cli/commands/completion.py b/packages/meshbay-cli/src/meshbay_cli/commands/completion.py
new file mode 100644
index 0000000..831c012
--- /dev/null
+++ b/packages/meshbay-cli/src/meshbay_cli/commands/completion.py
@@ -0,0 +1,96 @@
+"""
+`completion`: the script that makes Tab complete meshbay-cli in a shell.
+
+bash: eval "$(meshbay-cli completion bash)" (in ~/.bashrc)
+PowerShell: meshbay-cli completion powershell | Out-String | Invoke-Expression
+ (in $PROFILE)
+
+The packages install the bash one where bash-completion finds it. Both scripts
+ask `meshbay-cli __complete` for the candidates (see `complete.py`): actions,
+verbs, options, and the remote paths of the groups this machine is signed in to.
+"""
+
+from ..errors import USAGE, CliError
+from ..output import sentence
+from .context import Context
+
+HELP = "print the script that makes Tab complete meshbay-cli in bash or PowerShell"
+
+BASH = r'''# meshbay-cli completion for bash: eval "$(meshbay-cli completion bash)"
+_meshbay_cli() {
+ local cur=${COMP_WORDS[COMP_CWORD]} line files=0
+ local -a found=()
+ while IFS= read -r line; do
+ if [[ $line == __files__ ]]; then files=1; else found+=("$line"); fi
+ done < <(command meshbay-cli __complete bash "$COMP_CWORD" "${COMP_WORDS[@]}" 2>/dev/null)
+ COMPREPLY=("${found[@]}")
+ if (( files )); then
+ local f
+ while IFS= read -r f; do COMPREPLY+=("$f"); done < <(compgen -f -- "$cur")
+ fi
+ # Quote spaces and the like as for file names; no space after a folder.
+ compopt -o filenames 2>/dev/null
+ local c
+ for c in "${COMPREPLY[@]}"; do
+ if [[ $c == */ ]]; then compopt -o nospace 2>/dev/null; break; fi
+ done
+}
+complete -F _meshbay_cli meshbay-cli
+'''
+
+POWERSHELL = r'''# meshbay-cli completion for PowerShell:
+# meshbay-cli completion powershell | Out-String | Invoke-Expression
+Register-ArgumentCompleter -Native -CommandName 'meshbay-cli', 'meshbay-cli.exe' -ScriptBlock {
+ param($wordToComplete, $commandAst, $cursorPosition)
+ $elements = @($commandAst.CommandElements)
+ $words = @($elements | ForEach-Object { $_.Extent.Text })
+ $index = $words.Count
+ for ($i = 0; $i -lt $elements.Count; $i++) {
+ $e = $elements[$i].Extent
+ if ($cursorPosition -ge $e.StartOffset -and $cursorPosition -le $e.EndOffset) {
+ $index = $i
+ }
+ }
+ $found = @(& meshbay-cli __complete powershell $index @words 2>$null)
+ $quote = {
+ param($s)
+ if ($s -match '[\s''"`$&|;(){}@,#]') { "'" + ($s -replace "'", "''") + "'" } else { $s }
+ }
+ $item = [System.Management.Automation.CompletionResult]
+ $results = @()
+ foreach ($c in $found) {
+ if ($c -eq '__files__') {
+ $sep = [IO.Path]::DirectorySeparatorChar
+ $typed = $wordToComplete.Trim([char[]]"'`"")
+ $dir = Split-Path -Path $typed -Parent
+ Get-ChildItem -Path "$typed*" -ErrorAction SilentlyContinue |
+ ForEach-Object {
+ $p = if ($dir) { Join-Path $dir $_.Name } else { $_.Name }
+ if ($_.PSIsContainer) { $p += $sep }
+ $results += $item::new((& $quote $p), $p, 'ProviderItem', $p)
+ }
+ continue
+ }
+ $results += $item::new((& $quote $c), $c, 'ParameterValue', $c)
+ }
+ $results
+}
+'''
+
+SCRIPTS = {"bash": BASH, "powershell": POWERSHELL}
+
+
+def add_parser(sub, parent) -> None:
+ p = sub.add_parser("completion", parents=[parent], help=HELP, description=sentence(HELP)
+ + '. bash: eval "$(meshbay-cli completion bash)" in ~/.bashrc; '
+ "PowerShell: meshbay-cli completion powershell | Out-String | "
+ "Invoke-Expression in $PROFILE.")
+ p.add_argument("shell", choices=tuple(SCRIPTS), help="the shell")
+
+
+async def run(ctx: Context) -> int:
+ script = SCRIPTS.get(ctx.args.shell)
+ if script is None:
+ raise CliError(USAGE, "bash or powershell.")
+ print(script, end="")
+ return 0