summaryrefslogtreecommitdiffstats
path: root/scripts/gen_completion.py
blob: a97f26b50e577ce8bbb4e84e3381f48582d1e516 (plain)
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
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python3
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>  GPL-2.0-only
"""Generate completions/firefly.bash from the live command registry.

    python scripts/gen_completion.py > completions/firefly.bash

No drift: groups, leaves, and per-leaf flags are read straight off the
argparse subparsers the registry builds.
"""
import argparse
from collections import defaultdict

from firefly_cli import registry
import firefly_cli.commands  # noqa: F401  triggers registration

GROUP_ORDER = ["auth", "account", "category", "tag", "tx"]


def collect():
    groups = defaultdict(dict)  # group -> {leaf: [--flag, ...]}
    for c in registry.all_commands():
        g, _, leaf = c.name.partition(" ")
        p = argparse.ArgumentParser()
        if c.args:
            c.args(p)
        opts = []
        for a in p._actions:
            opts += [s for s in a.option_strings
                     if s.startswith("--") and s != "--help"]
        groups[g][leaf] = sorted(opts)
    return groups


def render(groups):
    order = [g for g in GROUP_ORDER if g in groups]
    order += [g for g in sorted(groups) if g not in GROUP_ORDER]

    leaf_cases, group_cases = [], []
    for g in order:
        leaves = " ".join(sorted(groups[g]))
        group_cases.append(f'        {g}) leaves="{leaves}";;')
        for leaf in sorted(groups[g]):
            flags = " ".join(groups[g][leaf])
            if flags:
                leaf_cases.append(
                    f'        "{g} {leaf}")'.ljust(28) + f'leaf_opts="{flags}";;')

    return TEMPLATE.format(
        groups=" ".join(order),
        leaf_cases="\n".join(leaf_cases),
        group_cases="\n".join(group_cases),
    )


TEMPLATE = '''# bash completion for firefly (firefly-cli)
# Install: source this file, or drop it in /etc/bash_completion.d/ or
# /usr/share/bash-completion/completions/firefly
#
# Generated by scripts/gen_completion.py -- do not edit by hand.
# Regenerate when commands change (see CLAUDE.md):
#   python scripts/gen_completion.py > completions/firefly.bash

_firefly() {{
    local cur prev words cword
    _init_completion 2>/dev/null || {{
        cur="${{COMP_WORDS[COMP_CWORD]}}"
        prev="${{COMP_WORDS[COMP_CWORD-1]}}"
        words=("${{COMP_WORDS[@]}}")
        cword=$COMP_CWORD
    }}

    local global_opts="--human --url --token -h --help"
    local groups="{groups}"

    # Find the group and leaf among the words (skip the program name at 0).
    local group="" leaf="" i
    for ((i=1; i < cword; i++)); do
        local w="${{words[i]}}"
        case "$w" in
            -*) ;;                      # an option, skip
            --url|--token) ((i++));;    # option that takes a value
            *)
                if [[ -z $group ]]; then group="$w"
                elif [[ -z $leaf ]]; then leaf="$w"
                fi
                ;;
        esac
    done

    # Leaf-specific options.
    local leaf_opts=""
    case "$group $leaf" in
{leaf_cases}
    esac

    # Leaves per group.
    local leaves=""
    case "$group" in
{group_cases}
    esac

    if [[ -z $group ]]; then
        COMPREPLY=($(compgen -W "$groups $global_opts" -- "$cur"))
    elif [[ -z $leaf ]]; then
        COMPREPLY=($(compgen -W "$leaves" -- "$cur"))
    else
        COMPREPLY=($(compgen -W "$leaf_opts --help" -- "$cur"))
    fi
}}
complete -F _firefly firefly
'''


if __name__ == "__main__":
    print(render(collect()), end="")