diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-15 12:32:24 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-15 12:32:24 +0200 |
| commit | 988a0eecd522431980174910db28e45a63ff2710 (patch) | |
| tree | 80b16f8cfe907f084fac931fa35326c7f2892a9d /packages/meshbay-cli/src/meshbay_cli/commands/completion.py | |
| parent | e0a1036e0fee15b3c6c83f3e935d50f472a2e776 (diff) | |
| download | meshbay-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.py | 96 |
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 |