Retire completed shell completion roadmaps
This commit is contained in:
@@ -1,345 +0,0 @@
|
||||
# Shell completion implementation plan
|
||||
|
||||
Status: Stages 1–8 complete.
|
||||
|
||||
Implement the [shell completion roadmap](completion.md) from baseline
|
||||
`2301872`. Follow the stages in order in one sprint. Intermediate stages may
|
||||
leave unfinished wiring or a noncompiling tree; validate the assembled result
|
||||
before calling the sprint complete. Use the existing ownership boundaries in
|
||||
[ADR 0013](../adr/0013-application-alias-routing.md),
|
||||
[ADR 0014](../adr/0014-invocation-reporting.md), and the
|
||||
[architecture policy](../policy/architecture.md). Apply the
|
||||
[testing policy](../policy/testing.md) to integration assertions. Keep protocol
|
||||
names, candidate ordering, and backend mechanics private.
|
||||
|
||||
## Stage 1: Prove the shell transport
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Use the Cobra version pinned in the root module. In a disposable prototype,
|
||||
generate scripts with `GenBashCompletionV2(w, true)`,
|
||||
`GenZshCompletion(w)`, and `GenFishCompletion(w, true)`. Give the generator
|
||||
a minimal root whose name is the installed executable basename. Do not
|
||||
install Cobra's completion command or execute its completion parser.
|
||||
2. Supply a fixture executable that handles the generated scripts' hidden
|
||||
request (`__complete` with these generator settings). Verify the actual
|
||||
arguments and replies using each script in its shell. The request carries
|
||||
the words through the cursor, including the partial word as its last
|
||||
argument; preserve an explicitly empty last argument. Check what each
|
||||
script does with the prefix of an attached value before deciding how to
|
||||
encode its replacement. Cover `--config=./par`, separated path values,
|
||||
spaces, an empty no-file reply, directory-only completion, and a partial
|
||||
short cluster. Verify the edited line, not only the printed candidate list.
|
||||
3. Use Cobra's line protocol: candidate lines with optional tab-separated
|
||||
descriptions, followed by the colon-prefixed directive integer and newline.
|
||||
Use the adapter's Cobra directive constants, not hardcoded numbers in core.
|
||||
Map command/flag/static choices and no candidates to NoFileComp, file hints
|
||||
to native file completion, and directory hints to FilterDirs. If a generated
|
||||
script cannot express the selected behavior as emitted, make the smallest
|
||||
adapter-owned script adjustment that preserves it and add a shell regression.
|
||||
In particular, verify attached-value prefix reconstruction and Fish's
|
||||
filesystem handling. Do not narrow the supported contexts to fit a script.
|
||||
4. Record the observed argument and replacement conventions in the sprint
|
||||
evidence. Carry forward only the adapter and fixtures needed for the final
|
||||
implementation; do not commit disposable prototype machinery.
|
||||
|
||||
Completion: generated scripts using Cobra v1.10.1 and exercised them through
|
||||
interactive Bash 5.3.9, Zsh 5.9, and Fish 4.2.1 with a fixture that records the
|
||||
query and the executed edited line. In the tested attached-value cases the
|
||||
query includes the entered flag and value; a static candidate contains the value
|
||||
alone, and the shell script preserves the flag prefix. Explicit empty words,
|
||||
quoted prior arguments, short clusters, file and directory hints, and no-file
|
||||
replies were exercised. Zsh's generated word splitting lost the attached flag
|
||||
context when a path contained an escaped space. Fish split quoted prior words,
|
||||
passed escapes in current words, and treated directory-only replies as ordinary
|
||||
file completion. The adapter adjusts those scripts and preserves the first `=`
|
||||
as the flag/value separator. The opt-in `TestCompletionShells` regression checks
|
||||
actual edited lines for these cases. Run it with Bash, Zsh, Fish, Python pexpect,
|
||||
and Bash completion installed using `COMMANDKIT_COMPLETION_SHELLS=1
|
||||
GOWORK=off GOTOOLCHAIN=local go test -count=1 -run '^TestCompletionShells$'
|
||||
./internal/cobra`. Zsh and Fish were extracted into a disposable directory for
|
||||
this run; the focused adapter suite and the full interactive matrix pass.
|
||||
|
||||
## Stage 2: Capture completion hints
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Add the following public API in the root package. Add
|
||||
`Completion CompletionHint` to both `FlagMeta` and `ArgumentMeta`;
|
||||
existing binding constructors and their signatures stay in place.
|
||||
|
||||
```go
|
||||
type CompletionChoice struct {
|
||||
Value string
|
||||
Description string
|
||||
}
|
||||
|
||||
type CompletionHint struct { /* private representation */ }
|
||||
|
||||
func CompleteChoices(choices ...CompletionChoice) CompletionHint
|
||||
func CompleteFiles() CompletionHint
|
||||
func CompleteDirectories() CompletionHint
|
||||
func NoCompletion() CompletionHint
|
||||
```
|
||||
|
||||
2. Represent the four strategies as a private discriminator and choice list.
|
||||
The zero hint and `NoCompletion()` are equivalent. Copy choice slices
|
||||
when constructing the hint. Capture the hint through ordinary bindings,
|
||||
repeatable bindings, and `CaptureFlags`; bridge it through
|
||||
`bridgeFlags` and `bridgeArguments` to neutral metadata. Use neutral
|
||||
strategy and choice types in `internal/commandmeta`; backend types do not
|
||||
cross the adapter boundary.
|
||||
3. Keep hints independent of binding identity, requiredness, defaults,
|
||||
repetition, and converters. Static choices are literal prefix matches and
|
||||
do not constrain accepted values. Empty choices mean no suggestions, not
|
||||
file fallback. Use ordinary boolean literals `true` and `false` for
|
||||
the built-in boolean assignment case; an application boolean binding
|
||||
without a hint has no value suggestions.
|
||||
4. Verify caller mutation of the original choice slice cannot change captured
|
||||
suggestions, repeated/captured bindings keep hints, and values absent from
|
||||
a suggestion list still reach the existing converter.
|
||||
|
||||
Completion: added the public choice and hint constructors, carried hints through
|
||||
flag and operand bindings into neutral metadata, and supplied explicit boolean
|
||||
choices for built-in help and reporting flags. Focused tests cover copied
|
||||
choices, repeated and captured bindings, the empty-choice strategy, independent
|
||||
bridge copies, and execution of values outside the suggested choices. Root,
|
||||
internal adapter, and neutral metadata package tests pass with `GOWORK=off` and
|
||||
`GOTOOLCHAIN=local`.
|
||||
|
||||
## Stage 3: Install completion as an ordinary declaration
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Add `func Completion(executable string) Command`. The parameter is the
|
||||
executable basename the operator types, independent of the human-readable
|
||||
`Identity.Name`. Use a root-only `completion` group with three runnable
|
||||
children, `bash`, `zsh`, and `fish`. Use the existing declaration and
|
||||
registration API (`New(..., Completion("app"))` or
|
||||
`app.Register(Completion("app"))`). Keep script-specific name handling
|
||||
inside completion; do not change validation of ordinary application identity.
|
||||
2. Carry a private completion-installation marker with the declaration and
|
||||
derive query availability from the committed routing snapshot. Use the
|
||||
existing registration candidate to validate collisions in either order,
|
||||
including aliases and same-batch declarations. Reserve the query's first
|
||||
token only while installed: a canonical command or alias beginning with
|
||||
that token would be shadowed by raw query dispatch. Reuse existing
|
||||
command/alias collision rules for `completion`. Do not represent the
|
||||
query as a canonical node, alias target, or public help entry.
|
||||
3. Generate scripts in the internal adapter using the transport established
|
||||
in Stage 1. Surface generator errors through ordinary presentation.
|
||||
Use `Reporter.RenderOutput` for script generation and delivery, so
|
||||
`app completion bash --quiet` follows normal reporting. Document the
|
||||
basename expected by the generated scripts; handle unsupported generator
|
||||
names at the completion boundary.
|
||||
4. Verify opt-in behavior, root-only placement, help visibility, batch
|
||||
rollback, late installation, and absence of new reserved names for an app
|
||||
that does not install completion.
|
||||
|
||||
Completion: added the root-only completion declaration and three script
|
||||
commands, with generator output delivered through the invocation reporter.
|
||||
Registration validates hidden-query collisions in either order, and the routing
|
||||
snapshot reflects committed installation. Tests cover help, quiet output,
|
||||
delivery failure, invalid basenames, opt-in behavior, collisions, rollback,
|
||||
nesting, and late installation. Fish variable names are adjusted to support
|
||||
dotted executable basenames; interactive checks of those names pass in Bash,
|
||||
Zsh, and Fish. Root and adapter package tests pass with `GOWORK=off` and
|
||||
`GOTOOLCHAIN=local`.
|
||||
|
||||
## Stage 4: Resolve the entered command context
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Add a private core completion request that separates completed words from
|
||||
the current word. Call `resolveEnteredRoute` on completed words only;
|
||||
use the snapshot's canonical metadata, resolved flag-alias context, and
|
||||
discovery context. Keep entered words unchanged. For canonical routes
|
||||
with a runnable operand owner, use the existing canonical prefix length
|
||||
to distinguish its trailing operands/options from command words.
|
||||
2. Suggest canonical child names matching the partial word while the input
|
||||
is still in command-path position. At a node with both children and
|
||||
operands, matching children take precedence; if there are no matching
|
||||
children, use the operand context when available. Check insertion against
|
||||
normal routing: resolve completed entered words plus the candidate and
|
||||
retain it only if it reaches the intended canonical child. Do not treat a
|
||||
partial alias as already entered. After a flag or operand has ended the
|
||||
command path, do not suggest children.
|
||||
3. An alias-only discovery prefix provides no command continuations, but can
|
||||
supply applicable canonical flags using discovery metadata and alias
|
||||
mappings. Unknown routes with no valid context yield no candidates.
|
||||
At root, use the installed visible commands, including built-ins and
|
||||
integrations. Exclude the protocol endpoint everywhere.
|
||||
4. Add context tests for root/group/runnable paths, a partial canonical
|
||||
child, a complete alias and alias chain, an alias-only prefix, a canonical
|
||||
child shadowed in the entered route, and flags beginning before the
|
||||
complete command path. Use existing routing rules as the oracle.
|
||||
|
||||
Completion: added private request context resolution using completed words and
|
||||
the committed routing snapshot. Canonical child candidates are checked by
|
||||
resolving the entered route with the candidate inserted; discovery-only and
|
||||
unknown contexts do not invent command continuations. Tests cover canonical
|
||||
and aliased routes, chains, scoped and discovery flag aliases, shadowed
|
||||
children, runnable operand metadata, and paths ended by flags or operands.
|
||||
The root package suite passes with `GOWORK=off` and `GOTOOLCHAIN=local`.
|
||||
|
||||
## Stage 5: Interpret flags and locate value positions
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Walk the completed tail using the same canonical and alias spellings and
|
||||
flag token rules as normal parsing. Factor shared token classification
|
||||
from `internal/cobra/flags.go` into neutral helpers where needed; keep
|
||||
backend parsing and failure wording at their current owner. The completion
|
||||
walk records supplied canonical flags, consumed operands, whether options
|
||||
ended, and any pending value flag. It does not run Cobra dispatch,
|
||||
converters, required checks, input factories, or providers.
|
||||
2. A pending value takes precedence even if the current word starts with
|
||||
a dash. For long equals forms, explicit boolean assignments, and short
|
||||
value flags in clusters, separate the value prefix from the entered
|
||||
spelling and separator. Preserve that spelling, including an alias.
|
||||
For a partially typed short cluster still accepting flag members, use its
|
||||
canonical short spellings for continuations; do not rewrite earlier members.
|
||||
A standalone `--` ends flags unless consumed as a value. After it,
|
||||
dash-looking words are operands. An unknown completed option that makes
|
||||
further interpretation ambiguous yields no suggestions.
|
||||
3. For flag-name suggestions, match canonical spellings and suppress already
|
||||
supplied singletons by canonical identity, including occurrences through
|
||||
aliases. Keep repeatable flags and the four reporting flags eligible.
|
||||
When a repeated singleton is typed anyway, still complete its value.
|
||||
4. For an operand, use the same cardinality allocation as `allocateOperands`
|
||||
in `binding.go` without required validation: include the current word
|
||||
as a placeholder, determine which binding receives that final position,
|
||||
and use its hint. Extract the cardinality calculation if necessary to avoid
|
||||
a second allocation policy. Excess operands receive no suggestions.
|
||||
When both operand and flag positions are available, an empty word uses
|
||||
the operand hint and an option-looking partial word requests flags.
|
||||
5. Test pending/attached/empty values, short clusters, scoped aliases and
|
||||
unavailable targets, repeats, booleans, option-looking values, interspersed
|
||||
operands, terminators, and optional/repeated operands before a required
|
||||
suffix. Keep existing normal execution tests green at the sprint boundary.
|
||||
|
||||
Completion: shared neutral token classification and flag lookup with normal
|
||||
parsing, and extracted operand count allocation for execution and completion.
|
||||
The completion walk records consumed flags and operands, locates pending or
|
||||
attached values, preserves entered prefixes, and filters canonical flag names
|
||||
by supplied identity. Tests cover aliases, short clusters, repeated flags,
|
||||
boolean assignments, option-looking values, terminators, interspersed operands,
|
||||
and operand cardinality. Root, adapter, and neutral metadata package tests pass
|
||||
with `GOWORK=off` and `GOTOOLCHAIN=local`.
|
||||
|
||||
## Stage 6: Assemble candidates and deliver query replies
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Produce a neutral result of candidate replacements, optional descriptions,
|
||||
or a filesystem strategy with value context. Keep prefix preservation
|
||||
distinct from matching; the adapter translates the neutral replacement
|
||||
according to the shell conventions verified in Stage 1. Do not interpret
|
||||
choice values as shell source. Normalize description line breaks and omit
|
||||
candidates the line protocol cannot represent rather than changing what
|
||||
an inserted value means. Do not add execution-time validation for these
|
||||
presentation limitations.
|
||||
2. In `Execute`, after normal receiver/context checks and before ordinary
|
||||
routing, recognize the exact raw query token only on an installed snapshot.
|
||||
Treat all following tokens as data. Split off the final word; a missing
|
||||
current-word argument is a malformed transport request, distinct from an
|
||||
empty string. Use the current snapshot on each query, including after
|
||||
later registration. Do not enter normal parsing, reporting selection,
|
||||
input preparation, or handler execution for this path.
|
||||
3. Write the adapter response only to normalized `Streams.Out`, with
|
||||
managed output delivery in ordinary mode. A valid query with no inferable
|
||||
context returns success and a NoFileComp reply. For a malformed request
|
||||
or query construction failure, return an operational outcome and, if the
|
||||
output is still usable, emit an error directive with no candidates.
|
||||
Explanations go to diagnostics, never into the reply. Preserve write
|
||||
failure evidence through normal presentation bookkeeping; do not retry
|
||||
a broken output stream. No generated script should consume ordinary
|
||||
usage guidance or debug output as a candidate.
|
||||
4. Test query dispatch via `App.Execute`, including explicit empty last word,
|
||||
no-context reply, malformed request, writer failure, hidden discovery,
|
||||
later registration, and target words containing `--quiet` and `--debug`.
|
||||
Use counter fixtures to prove target handlers, converters, factories,
|
||||
and providers are untouched. Verify no special dispatch without installation.
|
||||
|
||||
Completion: connected the installed query before normal routing and reporting
|
||||
selection, assembled neutral candidates and filesystem strategies, and routed
|
||||
protocol output through managed reporting. Invalid transport requests return an
|
||||
error directive and a separate diagnostic; write failures remain presentation
|
||||
evidence. The adapter preserves short attached prefixes through a private cue
|
||||
consumed by the generated scripts, while retaining literal choice values and
|
||||
normalizing descriptions. Query tests cover empty and malformed requests,
|
||||
aliases and discovery, later registration, callback isolation, reporting flags
|
||||
as data, and writer failure. Root and adapter package suites and the full
|
||||
interactive Bash, Zsh, and Fish transport matrix pass.
|
||||
|
||||
## Stage 7: Annotate maintained commands and examples
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Annotate static format/scope flags where their choices already come from
|
||||
fixed command metadata or literals. Use the same values as the existing
|
||||
version, config, and PromptKit command implementations; omit scope hints
|
||||
that would advertise values not supported by that installed declaration.
|
||||
Mark existing config/overlay filename flags as files where the binding
|
||||
takes a filename. Leave prompt IDs, dynamic selectors, and composite
|
||||
assignments unannotated. Do not infer domain semantics or load providers.
|
||||
2. Add explicit installation to the maintained core and composed examples.
|
||||
Demonstrate a static choice, a path hint, and an already-entered alias
|
||||
with no new runtime dependency. Include an integration-level check
|
||||
that installed hints reach completion without acquisition.
|
||||
3. Update GoDoc, the CLI reference, and consumer/example instructions with
|
||||
actual syntax, basename selection, manual script loading for each shell,
|
||||
and examples of hints. Keep the wire protocol private. Once delivered,
|
||||
update the feature status and keep alias discovery and dynamic discovery
|
||||
in deferred work.
|
||||
|
||||
Completion: annotated built-in version, configuration, and PromptKit formats,
|
||||
supported configuration scopes, and filename selections. The core and composed
|
||||
examples install completion and demonstrate choices, paths, and entered
|
||||
aliases. Integration tests verify scope availability and completion without
|
||||
input, state, acquisition, comparison, engine, or client callbacks. GoDoc, CLI,
|
||||
consumer, example, and roadmap documentation now describe the delivered scope;
|
||||
alias and dynamic discovery remain deferred. Root and both integration package
|
||||
tests pass in the local workspace, and changed Markdown links and whitespace
|
||||
checks pass.
|
||||
|
||||
## Stage 8: Validate the assembled sprint
|
||||
|
||||
Status: complete.
|
||||
|
||||
1. Exercise the generated scripts in Bash, Zsh, and Fish using a built fixture
|
||||
executable, a disposable directory with filenames and directories containing
|
||||
spaces, and isolated shell configuration. Verify actual completion output
|
||||
and replacement behavior. Cover canonical commands, an entered alias,
|
||||
static choices and descriptions, no fallback, file/directory hints in
|
||||
separated and attached values, and the empty operand/leading-dash rule.
|
||||
Use a PTY or a shell's native completion test interface where appropriate.
|
||||
Syntax checking alone is insufficient. Record shell versions and the
|
||||
commands or harness used so the evidence is reproducible.
|
||||
2. Run the root and both optional module suites under the local workspace
|
||||
procedure in [development.md](../development.md), plus the root suite
|
||||
with `GOWORK=off`. Keep shell-dependent checks outside the default Go
|
||||
suite unless the existing environment provides those shells; an absent
|
||||
shell is missing acceptance evidence, not a passing check.
|
||||
3. Verify no backend types in public declarations, no reverse optional-module
|
||||
dependency, and no changes to ordinary routing, flag acceptance, or report
|
||||
behavior outside the selected completion scope. Review documentation links,
|
||||
formatting, and the final diff. Record the actual validation results.
|
||||
|
||||
Completion: the opt-in `TestCompletionConsumerInShells` builds a CommandKit
|
||||
fixture, generates its scripts, and verifies edited invocations and displayed
|
||||
descriptions in interactive Bash 5.3.9, Zsh 5.9, and Fish 4.2.1. The fixture
|
||||
uses isolated shell configuration and paths containing spaces. Run it with
|
||||
Python pexpect, Bash completion, and the three shells available using
|
||||
`COMMANDKIT_COMPLETION_SHELLS=1 GOTOOLCHAIN=local go test -count=1 -run
|
||||
'^TestCompletionConsumerInShells$' .`. Zsh and Fish were extracted to a
|
||||
disposable directory for this run; their executable, library, Zsh module, and
|
||||
function paths were supplied through `PATH`, `LD_LIBRARY_PATH`,
|
||||
`COMPLETION_ZSH_MODULE_PATH`, and `COMPLETION_ZSH_FUNCTION_ROOT`, respectively.
|
||||
The adapter's interactive
|
||||
transport matrix and additional short-equals and Unicode-basename checks also
|
||||
pass in all three shells. The root and both optional module suites pass in the
|
||||
local workspace, as does the root suite with `GOWORK=off`. Public GoDoc and
|
||||
dependency checks show no exposed backend types or reverse optional-module
|
||||
dependency. Existing execution suites, changed documentation links, formatting,
|
||||
and diff whitespace checks pass. The local workspace file is ignored.
|
||||
Reference in New Issue
Block a user