7.3 KiB
G-040 punk::args choice aliasing (-choicealiases) with parse normalization, display folding, and doc-lookup parity
Status: proposed
Scope: src/modules/punk/args-999999.0a1.0.tm (parse + usage rendering), src/modules/punk/ns-999999.0a1.0.tm (cmdinfo/cmd_traverse choice resolution parity), src/modules/punk-999999.0a1.0.tm (punk::help topic argdoc as first consumer), src/tests/modules/punk/args/testsuites/, src/tests/modules/punk/ns/testsuites/
Acceptance: a definition using -choicealiases parses an alias (and an alias prefix where -choiceprefix allows) to its canonical choice in the parse result, with -choicerestricted 0 passthrough and the deny/reserve lists honoured unchanged; usage display shows one entry per canonical choice with aliases folded (no duplicate rows; -choicelabels attach to the canonical); punk::ns::cmdinfo/cmd_traverse resolve subcommand words to docids with the same outcome as the parser for alias, prefix, denied, reserved and unknown words (the pre-goal characterization tests updated from pinned-GAP to fixed); punk::help's topic definition adopts the feature so i help lists one entry per registered topic while help h/help e still fall through to command lookup; definitions without -choicealiases behave unchanged (existing punk::args and punk::ns suites pass).
Context
Arose from the 2026-07-08 punk::help topic-registry restructure. The ::punk::help argdoc
declares the topic leader with -choices {topics help tcl env environment console term terminal} (-choiceprefix 0 -choicerestricted 0): every alias is its own choice entry, so
the i help usage table shows 8 entries for 4 topics, with duplicated -choicelabels.
What the existing -choice* machinery already expresses (all verified 2026-07-08 on the dev tree, punk902z src, tcl 9.0.2):
-
Prefix-shaped alias pairs collapse completely via
-choiceprefix 1plus the two lists:topic ... -choicerestricted 0 -choiceprefix 1 -choices {topics help tcl environment console terminal} -choiceprefixdenylist {help} -choiceprefixreservelist {en ter}gives:
env..environment-> normalized toenvironmentin the parse result (the parser returns the canonical choice, so downstream alias resolution needs no prefix logic);e/enpass through to the unrestricted fallthrough (the reserved phantomenblocks them without becoming selectable);term+ ->terminalwitht/te/terpassing through;helprequires the full word (denylist) soh/he/helstay available as command-fallthrough words; unknown words (lindex) pass through unchanged. -
The usage renderer self-documents the scheme: each choice cell highlights its minimal accepted prefix (bright green
envinenvironment,cinconsole), and a denied choice renders fully highlighted (type all of it). -
Minimum-prefix policy is fully controllable per word by reserving each shorter phantom (e.g. reserve
candcoto requireconfor console). Open policy question for punk::help: whether to allow the free extra prefixesc->console,to->topics,tc->tcl, which mildly shadow those words as command-fallthrough candidates.
What it cannot express - the actual feature gap:
- Aliases with no prefix relation to their canonical (
help->topics) must remain separate displayed choice entries with duplicated labels. - Even prefix-related aliases remain separate display entries when both full words are
listed (
consoleandterminalboth render, same label), because a choice entry is an atomic string with no canonicalization link.
Hence -choicealiases {alias canonical ...}: alias accepted at parse (participating in
prefix calculation like a reservelist entry, but selectable), normalized to its canonical
in the parse result, and folded in usage display (shown as an annotation on the canonical
entry - e.g. dimmed help beneath/beside topics - not as its own row). -choicelabels
keys stay canonical-only.
Approach
- punk::args::define: accept and validate
-choicealiases(each value must name an existing choice; alias must not collide with a choice or another alias). Parse layer: alias hits (exact, or unique prefix when -choiceprefix and not denied/reserved) normalize to the canonical, before -choicemultiple/-multiple accounting so duplicates collapse predictably. Usage/arg_error rendering: fold alias names into the canonical entry's cell; extend the minimal-prefix highlighting to alias words. - punk::ns cmd_traverse parity: the subcommand walk currently does its own
tcl::prefix::matchover -choices/-choicegroups and honours only-choiceprefix--choiceprefixdenylistand-choiceprefixreservelistare ignored (divergence proven:i help en-style lookups prefix-match wherehelp enexecution falls through). Factor the choice-word resolution into one shared punk::args helper (choices + groups + aliases + prefix + deny/reserve -> canonical-or-miss) consumed by both the parser and cmd_traverse, rather than a second implementation. choiceinfo lookups (subhelp et al) then key on the canonical. - punk::help adoption: registry aliases map onto -choicealiases (topics/help,
env/environment, console/term/terminal); decide and record the minimum-prefix policy
(reservelist phantoms) including the c/to/tc question above;
help topicsoutput andhelptopic::resolvestay as-is (resolve receives canonicals from the parse). - Test-first sequencing (user-directed): characterization tests for the current parse choice behaviour (prefix/deny/reserve under -choicerestricted 0, normalization) and the punk::ns cmdinfo/cmd_traverse docid flow land BEFORE this goal's implementation, with the parse-vs-traverse divergence pinned as a GAP test (fossilmove pattern). This goal flips those GAP pins to the fixed behaviour.
Alternatives considered
- Prefix mechanics alone (no new feature) - covers env|environment and term|terminal but cannot fold topics|help or unify console/terminal display; rejected as the full answer, retained as the interim option for punk::help if the feature is deferred.
- Synthesising alias folding in punk::help only (custom display, registry-side resolution)
- rejected: the duplication belongs to every ensemble-style argdoc with alias words, and cmd_traverse would still diverge; solve it in punk::args once.
- Documenting subcommand aliases via duplicate -choices entries with shared -choicelabels (status quo) - works but scales the display linearly with alias count and lets labels drift; this is the shortcoming that motivated the goal.
Notes
- Session probe scripts (scratchpad, 2026-07-08): choicecollapse.tcl (parse behaviour table for the deny/reserve/prefix recipe), choicedisplay.tcl (usage rendering of the collapsed def, minimal-prefix highlighting).
- cmd_traverse divergence site: src/modules/punk/ns-999999.0a1.0.tm ~5157 (subcommand walk
tcl::prefix::matchover allchoices; consults -choiceprefix at ~5162, never the deny/reserve lists). - Parser reservelist/denylist semantics doc: 'i punk::args::define' -choice* section (clarified 2026-07-08 alongside this goal's creation).
- Related: the punk::help topic registry (punk module 0.2.0) is the intended first consumer; the possible future punk::config-declared subshell topic sets (not yet a goal) would inherit the folding for free.