dry-cli-autocomplete 0.1.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -7
- data/CLAUDE.md +34 -21
- data/README.md +104 -10
- data/Rakefile +2 -2
- data/{SPECIFICATION.md → docs/SPECIFICATION.md} +3 -0
- data/lib/dry/cli/autocomplete/command.rb +1 -1
- data/lib/dry/cli/autocomplete/emitters/bash.rb +2 -2
- data/lib/dry/cli/autocomplete/emitters/zsh.rb +2 -2
- data/lib/dry/cli/autocomplete/spec_builder.rb +2 -2
- data/lib/dry/cli/autocomplete/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e13789705a3120d92019f20ba4bb4c7619a2b76c3d5fe99639dd9ba29c96696
|
|
4
|
+
data.tar.gz: dba1d9805eb867d76c1c547f688dbadea1ece6714fc73cef2bcd1c93c30a62c3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 207eb7f84aea51e36d8a5ed3e08a45a5b2f278d1c3cf5d42e408d2caa353ce35b91514889390aba9298c851882e1d3eb25b3582084c32e68ef1f969f3b4443c8
|
|
7
|
+
data.tar.gz: bbeed56314a20aec94d8fabd92e43532c316d470348a546ae952a70ace686e84209fb22d99bf1fb3a7b6a529b1e2785d2fe0b57b80ec05cb1fa16074eea3bc7a
|
data/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-09-16
|
|
4
|
+
|
|
5
|
+
Documentation only; no change to the gem's behaviour.
|
|
6
|
+
|
|
7
|
+
- The README now matches the generated scripts. The bash example is real output, a zsh excerpt is included, and it documents `file:` on arguments and the name-based file guess, `program_name:`, option and positional values, `eval` for bash, placing the zsh `eval` after `compinit`, and Ruby 4.0.
|
|
8
|
+
- The specification moved to `docs/SPECIFICATION.md` and is marked as describing version 0.1.0. It is no longer part of the YARD docs.
|
|
9
|
+
- The YARD docs title names this gem instead of an unrelated project.
|
|
10
|
+
- Added a warning about AI contributions and an author section to the README.
|
|
11
|
+
|
|
3
12
|
## [0.1.3] - 2026-08-23
|
|
4
13
|
|
|
5
|
-
- The zsh script now registers itself when sourced. `eval "$(mycli completion zsh)"`
|
|
6
|
-
|
|
7
|
-
answered with `_tags:comptags:36: can only be called from completion function`.
|
|
8
|
-
The script now calls itself when autoloaded from `$fpath` and calls `compdef`
|
|
9
|
-
when sourced, so both work.
|
|
10
|
-
- The zsh function is named `_mycli` rather than `_mycli_completions`, matching
|
|
11
|
-
the name a `#compdef` file is autoloaded under. The bash function is unchanged.
|
|
14
|
+
- The zsh script now registers itself when sourced. `eval "$(mycli completion zsh)"` previously ran the completion function outside a completion context, and zsh answered with `_tags:comptags:36: can only be called from completion function`. The script now calls itself when autoloaded from `$fpath` and calls `compdef` when sourced, so both work.
|
|
15
|
+
- The zsh function is named `_mycli` rather than `_mycli_completions`, matching the name a `#compdef` file is autoloaded under. The bash function is unchanged.
|
|
12
16
|
|
|
13
17
|
## [0.1.2] - 2026-08-22
|
|
14
18
|
|
data/CLAUDE.md
CHANGED
|
@@ -6,9 +6,9 @@ Guidance for Claude Code (claude.ai/code) working in this repository.
|
|
|
6
6
|
|
|
7
7
|
A Ruby gem that generates static shell completion scripts for any `Dry::CLI` application. A host registers one command; `mycli completion bash` prints a script; the user evaluates it from a shell profile.
|
|
8
8
|
|
|
9
|
-
**Read `SPECIFICATION.md` first.** It carries the design decisions, the measurements behind them, and the acceptance criteria. This file covers how to work in the repository; that one covers what to build and why.
|
|
9
|
+
**Read `docs/SPECIFICATION.md` first.** It carries the design decisions, the measurements behind them, and the acceptance criteria. This file covers how to work in the repository; that one covers what to build and why.
|
|
10
10
|
|
|
11
|
-
The gem is
|
|
11
|
+
The gem is implemented and released (tags `v0.1.0` through `v0.1.3`). `README.md` documents the host-facing behaviour; keep it in step with `lib/` when behaviour changes.
|
|
12
12
|
|
|
13
13
|
## Environment
|
|
14
14
|
|
|
@@ -23,11 +23,12 @@ bundle install
|
|
|
23
23
|
bundle exec rspec # the suite
|
|
24
24
|
bundle exec rubocop # the linter
|
|
25
25
|
bundle exec rubocop -a # autocorrect
|
|
26
|
-
bundle exec rake #
|
|
26
|
+
bundle exec rake # the suite only; it is the default task and what CI runs
|
|
27
|
+
bundle exec rake doc # YARD documentation
|
|
27
28
|
bin/console # IRB with the gem loaded
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
The gemspec sets `required_ruby_version >=
|
|
31
|
+
The gemspec sets `required_ruby_version >= 4.0`, `.rubocop.yml` sets `TargetRubyVersion: 4.0`, and CI runs Ruby 4.0.6. Keep them in step: raising one without the other produces a linter that permits syntax the gemspec claims to support, or the reverse.
|
|
31
32
|
|
|
32
33
|
## The trap that has already bitten this repository once
|
|
33
34
|
|
|
@@ -43,6 +44,8 @@ module Dry
|
|
|
43
44
|
|
|
44
45
|
`lib/dry/cli/autocomplete/version.rb` deliberately does **not** `require "dry/cli"`, because the gemspec loads it at build time when the dependency may not be installed. It reopens `class CLI` on its own. dry-cli's `CLI` inherits from `Object`, so an empty reopening is compatible whichever loads first.
|
|
45
46
|
|
|
47
|
+
The same lexical scoping bites constants. Every file here sits inside `module Dry`, so a bare `Struct` or `Data` resolves to `Dry::Struct` or `Dry::Data` first when a host has loaded them. Write `::Data` and `::Struct`. `spec/dry/cli/autocomplete/dry_struct_host_spec.rb` loads dry-struct to catch this.
|
|
48
|
+
|
|
46
49
|
For deriving names at runtime, use `dry-inflector`. `Dry::Inflector.new { |i| i.acronym("CLI") }` handles both the casing above and the `underscore` needed for shell function identifiers. `Dry::CLI::Inflector` ships with dry-cli but only has `dasherize` and is marked `@api private`; do not depend on it.
|
|
47
50
|
|
|
48
51
|
## Architecture
|
|
@@ -58,31 +61,41 @@ Four pieces, and the boundary between the first and the rest is load-bearing.
|
|
|
58
61
|
|
|
59
62
|
Two rules hold this shape together, both measured rather than assumed:
|
|
60
63
|
|
|
61
|
-
- **The command shim loads no emitter.** A host pays nothing at boot for a command run once per shell. `SPECIFICATION.md` §2.4.
|
|
62
|
-
- **The spec builder touches only the registry.** It must be safe to run at shell startup, because it runs at every shell startup. `SPECIFICATION.md` §2.2.
|
|
64
|
+
- **The command shim loads no emitter.** A host pays nothing at boot for a command run once per shell. `docs/SPECIFICATION.md` §2.4.
|
|
65
|
+
- **The spec builder touches only the registry.** It must be safe to run at shell startup, because it runs at every shell startup. `docs/SPECIFICATION.md` §2.2.
|
|
66
|
+
|
|
67
|
+
`SpecBuilder` returns frozen `::Data` values: a `CompletionSpec` holding one `Node` per visible command or group, each with `OptionSpec` and `ArgumentSpec` entries. An argument is a file argument when it declares `file: true`, or, with no `file:` key, when its name matches `/file|path/i`.
|
|
63
68
|
|
|
64
69
|
The emitters take the same description and share no code. A fourth shell should be a new emitter class, never a branch inside an existing one.
|
|
65
70
|
|
|
66
71
|
## Conventions
|
|
67
72
|
|
|
68
|
-
- **The generator is not a hot path.** It runs in 0.067ms against a 27-command registry. Do not optimise it, do not add native extensions, and do not cache anything. The reasoning is in `SPECIFICATION.md` §2.3.
|
|
73
|
+
- **The generator is not a hot path.** It runs in 0.067ms against a 27-command registry. Do not optimise it, do not add native extensions, and do not cache anything. The reasoning is in `docs/SPECIFICATION.md` §2.3.
|
|
69
74
|
- **Read a registry through its methods, not its ivars.** `registry.get(path)` returns a result exposing `command`, `children` and `names`. `instance_variable_get(:@node)` is what the gem this one replaces does, and it will break on a dry-cli release. Do not mistake this for a public API: in 1.4.1 `Registry#get`, all of `CommandRegistry`, every `LookupResult` reader and every `Node` reader carry `@api private`. There is no public way to enumerate a registry, so an upgrade can break the walk and the fixture suite is what catches it.
|
|
70
|
-
- **Test against registries this project did not write.** A generator tested against one CLI encodes that CLI's shape. `SPECIFICATION.md` §5.
|
|
71
|
-
- **Validate generated shell with the shell.** `bash -n` and `zsh -n` parse without executing. A regex over generated output proves nothing about whether it runs.
|
|
75
|
+
- **Test against registries this project did not write.** A generator tested against one CLI encodes that CLI's shape. `docs/SPECIFICATION.md` §5.
|
|
76
|
+
- **Validate generated shell with the shell.** `bash -n` and `zsh -n` parse without executing. A regex over generated output proves nothing about whether it runs. `spec/support/shell_helpers.rb` skips a missing shell locally and fails on CI.
|
|
77
|
+
- **Emitter output is pinned by golden files** in `spec/support/golden/`. A deliberate output change means updating the golden file in the same commit.
|
|
78
|
+
- **The bash emitter targets bash 3.2.** macOS ships it as `/bin/bash`, so no associative arrays.
|
|
79
|
+
- **The zsh script works both from `$fpath` and from `eval`.** Its footer checks `$funcstack[1]` against the function name, so the function must stay named `_<program>`.
|
|
72
80
|
- **Commit messages**: imperative mood, 50-character subject, no full stop. A body only where the change needs explaining, saying what and why.
|
|
73
81
|
- **Writing prose here**: no em dashes, active voice, plain words. Say what a thing does, not how it feels. If a sentence could appear unchanged in another project's README, it says nothing about this one and should go.
|
|
74
82
|
|
|
75
83
|
## Repository layout
|
|
76
84
|
|
|
77
|
-
| Path | What it is
|
|
78
|
-
| ------------------------------------- |
|
|
79
|
-
| `SPECIFICATION.md`
|
|
80
|
-
| `
|
|
81
|
-
| `
|
|
82
|
-
| `
|
|
83
|
-
| `
|
|
84
|
-
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
| Path | What it is |
|
|
86
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
87
|
+
| `docs/SPECIFICATION.md` | What to build, why, and what "done" means |
|
|
88
|
+
| `README.md` | Host-facing documentation |
|
|
89
|
+
| `CHANGELOG.md` | Release notes |
|
|
90
|
+
| `lib/dry/cli/autocomplete.rb` | Entry point for `require "dry/cli/autocomplete"`. Hosts require `command.rb` instead |
|
|
91
|
+
| `lib/dry-cli-autocomplete.rb` | Bundler-style entry point, requires the one above |
|
|
92
|
+
| `lib/dry/cli/autocomplete/version.rb` | Version, loaded standalone by the gemspec |
|
|
93
|
+
| `sig/` | RBS signatures. Only `VERSION` is declared so far |
|
|
94
|
+
| `spec/support/fixtures/` | Registries the suite walks, including shapes modelled on other CLIs |
|
|
95
|
+
| `spec/support/golden/` | Expected bash and zsh output, compared byte for byte |
|
|
96
|
+
| `.github/workflows/main.yml` | CI: installs zsh, runs `bundle exec rake` |
|
|
97
|
+
| `.github/workflows/rubocop.yml` | CI: runs `bundle exec rubocop` |
|
|
98
|
+
|
|
99
|
+
## Releasing
|
|
100
|
+
|
|
101
|
+
Bump `VERSION` in `lib/dry/cli/autocomplete/version.rb`, add a `CHANGELOG.md` entry, then `bundle exec rake release`. The gemspec requires MFA for pushes. The `dry-` prefix and the `Dry::CLI::Autocomplete` namespace imply an affiliation with dry-rb that does not exist; the README says so, and that note should stay.
|
data/README.md
CHANGED
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
Shell completion for [dry-cli](https://github.com/dry-rb/dry-cli) applications, with no Ruby in the TAB path.
|
|
6
6
|
|
|
7
7
|
> [!NOTE]
|
|
8
|
-
> For the specification of this gem see [SPECIFICATION](SPECIFICATION.md)
|
|
8
|
+
> For the original specification of this gem see [SPECIFICATION](docs/SPECIFICATION.md)
|
|
9
|
+
|
|
10
|
+
______________________________________________________________________
|
|
11
|
+
|
|
12
|
+
> [!WARNING]
|
|
13
|
+
> This gem was written with a collaboration with Claude Code. Most of the ruby was written by a human (myself), reviewed and pushed to GitHub by Claude (anyone loves writing commit descriptions?). The part where Claude authored the most code is the ZSH autocompletion code as I'm less familiar with it than BASH. If you prefer not to use gems that had some AI contributions that were reviewed by a human, do not use this gem.
|
|
9
14
|
|
|
10
15
|
Your CLI knows its own commands, options, aliases and enum values. The shell does not. This gem walks your registry once, prints a bash or zsh script, and you source it from your profile. Pressing TAB then spawns nothing and costs nothing, because every completion the script will ever offer is already inside it.
|
|
11
16
|
|
|
@@ -41,6 +46,28 @@ There is a dependency argument too. `completely` pulls `colsole`, `docopt_ng` an
|
|
|
41
46
|
Given this registry:
|
|
42
47
|
|
|
43
48
|
```ruby
|
|
49
|
+
class Version < Dry::CLI::Command
|
|
50
|
+
desc "Print the version"
|
|
51
|
+
option :format, values: %w[json plain], desc: "Output format"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class Deploy < Dry::CLI::Command
|
|
55
|
+
desc "Deploy the application"
|
|
56
|
+
option :force, type: :boolean, aliases: ["-f"], desc: "Skip confirmation"
|
|
57
|
+
argument :environment, values: %w[staging production], required: true, desc: "Target environment"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class DbStatus < Dry::CLI::Command
|
|
61
|
+
desc "Show pending migrations"
|
|
62
|
+
option :verbose, type: :boolean, desc: "Print full migration history"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class DbMigrate < Dry::CLI::Command
|
|
66
|
+
desc "Run pending migrations"
|
|
67
|
+
option :step, desc: "Migrate to a specific step"
|
|
68
|
+
argument :file, desc: "Migration file to run"
|
|
69
|
+
end
|
|
70
|
+
|
|
44
71
|
register "version", Version
|
|
45
72
|
register "deploy", Deploy
|
|
46
73
|
register "db", DbStatus do |prefix|
|
|
@@ -49,17 +76,23 @@ end
|
|
|
49
76
|
register "secret", Secret, hidden: true
|
|
50
77
|
```
|
|
51
78
|
|
|
52
|
-
`mycli completion bash` prints a `complete -F` function
|
|
79
|
+
`mycli completion bash` prints a `complete -F` function. It walks `COMP_WORDS` to find the command path under the cursor, answers option values first, then offers that path's words:
|
|
53
80
|
|
|
54
81
|
```bash
|
|
55
82
|
_mycli_completions() {
|
|
56
83
|
# ...walks COMP_WORDS to find the current command path...
|
|
84
|
+
|
|
85
|
+
case "$path:$prev" in
|
|
86
|
+
"version:--format") COMPREPLY=($(compgen -W "json plain" -- "$cur")); return ;;
|
|
87
|
+
esac
|
|
88
|
+
|
|
57
89
|
words=""
|
|
58
90
|
case "$path" in
|
|
59
91
|
"") words="version deploy db" ;;
|
|
60
92
|
"version") words="--format" ;;
|
|
61
|
-
"deploy") words="--force -f" ;;
|
|
93
|
+
"deploy") words="--force -f staging production" ;;
|
|
62
94
|
"db") words="migrate --verbose" ;;
|
|
95
|
+
"db migrate") words="--step" ;;
|
|
63
96
|
esac
|
|
64
97
|
|
|
65
98
|
COMPREPLY=($(compgen -W "$words" -- "$cur"))
|
|
@@ -70,17 +103,59 @@ _mycli_completions() {
|
|
|
70
103
|
complete -F _mycli_completions mycli
|
|
71
104
|
```
|
|
72
105
|
|
|
73
|
-
Read what that output proves
|
|
106
|
+
Read what that output proves:
|
|
107
|
+
|
|
108
|
+
- `db` offers `migrate` alongside its own `--verbose`, so a group with both a command and children keeps both.
|
|
109
|
+
- `db migrate` gets real file completion.
|
|
110
|
+
- `secret` is absent, because hidden commands stay hidden.
|
|
111
|
+
- The `-f` alias on `deploy` is there because you declared it.
|
|
112
|
+
- `mycli version --format <TAB>` offers `json plain`, and nothing else.
|
|
113
|
+
- `mycli deploy <TAB>` offers `staging production`, the values declared on the positional.
|
|
114
|
+
|
|
115
|
+
The script uses no associative arrays, so it runs under the bash 3.2 that macOS ships as `/bin/bash`.
|
|
116
|
+
|
|
117
|
+
`mycli completion zsh` prints a native `#compdef` script. Options go through `_arguments` with their `desc` as help text, subcommands go through `_describe` with the command's `desc`, declared values become a value list, and file arguments use `_files`:
|
|
118
|
+
|
|
119
|
+
```zsh
|
|
120
|
+
('deploy')
|
|
121
|
+
_arguments -s \
|
|
122
|
+
'--force[Skip confirmation]' \
|
|
123
|
+
'-f[Skip confirmation]' \
|
|
124
|
+
'*:Target environment:(staging production)' && ret=0
|
|
125
|
+
;;
|
|
126
|
+
('db')
|
|
127
|
+
_arguments -s \
|
|
128
|
+
'--verbose[Print full migration history]' && ret=0
|
|
129
|
+
commands=(
|
|
130
|
+
'migrate:Run pending migrations'
|
|
131
|
+
)
|
|
132
|
+
_describe -t commands 'db command' commands && ret=0
|
|
133
|
+
;;
|
|
134
|
+
```
|
|
74
135
|
|
|
75
|
-
|
|
136
|
+
### Enum values
|
|
76
137
|
|
|
77
|
-
|
|
138
|
+
Values declared on an option or argument come through at no cost:
|
|
78
139
|
|
|
79
140
|
```ruby
|
|
80
|
-
option :format, values: %w[json yaml table] # completes json yaml table
|
|
141
|
+
option :format, values: %w[json yaml table] # completes json yaml table after --format
|
|
81
142
|
argument :component, values: %w[major minor] # completes major minor
|
|
82
143
|
```
|
|
83
144
|
|
|
145
|
+
### File arguments
|
|
146
|
+
|
|
147
|
+
An argument completes file paths when it declares `file: true`. Without that key, the generator treats any argument whose name contains `file` or `path` as a file argument. Declare `file: false` to opt out of the guess:
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
argument :output, file: true # completes paths
|
|
151
|
+
argument :path, file: false # does not, despite the name
|
|
152
|
+
argument :config_file # completes paths, by name
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Program names
|
|
156
|
+
|
|
157
|
+
Shell function names derive from the program name. A program installed as `my-tool` gets `_my_tool_completions` in bash and `_my_tool` in zsh.
|
|
158
|
+
|
|
84
159
|
## Installation
|
|
85
160
|
|
|
86
161
|
```bash
|
|
@@ -105,19 +180,33 @@ end
|
|
|
105
180
|
|
|
106
181
|
That require pulls in the command class and nothing else. No emitter loads until someone actually runs `mycli completion`.
|
|
107
182
|
|
|
183
|
+
The command reads the program name from `$PROGRAM_NAME` when it runs. If your executable can be invoked under a different name, such as through a wrapper or a binstub, pin it:
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
register "completion", Dry::CLI::Autocomplete::Command[MyCLI, program_name: "mycli"]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The command takes one required argument, `bash` or `zsh`, and prints the script to standard output.
|
|
190
|
+
|
|
108
191
|
Then have your users write the script once and source it. For bash:
|
|
109
192
|
|
|
110
193
|
```bash
|
|
111
194
|
mycli completion bash > /usr/local/etc/bash_completion.d/mycli
|
|
112
195
|
```
|
|
113
196
|
|
|
197
|
+
Or evaluate it from `.bashrc`:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
eval "$(mycli completion bash)"
|
|
201
|
+
```
|
|
202
|
+
|
|
114
203
|
For zsh, put it anywhere on your `$fpath`:
|
|
115
204
|
|
|
116
205
|
```bash
|
|
117
206
|
mycli completion zsh > "${fpath[1]}/_mycli"
|
|
118
207
|
```
|
|
119
208
|
|
|
120
|
-
Sourcing it from `.zshrc` works too, if you would rather not manage a file:
|
|
209
|
+
Sourcing it from `.zshrc` works too, if you would rather not manage a file. Place the line after `compinit`, since the script calls `compdef` to register itself:
|
|
121
210
|
|
|
122
211
|
```bash
|
|
123
212
|
eval "$(mycli completion zsh)"
|
|
@@ -155,19 +244,24 @@ The same table explains two other decisions. The generator will not be optimised
|
|
|
155
244
|
|
|
156
245
|
## Development
|
|
157
246
|
|
|
158
|
-
Ruby
|
|
247
|
+
Ruby 4.0 or newer, matching the gemspec and CI. This repository uses rbenv, so activate it first:
|
|
159
248
|
|
|
160
249
|
```bash
|
|
161
250
|
eval "$(rbenv init -)"
|
|
162
251
|
bundle install
|
|
163
252
|
bundle exec rspec # the suite
|
|
164
253
|
bundle exec rubocop # the linter
|
|
165
|
-
bundle exec rake #
|
|
254
|
+
bundle exec rake # the suite, and the default task
|
|
255
|
+
bundle exec rake doc # YARD documentation
|
|
166
256
|
bin/console # IRB with the gem loaded
|
|
167
257
|
```
|
|
168
258
|
|
|
169
259
|
Two conventions in the suite are worth knowing before you add to it. Fixtures include registries this project did not write, because a generator tested against one CLI quietly encodes that CLI's shape. And generated scripts are validated by the shells themselves, with `bash -n` and `zsh -n` parsing without executing, since a regex over the output proves nothing about whether it runs.
|
|
170
260
|
|
|
261
|
+
## Author
|
|
262
|
+
|
|
263
|
+
- Konstantin Gredeskoul pairing with Claude Code. Every line has been reviewed and co-written by a human. The commits were pushed by Claude to save time writing comment descriptions.
|
|
264
|
+
|
|
171
265
|
## Contributing
|
|
172
266
|
|
|
173
267
|
Bug reports and pull requests are welcome at <https://github.com/kigster/dry-cli-autocomplete>.
|
data/Rakefile
CHANGED
|
@@ -29,8 +29,8 @@ end
|
|
|
29
29
|
task build: :permissions
|
|
30
30
|
|
|
31
31
|
YARD::Rake::YardocTask.new(:doc) do |t|
|
|
32
|
-
t.files = %w[lib/**/*.rb
|
|
33
|
-
t.options.unshift("--title", '"
|
|
32
|
+
t.files = %w[lib/**/*.rb - README.md LICENSE.txt CHANGELOG.md]
|
|
33
|
+
t.options.unshift("--title", '"dry-cli-autocomplete: shell completion for dry-cli"')
|
|
34
34
|
t.after = -> { exec("open doc/index.html") } if RUBY_PLATFORM =~ /darwin/
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# `dry-cli-autocomplete`: Specification
|
|
2
2
|
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> This is the specification for version 0.1.0. Later versions may differ; see `CHANGELOG.md` and `README.md` for current behaviour.
|
|
5
|
+
|
|
3
6
|
Generate static shell completion scripts for any `Dry::CLI` application, from the command registry alone.
|
|
4
7
|
|
|
5
8
|
The intended use is one line in a shell profile:
|
|
@@ -12,7 +12,7 @@ module Dry
|
|
|
12
12
|
# for whatever this require pulls on *every* invocation, while the
|
|
13
13
|
# command itself runs about once per shell. The generator is required
|
|
14
14
|
# inside #call, where the cost is actually incurred. See
|
|
15
|
-
# SPECIFICATION.md §1.3 and §2.4, and the spec that pins it.
|
|
15
|
+
# docs/SPECIFICATION.md §1.3 and §2.4, and the spec that pins it.
|
|
16
16
|
class Command < Dry::CLI::Command
|
|
17
17
|
SHELLS = %w[bash zsh].freeze
|
|
18
18
|
|
|
@@ -7,7 +7,7 @@ module Dry
|
|
|
7
7
|
module Autocomplete
|
|
8
8
|
module Emitters
|
|
9
9
|
# Turns a CompletionSpec into a bash `complete -F` script.
|
|
10
|
-
# See SPECIFICATION.md §4.1: a static, case-statement walk over
|
|
10
|
+
# See docs/SPECIFICATION.md §4.1: a static, case-statement walk over
|
|
11
11
|
# COMP_WORDS resolves which node the cursor is under, then
|
|
12
12
|
# `compgen -W` fills COMPREPLY from that node's children and
|
|
13
13
|
# option flags, with `compgen -f` added where an argument is a
|
|
@@ -97,7 +97,7 @@ module Dry
|
|
|
97
97
|
def function_name = "_#{shell_identifier}_completions"
|
|
98
98
|
|
|
99
99
|
# A program installed as `my-tool` cannot name a shell function
|
|
100
|
-
# directly. See SPECIFICATION.md §4.2.
|
|
100
|
+
# directly. See docs/SPECIFICATION.md §4.2.
|
|
101
101
|
def shell_identifier
|
|
102
102
|
Dry::Inflector.new.underscore(spec.program_name.to_s).gsub(/[^A-Za-z0-9_]/, "_")
|
|
103
103
|
end
|
|
@@ -13,7 +13,7 @@ module Dry
|
|
|
13
13
|
# `_describe`, declared enum values become a `(a b c)` action, and a
|
|
14
14
|
# file argument becomes `_files`. That per-option help is the thing
|
|
15
15
|
# zsh users lose with a shim, and the reason this emitter exists.
|
|
16
|
-
# See SPECIFICATION.md §4.1.
|
|
16
|
+
# See docs/SPECIFICATION.md §4.1.
|
|
17
17
|
#
|
|
18
18
|
# Shares no code with the bash emitter by design: a fourth shell
|
|
19
19
|
# should be a new class here, never another branch inside one of
|
|
@@ -193,7 +193,7 @@ module Dry
|
|
|
193
193
|
def function_name = "_#{shell_identifier}"
|
|
194
194
|
|
|
195
195
|
# A program installed as `my-tool` cannot name a shell function
|
|
196
|
-
# directly. See SPECIFICATION.md §4.2.
|
|
196
|
+
# directly. See docs/SPECIFICATION.md §4.2.
|
|
197
197
|
def shell_identifier
|
|
198
198
|
Dry::Inflector.new.underscore(spec.program_name.to_s).gsub(/[^A-Za-z0-9_]/, "_")
|
|
199
199
|
end
|
|
@@ -9,7 +9,7 @@ module Dry
|
|
|
9
9
|
#
|
|
10
10
|
# Touches nothing beyond the registry and the command classes it
|
|
11
11
|
# already holds, so it stays cheap enough to run on every shell start.
|
|
12
|
-
# See SPECIFICATION.md §2.2 and §2.3.
|
|
12
|
+
# See docs/SPECIFICATION.md §2.2 and §2.3.
|
|
13
13
|
class SpecBuilder
|
|
14
14
|
# `::Data`, with the leading colons, and never a bare `Data`. This file
|
|
15
15
|
# is lexically inside `module Dry`, so an unqualified constant is looked
|
|
@@ -31,7 +31,7 @@ module Dry
|
|
|
31
31
|
ArgumentSpec = ::Data.define(:name, :values, :desc, :required, :file)
|
|
32
32
|
|
|
33
33
|
# A bare heuristic, used only when a host does not declare `file:`
|
|
34
|
-
# explicitly on the argument. See SPECIFICATION.md §4.3.
|
|
34
|
+
# explicitly on the argument. See docs/SPECIFICATION.md §4.3.
|
|
35
35
|
FILE_ARGUMENT_HEURISTIC = /file|path/i
|
|
36
36
|
|
|
37
37
|
def self.call(registry, program_name:)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dry-cli-autocomplete
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Gredeskoul
|
|
@@ -51,7 +51,7 @@ files:
|
|
|
51
51
|
- LICENSE.txt
|
|
52
52
|
- README.md
|
|
53
53
|
- Rakefile
|
|
54
|
-
- SPECIFICATION.md
|
|
54
|
+
- docs/SPECIFICATION.md
|
|
55
55
|
- docs/img/badge.svg
|
|
56
56
|
- justfile
|
|
57
57
|
- lefthook.yml
|
|
@@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
86
86
|
- !ruby/object:Gem::Version
|
|
87
87
|
version: '0'
|
|
88
88
|
requirements: []
|
|
89
|
-
rubygems_version: 4.0.
|
|
89
|
+
rubygems_version: 4.0.20
|
|
90
90
|
specification_version: 4
|
|
91
91
|
summary: A missing auto-complete addition for dry-cli powered Ruby CLI tools for BASH
|
|
92
92
|
& ZSH
|