Browse Source
User-directed activation and implementation in one arc (proposed -> active at
the user's word with the activation-freshness overlap survey recorded, ->
achieved + archived on acceptance).
punk::args 0.18.0 - new parse_report: the annotated SUCCESS render (the
arg_error usage table's success-side sibling). One row per value-holding
argument (received, or -default in effect) in declaration-section order
(leaders, opts, values), columns Argument | Source | Value; Source carries
received / received xN / default (the plain-mode twin of the colour marking:
CLR(check)/CLR(parsekey_hint)); absent optionals get no row. Entry forms per
acceptance: a punk::args::parse result dict, or '<arglist> withid <id>' (the
parse is performed first - a rejected line raises the same validation error
parse would; errorcode parity pinned). Returns: table (bordered textblock
block, default), tableobject, string (plain lines; also the degraded
no-textblock path), dict (machine form - never elided). The canonical
demonstration pinned: {build punk95 -confirm 0} lands
'args (received x2) = -confirm 0' - a flag-like word consumed as a VALUE
visibly attributed to its consuming argument (the make.tcl dry-run
'kitname = punk91 -confirm 0' class from the G-143 sessions).
Display elision is type-aware, deterministic, always marked: strings
single-line-ized (ansistring VIEW -lf 1 -vt 1 -sp 0 - controls and embedded
ANSI render visibly so a value cannot disturb the table, real spaces stay
real) then grapheme-capped with '...' + ' (len N)'; -multiple/-type list
values element-capped '(+N more)'; -type dict values pair-capped
'(+N pairs)'. Width cascade per the G-149 plumbing precedent: caller
-valuewidth > new @cmd directive key -reportvaluewidth (documented in
define -help) > built-in 48; 0 = no cap; never console-derived (the G-007
emit-then-query lesson). Row data rides the G-049
private::parse_status_build structure - no second status assembler;
display-level bridging recovers the value-in-effect across the parse
result's storage-key folds (-parsekey renames, aliased optionsets'
last-|-member finalopts fold) so received aliased args keep their row -
engine-level rationalization recorded as a G-084 follow-on disposition.
The registered two-form definition (parsed/withid) follows parse_status's
structure - per-form @leaders first, then the shared @opts via a re-widened
@form selection (the resolver rejects leaders declared after a form's
options).
punk::ansi 0.2.0 - new ansistring TRUNCATE ?-ellipsis marker? string
maxgraphemes (design lean 4: the ANSI/grapheme-safe truncate primitive
homes in ansistring beside RANGE/VIEW): fits => byte-identical passthrough
(trailing and non-SGR codes included); truncation => RANGE-extracted prefix
(merged SGR re-application per the contract documented at 0.1.4) + marker
totalling exactly maxgraphemes, with an SGR reset appended before the
marker when the prefix carries codes; the marker is charged against the
budget and itself truncated when it alone meets/exceeds it; maxgraphemes 0
=> empty string. Grapheme-count based (column-aware variant a recorded
follow-on). Strict option handling (deliberately unlike VIEW's pinned
silent tolerance). Ensemble export + PUNKARGS argdoc + doctools comment.
Tests: new args/parsereport.test (13 - canonical attribution, entry
parity, dict shape/row order/row policy, solo+multi xN multiplicity,
per-type elision markers, dict-never-elided, width cascade,
single-line-ization, alias bridging, bordered/tableobject renders, failure
parity, bad calls, own-definition render); ansi/ansistring.test +2
TRUNCATE pins (budget/passthrough/errors; ANSI-reset + CJK +
combining-cluster safety). Full punk/args subtree 331 passed / 3
pre-existing skips / 0 failed and punk/ansi subtree 73/73 - each on native
tclsh90 (9.0.3) AND tclsh87; failure-side rendering unchanged per
acceptance. Minted modules/punk/args-0.18.0.tm + ansi-0.2.0.tm via
make.tcl modules; bootsupport/vfscommon promotion left to the next cycle -
make.tcl keeps its interim one-line report (and its 4-copy 'no annotated
success render yet' comment) until the promotion-gated follow-on lands.
Goals: G-151 entry moved to GOALS-archive.md, detail file to goals/archive/
with verification evidence and 5 Follow-on lines (make.tcl interim-report
retirement open; arg_error value-truncation via the same helpers open;
storage-key rationalization => goal G-084; column-aware TRUNCATE open;
word-oriented inverse view open). Activation-survey Related: lines recorded
(G-166, G-084, G-167 back-pointer); reference sweep updated G-170
(sequencing lean honoured - its dry-run arm consumes this render), G-167
archive marker, G-084 back-pointer note. src/tests/modules AGENTS.md
punk/args + punk/ansi bullets extended. goals_lint clean (83 active / 87
archived).
Claude-Session: https://claude.ai/code/session_0156PuejSCGjgeGb7jiABrDU
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
14 changed files with 1101 additions and 88 deletions
@ -1,72 +0,0 @@
|
||||
# G-151 punk::args annotated success render (received-args landing report) |
||||
|
||||
Status: proposed |
||||
Scope: src/modules/punk/args-999999.0a1.0.tm (parse-result presentation); src/tests/modules/punk/args/testsuites/args/ |
||||
Goal: punk::args can render a SUCCESSFUL parse the way arg_error renders a failed one - the usage table (or a compact per-argument report) annotated with where each received word landed: options consumed, values attributed to the argument that took them, received distinguished from defaulted - so dry-run consumers (make.tcl help today; completion/hinting later) present authoritative landing information instead of hand-assembled summaries. |
||||
Acceptance: given a successful parse result (or the words plus definition id), a punk::args surface renders per-argument received-vs-default annotation covering leaders, opts and values including -multiple aggregation - the canonical demonstration being a flag-like word consumed as a VALUE (the 'punk91 -confirm 0'-as-three-values class) visibly attributed to its consuming argument; failure-side rendering is unchanged (existing arg_error pins pass); the behaviour is pinned in the args testsuite. make.tcl retiring its interim one-line 'dry-run: line accepted ...' report in favour of this render is recorded as consumer follow-through after a bootsupport promotion, not part of this acceptance. |
||||
|
||||
## Context |
||||
|
||||
From the G-143 dry-run help sessions (2026-08-01/02 - archived detail file): the failure side has arg_error's annotated tables, but a successful dry-run had nothing showing where the supplied words landed, so make.tcl grew an interim one-line report built from the parse result's 'received' key ('dry-run: line accepted (form build) - action = build | -test = 0 | toolname = punkzip'; before bake kitnames became choice-restricted, the value-swallow clue read 'kitname = punk91 -confirm 0'). The parse result already carries received/leaders/opts/values/multis - this goal is a presentation surface over existing data, at punk::args level where every consumer (and the repl) can share it. |
||||
|
||||
## Notes |
||||
|
||||
- Related: G-050 (proposed) - synopsis argument-validity marking; the nearest sibling (status-aware marking over the same argument rows). |
||||
- Related: G-044 (proposed) - punk::args-driven completion; landing attribution is the same data completion hints from. |
||||
- Related: G-170 (proposed) - consumer: its launcher help dry-run arm renders |
||||
this goal's landing report for accepted lines (back-pointer added 2026-08-05 |
||||
with G-170's cross-link; sequencing lean recorded there). |
||||
- Related: G-149 (achieved 2026-08-05 - goals/archive/G-149-punkargs-formhint-labels.md) - configurable form-hint labels; sibling punk::args render-surface goal drafted the same session. Its landed shape (caller option on arg_error/usage + @cmd definition key, caller > definition > default precedence) is the plumbing precedent for adding a render option to the same surfaces. |
||||
- Overlap survey 2026-08-02: goals_xref paths src/modules/punk/args-999999.0a1.0.tm - the punkargs family as recorded in G-149's survey; G-050 (named above) is the closest surface, the remainder are parser/spec mechanisms. |
||||
- Design leans (user-agreed 2026-08-05, ahead of activation): |
||||
1. Shape: a COMPACT LANDING TABLE - a separate small arg_error-styled bordered |
||||
table (Argument | Source | Value) stacked under the usage render in dry-run |
||||
contexts, NOT annotation of the usage table itself (the help column already |
||||
dominates width and values are the one input authors cannot bound). The |
||||
existing -parsedargs row marking and goodchoice word marking stay as-is and |
||||
compose with it. No per-value/per-arg subtables (the -choices subtables earn |
||||
their borders as static grouped documentation; received values are transient |
||||
echo) - the report itself is the one bordered block; if G-088's footer |
||||
mechanism lands later the same content could dock into the usage table's |
||||
footer without redesign. Arg-oriented rows in declaration-section order |
||||
(leaders/opts/values); a word-oriented inverse view (word -> argument) is a |
||||
possible later -return variant, not the primary. |
||||
2. Width: deterministic caps, never console-queried (piped contexts + the |
||||
emit-then-query flush trap of G-007 (achieved - goals/archive/G-007-console-location-transparency.md); |
||||
pinned tests want deterministic output). Value column |
||||
capped ~48 for a ~80 total by default; configurable via the G-149 plumbing |
||||
precedent (caller option > @cmd definition key > default). Machine-facing |
||||
returns (-return dict) never truncate - elision is display-only. |
||||
3. Elision is type-aware and always marked (display-hint honesty): strings are |
||||
single-line-ized (newlines/tabs as visible escapes) then char-capped with |
||||
trailing '...' plus '(len N)'; lists and -multiple aggregations are |
||||
element-capped with '(+N more)'; dicts pair-capped with '(+N pairs)'. |
||||
Pre-elide at data-prep level rather than relying on the textblock table |
||||
class's per-column -maxwidth (recorded header-truncation TODOs there; and |
||||
pre-elided strings make the plain twin and test pins trivial). |
||||
4. The ANSI/grapheme-safe char-level truncate primitive lives in |
||||
punk::ansi::ansistring (beside trim/RANGE/VIEW, per the ANSI-surgery |
||||
domain rule); punk::args layers only the element/pair-count elision on |
||||
top. Precondition (user direction 2026-08-05): before modifying |
||||
ansistring, survey its test coverage against codebase usage and add |
||||
missing characterization pins so the modification has a safety net. |
||||
Survey DONE 2026-08-05 (usage-weighted: VIEW ~250 sites incl 124 '-lf 1'; |
||||
VIEWSTYLE/VIEWCODES/NEW ~40 interactive sites; RANGE 8): 8 pins added to |
||||
ansistring.test, green 71/71 on tclsh90+tcl87. Findings the implementation |
||||
must respect: RANGE re-emits MERGED code stacks (not byte-identical |
||||
round-trip) and DROPS codes trailing the last grapheme (source TODO) - a |
||||
truncate building on RANGE must fetch trailing state separately (INDEXCODE |
||||
end+1 works) if it matters; VIEW -lf 1 is the proven single-line-ization |
||||
primitive; VIEW silently tolerates unknown option pairs (overtype's |
||||
'-nul 1' sites depend on this - NUL substitution is actually always-on); |
||||
VIEWCODES/VIEWSTYLE are broken headless (bare 'a+'/'a' interactive-alias |
||||
dependency, known-deficiency pinned) - do not route the truncate through |
||||
the class view paths. |
||||
5. Serving the failure-side value-truncation todo recorded in the engine |
||||
("truncate/summarize values in error messages", args-999999.0a1.0.tm |
||||
arg_error region) with the same helper is a FOLLOW-ON, not part of this |
||||
goal's acceptance. |
||||
6. Row policy: rows only for arguments holding a value post-parse (received, |
||||
or default-in-effect - the Source column carries the received/default |
||||
distinction and is the plain-mode-safe twin of the colour marking); |
||||
absent optionals get no row. |
||||
@ -0,0 +1,175 @@
|
||||
# G-151 punk::args annotated success render (received-args landing report) |
||||
|
||||
Status: achieved 2026-08-05 |
||||
Scope: src/modules/punk/args-999999.0a1.0.tm (parse-result presentation); src/tests/modules/punk/args/testsuites/args/ |
||||
Goal: punk::args can render a SUCCESSFUL parse the way arg_error renders a failed one - the usage table (or a compact per-argument report) annotated with where each received word landed: options consumed, values attributed to the argument that took them, received distinguished from defaulted - so dry-run consumers (make.tcl help today; completion/hinting later) present authoritative landing information instead of hand-assembled summaries. |
||||
Acceptance: given a successful parse result (or the words plus definition id), a punk::args surface renders per-argument received-vs-default annotation covering leaders, opts and values including -multiple aggregation - the canonical demonstration being a flag-like word consumed as a VALUE (the 'punk91 -confirm 0'-as-three-values class) visibly attributed to its consuming argument; failure-side rendering is unchanged (existing arg_error pins pass); the behaviour is pinned in the args testsuite. make.tcl retiring its interim one-line 'dry-run: line accepted ...' report in favour of this render is recorded as consumer follow-through after a bootsupport promotion, not part of this acceptance. |
||||
|
||||
## Context |
||||
|
||||
From the G-143 dry-run help sessions (2026-08-01/02 - archived detail file): the failure side has arg_error's annotated tables, but a successful dry-run had nothing showing where the supplied words landed, so make.tcl grew an interim one-line report built from the parse result's 'received' key ('dry-run: line accepted (form build) - action = build | -test = 0 | toolname = punkzip'; before bake kitnames became choice-restricted, the value-swallow clue read 'kitname = punk91 -confirm 0'). The parse result already carries received/leaders/opts/values/multis - this goal is a presentation surface over existing data, at punk::args level where every consumer (and the repl) can share it. |
||||
|
||||
## Notes |
||||
|
||||
- Related: G-050 (proposed) - synopsis argument-validity marking; the nearest sibling (status-aware marking over the same argument rows). |
||||
- Related: G-044 (proposed) - punk::args-driven completion; landing attribution is the same data completion hints from. |
||||
- Related: G-170 (proposed) - consumer: its launcher help dry-run arm renders |
||||
this goal's landing report for accepted lines (back-pointer added 2026-08-05 |
||||
with G-170's cross-link; sequencing lean recorded there). |
||||
- Related: G-149 (achieved 2026-08-05 - goals/archive/G-149-punkargs-formhint-labels.md) - configurable form-hint labels; sibling punk::args render-surface goal drafted the same session. Its landed shape (caller option on arg_error/usage + @cmd definition key, caller > definition > default precedence) is the plumbing precedent for adding a render option to the same surfaces. |
||||
- Overlap survey 2026-08-02: goals_xref paths src/modules/punk/args-999999.0a1.0.tm - the punkargs family as recorded in G-149's survey; G-050 (named above) is the closest surface, the remainder are parser/spec mechanisms. |
||||
- Activation survey 2026-08-05 (goals_xref score G-151, per the activation-freshness |
||||
rule) - relationships not previously recorded: |
||||
- Related: G-166 (proposed) - top unlinked hit: cmdinfo/cmdhelp advisory-parse |
||||
presentation on the punk::ns side; a sibling presentation surface over parse |
||||
outcomes and a possible later consumer of this goal's landing report (cmdhelp |
||||
advisory parses of argument tails). |
||||
- Related: G-084 (proposed) - -parsekey completeness. The parse result dict this |
||||
goal renders from folds aliased optionset keys to their last |-member and |
||||
-parsekey renames storage keys; the landing report's value-in-effect lookup |
||||
bridges that fold at display level (see Progress) - G-084 is where the |
||||
storage-key model itself gets rationalized. |
||||
- Related: G-167 (proposed) - back-pointer (G-167 already references this goal): |
||||
version-delta availability marking renders over the same argument-row surfaces. |
||||
- Design leans (user-agreed 2026-08-05, ahead of activation): |
||||
1. Shape: a COMPACT LANDING TABLE - a separate small arg_error-styled bordered |
||||
table (Argument | Source | Value) stacked under the usage render in dry-run |
||||
contexts, NOT annotation of the usage table itself (the help column already |
||||
dominates width and values are the one input authors cannot bound). The |
||||
existing -parsedargs row marking and goodchoice word marking stay as-is and |
||||
compose with it. No per-value/per-arg subtables (the -choices subtables earn |
||||
their borders as static grouped documentation; received values are transient |
||||
echo) - the report itself is the one bordered block; if G-088's footer |
||||
mechanism lands later the same content could dock into the usage table's |
||||
footer without redesign. Arg-oriented rows in declaration-section order |
||||
(leaders/opts/values); a word-oriented inverse view (word -> argument) is a |
||||
possible later -return variant, not the primary. |
||||
2. Width: deterministic caps, never console-queried (piped contexts + the |
||||
emit-then-query flush trap of G-007 (achieved - goals/archive/G-007-console-location-transparency.md); |
||||
pinned tests want deterministic output). Value column |
||||
capped ~48 for a ~80 total by default; configurable via the G-149 plumbing |
||||
precedent (caller option > @cmd definition key > default). Machine-facing |
||||
returns (-return dict) never truncate - elision is display-only. |
||||
3. Elision is type-aware and always marked (display-hint honesty): strings are |
||||
single-line-ized (newlines/tabs as visible escapes) then char-capped with |
||||
trailing '...' plus '(len N)'; lists and -multiple aggregations are |
||||
element-capped with '(+N more)'; dicts pair-capped with '(+N pairs)'. |
||||
Pre-elide at data-prep level rather than relying on the textblock table |
||||
class's per-column -maxwidth (recorded header-truncation TODOs there; and |
||||
pre-elided strings make the plain twin and test pins trivial). |
||||
4. The ANSI/grapheme-safe char-level truncate primitive lives in |
||||
punk::ansi::ansistring (beside trim/RANGE/VIEW, per the ANSI-surgery |
||||
domain rule); punk::args layers only the element/pair-count elision on |
||||
top. Precondition (user direction 2026-08-05): before modifying |
||||
ansistring, survey its test coverage against codebase usage and add |
||||
missing characterization pins so the modification has a safety net. |
||||
Survey DONE 2026-08-05 (usage-weighted: VIEW ~250 sites incl 124 '-lf 1'; |
||||
VIEWSTYLE/VIEWCODES/NEW ~40 interactive sites; RANGE 8): 8 pins added to |
||||
ansistring.test, green 71/71 on tclsh90+tcl87. Findings the implementation |
||||
must respect: RANGE re-emits MERGED code stacks (not byte-identical |
||||
round-trip) and DROPS codes trailing the last grapheme (source TODO) - a |
||||
truncate building on RANGE must fetch trailing state separately (INDEXCODE |
||||
end+1 works) if it matters; VIEW -lf 1 is the proven single-line-ization |
||||
primitive; VIEW silently tolerates unknown option pairs (overtype's |
||||
'-nul 1' sites depend on this - NUL substitution is actually always-on); |
||||
VIEWCODES/VIEWSTYLE are broken headless (bare 'a+'/'a' interactive-alias |
||||
dependency, known-deficiency pinned) - do not route the truncate through |
||||
the class view paths. |
||||
5. Serving the failure-side value-truncation todo recorded in the engine |
||||
("truncate/summarize values in error messages", args-999999.0a1.0.tm |
||||
arg_error region) with the same helper is a FOLLOW-ON, not part of this |
||||
goal's acceptance. |
||||
6. Row policy: rows only for arguments holding a value post-parse (received, |
||||
or default-in-effect - the Source column carries the received/default |
||||
distinction and is the plain-mode-safe twin of the colour marking); |
||||
absent optionals get no row. |
||||
|
||||
## Progress |
||||
|
||||
Achieved 2026-08-05 in one session (user-directed activation and implementation |
||||
same day; punk::args 0.18.0 + punk::ansi 0.2.0). All six design leans enacted |
||||
as recorded above. |
||||
|
||||
Mechanism landed: |
||||
|
||||
- New `punk::args::parse_report` - the landing report render. Entry forms per |
||||
the acceptance: a punk::args::parse result dict (its id key resolved via |
||||
real_id/get_spec; the result's form key selects the displayed form), or |
||||
`<arglist> withid <id>` (the parse is performed first; a rejected line |
||||
raises the same validation error punk::args::parse raises - errorcode |
||||
parity pinned). Hand-rolled argument processing in the parse/parse_status |
||||
style (self-parse against the registered two-form definition only on the |
||||
unhappy path, so a report render never recurses through a second live |
||||
parse); the registered definition (forms 'parsed'/'withid') follows |
||||
parse_status's shared-block structure - per-form @leaders first, then the |
||||
shared @opts, then per-form @values (a shared-then-narrow @leaders ordering |
||||
is rejected by the resolver: leaders must precede options per form). |
||||
- Row data rides the existing G-049 machinery: private::parse_status_build |
||||
-ok 1 -parsedargs <result> supplies per-argument class/received/positions/ |
||||
hasvalue/value in declaration-section order (leaders, opts, values) - G-151 |
||||
adds no second status assembler. Display-level bridging recovers the |
||||
value-in-effect where the build's direct ARG_INFO-name lookup misses the |
||||
parse result's storage-key folds (-parsekey renames; aliased optionsets |
||||
stored under their last |-member) so received aliased/parsekey'd arguments |
||||
keep their row (G-084 owns the storage-key model itself; pinned via the |
||||
-f|-file fixture). |
||||
- Returns: table (arg_error-styled bordered textblock block, title default |
||||
'Received', columns Argument | Source | Value; colour bootstrap shares |
||||
arg_error's CLR base + scheme-override + colour-flip reload pattern), |
||||
tableobject, string (plain 'name (source) = value' lines; also the |
||||
degraded no-textblock path), dict (machine form id/form/rows - never |
||||
elided). Source column: received / received xN / default (CLR(check) / |
||||
CLR(parsekey_hint) colouring; words stay the plain-mode distinction). |
||||
- Elision (lean 3): strings single-line-ized via ansistring VIEW -lf 1 -vt 1 |
||||
-sp 0 (controls AND embedded ANSI render visibly, so a value cannot |
||||
disturb the table; real spaces stay real) then grapheme-capped via the new |
||||
ansistring TRUNCATE with '...' + ' (len N)' (N = raw string length); |
||||
-multiple/-type list values element-capped with '(+N more)' (whole |
||||
list-quoted elements while they fit, first element char-capped if it alone |
||||
overflows); -type dict values pair-capped with '(+N pairs)'; plain-string |
||||
fallbacks when punk::ansi is unavailable. Width cascade (lean 2, G-149 |
||||
plumbing precedent): caller -valuewidth > new @cmd directive key |
||||
-reportvaluewidth (documented in define -help) > built-in 48; 0 = no cap; |
||||
never console-derived. |
||||
- The truncate primitive (lean 4): `ansistring TRUNCATE ?-ellipsis marker? |
||||
string maxgraphemes` in punk::ansi 0.2.0 - fits => byte-identical |
||||
passthrough (trailing/non-SGR codes included); truncation => RANGE- |
||||
extracted prefix (merged SGR re-application per the 0.1.4-documented |
||||
contract) + marker totalling exactly maxgraphemes, with an SGR reset |
||||
appended before the marker when the prefix carries codes (RANGE re-applies |
||||
stacks with no trailing reset - the survey finding); marker charged |
||||
against the budget and itself truncated when it alone meets/exceeds it; |
||||
grapheme-count based (CJK counts 1/each; column-aware variant recorded as |
||||
a follow-on). Strict option handling (deliberately unlike VIEW's pinned |
||||
silent tolerance). Ensemble export + argdoc + doctools added. |
||||
|
||||
Verification evidence: |
||||
|
||||
- New suite src/tests/modules/punk/args/testsuites/args/parsereport.test |
||||
(13 tests) - the acceptance's canonical demonstration pinned exactly |
||||
(fixture parse of {build punk95 -confirm 0}: the flag-like word -confirm |
||||
and its 0 land as VALUES attributed 'args (received x2) = -confirm 0' |
||||
beside 'kitname (received) = punk95' and '-test (default) = 0'); entry |
||||
parity, dict shape/row order/row policy, solo+multi multiplicity, elision |
||||
markers by type, dict-never-elided, width cascade, single-line-ization, |
||||
alias bridging, bordered/tableobject renders, failure parity, bad-call |
||||
errors, own-definition render. |
||||
- ansistring.test +2 TRUNCATE pins (budget/passthrough/errors; ANSI-reset + |
||||
CJK + combining-cluster safety). |
||||
- Full modules/punk/args subtree 331 passed / 3 pre-existing skips / 0 |
||||
failed, and modules/punk/ansi subtree 73/73, each on BOTH native tclsh90 |
||||
(Tcl 9.0.3) and tclsh87 - failure-side rendering unchanged per acceptance |
||||
(all existing arg_error/usage/synopsis/marking pins pass untouched). |
||||
- Minted modules/punk/args-0.18.0.tm + modules/punk/ansi-0.2.0.tm via |
||||
make.tcl modules. |
||||
- make.tcl's interim one-line report (bootsupport punk::args) is untouched |
||||
until a bootsupport promotion carries 0.18.0 - recorded consumer |
||||
follow-through below, per the acceptance. |
||||
|
||||
## Follow-ons |
||||
|
||||
Follow-on: make.tcl retires its interim one-line 'dry-run: line accepted ...' report in favour of parse_report (stacked under the usage render per lean 1) after a bootsupport promotion carrying punk::args 0.18.0- and punk::ansi 0.2.0- => open |
||||
Follow-on: serve arg_error's failure-side value-truncation todo ('truncate/summarize values in error messages', args-999999.0a1.0.tm arg_error region) with the same report_display_value/TRUNCATE helpers (lean 5 - explicitly excluded from this goal's acceptance) => open |
||||
Follow-on: engine-level rationalization of parse-result storage keys vs definition argument names (aliased optionset last-|-member fold, -parsekey renames) so value-in-effect lookups need no display-level bridging => goal G-084 |
||||
Follow-on: column-aware (display-width) TRUNCATE variant for CJK-heavy values (the grapheme-count cap under-counts double-wide content; noted in the TRUNCATE argdoc) => open |
||||
Follow-on: word-oriented inverse view (word -> consuming argument, e.g a -return words variant) as completion/hinting-facing data - lean 1 records it as a possible later variant, not the primary => open |
||||
@ -1,6 +1,7 @@
|
||||
0.1.4 |
||||
0.2.0 |
||||
#First line must be a semantic version number |
||||
#all other lines are ignored. |
||||
#0.2.0 - G-151: new ansistring TRUNCATE ?-ellipsis marker? string maxgraphemes - ANSI/grapheme-safe display truncation primitive (homed beside RANGE/VIEW per the ANSI-surgery domain rule; punk::args::parse_report 0.18.0 is the driving consumer). Returns string unchanged (byte-identical - trailing and non-SGR codes included) when its grapheme count (as for COUNT) is at most maxgraphemes; otherwise the leading graphemes extracted as for RANGE (merged/canonicalized SGR re-application per the contract documented at 0.1.4) with the marker appended such that the result's total grapheme count equals maxgraphemes. The marker (default '...') charges its grapheme count against the budget; a marker alone meeting/exceeding the budget is itself truncated to maxgraphemes; maxgraphemes 0 returns empty string; negative or non-integer maxgraphemes errors. When the kept prefix carries ANSI codes an SGR reset is appended before the marker (RANGE re-applies stacks with no trailing reset) so the marker and any following text render unstyled. Grapheme-count based, not display-column based (wide CJK graphemes count 1 each - a column-aware variant is a possible follow-on). Strict option handling (unknown option errors - unlike VIEW's pinned silent tolerance). Ensemble export + PUNKARGS argdoc + doctools comment added. New pins in ansi/ansistring.test. |
||||
#0.1.4 - documentation-only: ansistring RANGE argdoc + doctools comment now state the pinned contract (tests ansi/ansistring.test, 2026-08-05 coverage survey): merged/canonicalized SGR re-emission (style-equivalent, not byte-identical), SGR-only carriage (non-SGR sequence types not re-emitted), trailing-code exclusion with INDEXCODE end+1 as the retrieval mechanism, and clamping/empty-range semantics. Summary reworded (was 'codes preserved' - overclaimed). Open design questions (trailing codes on literal end, non-SGR retention, charset/gx0 handling) stay as code TODO/review comments and G-151 Notes - deliberately not promised in the doc. |
||||
#0.1.3 - documentation-only: grepstr -return summarydict choicelabel corrected - the summary dict's 'linemap' key is always present (the old text claimed it appeared only with -n; actual always-present behaviour pinned in tests ansi/grepstr.test). Reconciliation deferred from the grepstr characterization wave to the punk::ns hygiene pass. |
||||
#0.1.2 - documentation-only: PUNKARGS argdoc blocks added for punk::ansi::codetype (is_sgr_reset, has_sgr_leadingreset, is_cursor_move_in_line, has_all_effective, get_effective_types, is_gx/is_gx_open/is_gx_close, sgr_merge), punk::ansi::sequence_type (is_Fe7/is_Fe/is_Fe8, is_Fp, is_Fs, is_nF, is_3Fp, is_code7/is_code8/is_code, classify), punk::ansi::ta (detect_in_list, detectcode, detectcode_in_list, detect_g0, detect_open, detect_st_open, detect_csi, detect_sgr, split_at_codes, split_codes, split_codes_single, get_codes_single) and punk::ansi::ansistring (VIEW, COUNT, length, trimleft/trimright/trim, INDEX, INDEXCHAR, RANGE, INSERT, INDEXABSOLUTE, INDEXCOLUMNS, COLUMNINDEX); ::punk::ansi::sequence_type added to punk::args::register NAMESPACES so its argdocs are discoverable |
||||
|
||||
@ -0,0 +1,309 @@
|
||||
package require tcltest |
||||
|
||||
package require punk::args |
||||
package require punk::lib |
||||
package require punk::ansi |
||||
|
||||
#punk::args::parse_report (G-151 annotated success render, punk::args 0.18.0) - |
||||
#the landing report for a SUCCESSFUL parse: one row per value-holding argument |
||||
#(received, or filled from -default) in declaration-section order (leaders, |
||||
#opts, values), Source column distinguishing received / received xN / default. |
||||
#The canonical demonstration is a flag-like word consumed as a VALUE by |
||||
#position, visibly attributed to its consuming argument (the make.tcl dry-run |
||||
#'kitname = punk91 -confirm 0' class from the G-143 sessions). |
||||
#Pins are colour-state independent: -return string carries no ANSI (the value |
||||
#cell is VIEW-neutralized, the source word is plain), -return dict is the |
||||
#machine form, and table pins glob on stripped/ASCII content only. |
||||
#Display elision is deterministic (never console-derived): strings single-line- |
||||
#ized then grapheme-capped with '...' + ' (len N)' (N = raw string length), |
||||
#lists/-multiple element-capped with '(+N more)', dicts pair-capped with |
||||
#'(+N pairs)'; the -return dict form is never elided. |
||||
#Width cascade (G-149 plumbing precedent): caller -valuewidth > @cmd directive |
||||
#key -reportvaluewidth > built-in 48; 0 means no cap. |
||||
|
||||
namespace eval ::testspace { |
||||
namespace import ::tcltest::* |
||||
variable common { |
||||
set result "" |
||||
} |
||||
|
||||
#make.tcl-shaped fixture: choice leader, defaulted option, optional value + |
||||
#-multiple tail able to swallow flag-like words as values |
||||
punk::args::define { |
||||
@id -id ::testspace::prmk |
||||
@cmd -name testspace::prmk |
||||
@leaders -min 1 -max 1 |
||||
action -choices {build info} |
||||
@opts |
||||
-test -type integer -default 0 |
||||
-note -type string |
||||
@values -min 0 -max -1 |
||||
kitname -type string -optional 1 -default punk91 |
||||
args -type any -multiple 1 -optional 1 |
||||
} |
||||
|
||||
#elision fixture: declared list/dict types + free string value |
||||
punk::args::define { |
||||
@id -id ::testspace::prel |
||||
@cmd -name testspace::prel |
||||
@opts |
||||
-biglist -type list -default {} |
||||
-bigdict -type dict -default {} |
||||
@values -min 0 -max 1 |
||||
text -type string -optional 1 |
||||
} |
||||
|
||||
#definition-level width key fixture |
||||
punk::args::define { |
||||
@id -id ::testspace::prrw |
||||
@cmd -name testspace::prrw -reportvaluewidth 20 |
||||
@values -min 0 -max 1 |
||||
text -type string -optional 1 |
||||
} |
||||
|
||||
#solo + multiple options fixture |
||||
punk::args::define { |
||||
@id -id ::testspace::prsolo |
||||
@cmd -name testspace::prsolo |
||||
@opts |
||||
-v -type none -multiple 1 |
||||
-file -type string -multiple 1 |
||||
@values -min 0 -max 0 |
||||
} |
||||
|
||||
#aliased optionset fixture (storage-key fold bridging) |
||||
punk::args::define { |
||||
@id -id ::testspace::pralias |
||||
@cmd -name testspace::pralias |
||||
@opts |
||||
-f|-file -type string |
||||
@values -min 0 -max 0 |
||||
} |
||||
|
||||
#added 2026-08-05 (agent, G-151) - the acceptance's canonical demonstration: |
||||
#flag-like words consumed as VALUES visibly attributed to the -multiple |
||||
#argument that took them; received vs default distinguished in Source |
||||
test parsereport_canonical_flagword_value_attribution {a flag-like word consumed as a VALUE shows attributed to its consuming argument; received/default distinction; declaration-section row order}\ |
||||
-setup $common -body { |
||||
set argd [punk::args::parse {build punk95 -confirm 0} withid ::testspace::prmk] |
||||
punk::args::parse_report $argd -return string |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [join [list\ |
||||
{action (received) = build}\ |
||||
{-test (default) = 0}\ |
||||
{kitname (received) = punk95}\ |
||||
{args (received x2) = -confirm 0}\ |
||||
] \n] |
||||
|
||||
#added 2026-08-05 (agent, G-151) |
||||
test parsereport_parsedresult_and_words_forms_agree {the parse-result entry form and the words+withid entry form produce identical output}\ |
||||
-setup $common -body { |
||||
set argd [punk::args::parse {build punk95 -confirm 0} withid ::testspace::prmk] |
||||
set via_result [punk::args::parse_report $argd -return string] |
||||
set via_words [punk::args::parse_report {build punk95 -confirm 0} -return string withid ::testspace::prmk] |
||||
lappend result [expr {$via_result eq $via_words}] |
||||
set d_result [punk::args::parse_report $argd -return dict] |
||||
set d_words [punk::args::parse_report {build punk95 -confirm 0} -return dict withid ::testspace::prmk] |
||||
lappend result [expr {$d_result eq $d_words}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - machine form: id/form/rows; per-row |
||||
#class/source/received/positions/multiple/hasvalue/value; row order is |
||||
#declaration-section order; absent optionals (no default) get no row |
||||
test parsereport_dict_machine_shape {-return dict carries id/form and ordered rows with per-argument landing data; absent optional -note has no row}\ |
||||
-setup $common -body { |
||||
set argd [punk::args::parse {build punk95 -confirm 0} withid ::testspace::prmk] |
||||
set rep [punk::args::parse_report $argd -return dict] |
||||
lappend result [dict get $rep id] |
||||
lappend result [dict keys [dict get $rep rows]] |
||||
lappend result [dict get $rep rows args] |
||||
lappend result [dict get $rep rows -test] |
||||
lappend result [dict exists $rep rows -note] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list\ |
||||
::testspace::prmk\ |
||||
{action -test kitname args}\ |
||||
{class value source received received 2 positions {2 3} multiple 1 hasvalue 1 value {-confirm 0}}\ |
||||
{class option source default received 0 positions {} multiple 0 hasvalue 1 value 0}\ |
||||
0\ |
||||
] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - solo flags and -multiple options: the |
||||
#Source column carries the aggregation count; values echo the stored |
||||
#aggregations |
||||
test parsereport_source_multiplicity_solos_and_multis {repeated solo flags and -multiple options report received xN with their aggregated values}\ |
||||
-setup $common -body { |
||||
set argd [punk::args::parse {-v -v -file a.txt -file b.txt} withid ::testspace::prsolo] |
||||
punk::args::parse_report $argd -return string |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [join [list\ |
||||
{-v (received x2) = 1 1}\ |
||||
{-file (received x2) = a.txt b.txt}\ |
||||
] \n] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - type-aware always-marked elision at the |
||||
#default width (48): element cap '(+N more)', pair cap '(+N pairs)', string |
||||
#char cap '...' + ' (len N)' citing the raw length |
||||
test parsereport_elision_marked_by_type {list values element-capped, dict values pair-capped, strings char-capped - all with honest markers at the default width}\ |
||||
-setup $common -body { |
||||
set biglist [list] |
||||
for {set i 0} {$i < 30} {incr i} {lappend biglist elem$i} |
||||
set bigdict [dict create] |
||||
for {set i 0} {$i < 20} {incr i} {dict set bigdict key$i val$i} |
||||
set longtext [string repeat abcdefghij 10] |
||||
set argd [punk::args::parse [list -biglist $biglist -bigdict $bigdict $longtext] withid ::testspace::prel] |
||||
punk::args::parse_report $argd -return string |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [join [list\ |
||||
{-biglist (received) = elem0 elem1 elem2 elem3 elem4 elem5 (+24 more)}\ |
||||
{-bigdict (received) = key0 val0 key1 val1 key2 val2 (+17 pairs)}\ |
||||
{text (received) = abcdefghijabcdefghijabcdefghijabcde... (len 100)}\ |
||||
] \n] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - the -return dict form is never elided |
||||
test parsereport_dict_never_elided {machine rows carry the full untruncated values}\ |
||||
-setup $common -body { |
||||
set biglist [list] |
||||
for {set i 0} {$i < 30} {incr i} {lappend biglist elem$i} |
||||
set argd [punk::args::parse [list -biglist $biglist] withid ::testspace::prel] |
||||
set rep [punk::args::parse_report $argd -return dict] |
||||
lappend result [expr {[dict get $rep rows -biglist value] eq $biglist}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - width cascade: @cmd -reportvaluewidth |
||||
#applies when the caller passes no -valuewidth; the caller option overrides; |
||||
#0 means no cap |
||||
test parsereport_valuewidth_cascade {caller -valuewidth > @cmd -reportvaluewidth > built-in default; 0 uncaps}\ |
||||
-setup $common -body { |
||||
set longtext [string repeat abcdefghij 10] |
||||
set argd [punk::args::parse [list $longtext] withid ::testspace::prrw] |
||||
lappend result [punk::args::parse_report $argd -return string] |
||||
lappend result [punk::args::parse_report $argd -return string -valuewidth 60] |
||||
lappend result [punk::args::parse_report $argd -return string -valuewidth 0] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list\ |
||||
{text (received) = abcdefg... (len 100)}\ |
||||
{text (received) = abcdefghijabcdefghijabcdefghijabcdefghijabcdefg... (len 100)}\ |
||||
"text (received) = [string repeat abcdefghij 10]"\ |
||||
] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - single-line-ization: newlines/tabs render |
||||
#as visible control pictures (as for ansistring VIEW -lf 1) so a value |
||||
#cannot break the row; expected string constructed via format to keep this |
||||
#file ASCII |
||||
test parsereport_multiline_value_single_lined {a value containing newline and tab renders one-line with visible substitutes (defaulted empty-value rows keep their trailing-space line shape)}\ |
||||
-setup $common -body { |
||||
set argd [punk::args::parse [list "line1\nline2\ttabbed"] withid ::testspace::prel] |
||||
set rep [punk::args::parse_report $argd -return string] |
||||
#the prel fixture's -biglist/-bigdict defaults ({}) hold values, so they row too |
||||
set expected "-biglist (default) = \n-bigdict (default) = \ntext (received) = line1[format %c 0x240A]line2[format %c 0x2409]tabbed" |
||||
lappend result [expr {$rep eq $expected}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - aliased optionset storage-key bridging: |
||||
#the parse result stores an aliased optionset under its last |-member; the |
||||
#report bridges the fold so the received argument keeps its row (G-084 owns |
||||
#the storage-key model itself) |
||||
test parsereport_aliased_optionset_row_bridged {an option received via its alias keeps its row with the value-in-effect}\ |
||||
-setup $common -body { |
||||
set argd [punk::args::parse {-f x.txt} withid ::testspace::pralias] |
||||
lappend result [punk::args::parse_report $argd -return string] |
||||
lappend result [dict get [punk::args::parse_report $argd -return dict] rows -f|-file value] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list {-f|-file (received) = x.txt} x.txt] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - the bordered landing table: title in the |
||||
#frame, Argument/Source/Value headers, the canonical attribution row intact |
||||
#on one line (ASCII-content globs on the stripped render) |
||||
test parsereport_table_bordered_block {-return table renders the arg_error-styled bordered block with title, headers and attribution rows}\ |
||||
-setup $common -body { |
||||
set argd [punk::args::parse {build punk95 -confirm 0} withid ::testspace::prmk] |
||||
set out [punk::ansi::ansistrip [punk::args::parse_report $argd]] |
||||
set lines [split $out \n] |
||||
lappend result [string match "*Received*" [lindex $lines 0]] |
||||
lappend result [string match "*Argument*Source*Value*" $out] |
||||
set attribution_line "" |
||||
foreach ln $lines { |
||||
if {[string match "*-confirm 0*" $ln]} {set attribution_line $ln} |
||||
} |
||||
lappend result [string match "*args*received x2*-confirm 0*" $attribution_line] |
||||
lappend result [expr {[llength $lines] >= 8}] |
||||
set out2 [punk::ansi::ansistrip [punk::args::parse_report $argd -scheme nocolour -title Landing]] |
||||
lappend result [string match "*Landing*" [lindex [split $out2 \n] 0]] |
||||
set t [punk::args::parse_report $argd -return tableobject] |
||||
lappend result [info object isa object $t] |
||||
$t destroy |
||||
lappend result [llength [info commands $t]] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1 1 1 1 1 0] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - the words form performs the parse: a |
||||
#rejected line raises the same validation error punk::args::parse raises |
||||
test parsereport_words_form_failure_parity {a rejected words line raises with the same errorcode as punk::args::parse}\ |
||||
-setup $common -body { |
||||
set rc1 [catch {punk::args::parse_report {frobnicate} withid ::testspace::prmk} m1 opts1] |
||||
set rc2 [catch {punk::args::parse {frobnicate} withid ::testspace::prmk} m2 opts2] |
||||
lappend result $rc1 $rc2 |
||||
lappend result [expr {[dict get $opts1 -errorcode] eq [dict get $opts2 -errorcode]}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1 1] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - unhappy call shapes: pointed errors for |
||||
#non-result-dict payload / unknown id / bad -valuewidth; an unknown option |
||||
#routes through the documented definition (a PUNKARGS VALIDATION raise) |
||||
test parsereport_bad_calls {pointed errors: payload neither result dict nor words+withid, no such id, bad -valuewidth, unknown option via the documented definition}\ |
||||
-setup $common -body { |
||||
lappend result [catch {punk::args::parse_report "not a result dict"} m] |
||||
lappend result [string match "*not a punk::args::parse result dict*" $m] |
||||
lappend result [catch {punk::args::parse_report {a b} withid ::testspace::pr_nosuchid} m] |
||||
lappend result [string match "*no such id*" $m] |
||||
set argd [punk::args::parse {build} withid ::testspace::prmk] |
||||
lappend result [catch {punk::args::parse_report $argd -valuewidth -5} m] |
||||
lappend result [string match "*must be an integer >= 0*" $m] |
||||
lappend result [catch {punk::args::parse_report $argd -bogus 1} m mopts] |
||||
lappend result [expr {[lindex [dict get $mopts -errorcode] 0] in [list PUNKARGS TCL]}] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list 1 1 1 1 1 1 1 1] |
||||
|
||||
#added 2026-08-05 (agent, G-151) - parse_report's own registered definition: |
||||
#both forms present and the usage render carries both synopsis shapes |
||||
test parsereport_own_definition_renders {the registered ::punk::args::parse_report definition resolves with forms {parsed withid} and renders both synopses}\ |
||||
-setup $common -body { |
||||
lappend result [punk::args::forms ::punk::args::parse_report] |
||||
set u [punk::ansi::ansistrip [punk::args::usage ::punk::args::parse_report]] |
||||
lappend result [string match "*parse_report parsedresult*" $u] |
||||
lappend result [string match "*parse_report arglist*withid id*" $u] |
||||
}\ |
||||
-cleanup { |
||||
}\ |
||||
-result [list {parsed withid} 1 1] |
||||
|
||||
} |
||||
tcltest::cleanupTests ;#needed to produce test summary. |
||||
Loading…
Reference in new issue