aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-cli/src/meshbay_cli/commands/completion.py
blob: 0fc3f30fe97038baa59ad24da7f7595e64bcaf36 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"""
`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
        }
    }
    # The client writes UTF-8; Windows PowerShell reads a program's output in the
    # console's code page, which turns an accented name into another name.
    $encoding = [Console]::OutputEncoding
    try { [Console]::OutputEncoding = [Text.Encoding]::UTF8 } catch { }
    try {
        $found = @(& meshbay-cli __complete powershell $index @words 2>$null)
    } finally {
        try { [Console]::OutputEncoding = $encoding } catch { }
    }
    $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