You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

7.5 KiB

G-045 punk::args definition authoring ergonomics: record continuation, @cmd unindented fields, constructed-definition normalization

Status: proposed Scope: src/modules/punk/args-999999.0a1.0.tm (record parsing in resolve, tstr interplay, arg_error @cmd rendering), src/tests/modules/punk/args/testsuites/ (rendering.test/defquoting.test as the safety net), src/modules/punk-999999.0a1.0.tm (::punk::helptopic::define_docs de-hacked as the consumer proof) Goal: authoring punk::args definitions no longer requires backslash line-continuations or ad-hoc workarounds for multi-line records and constructed definitions - a parser-recognised record-continuation mechanism (candidate: an unquoted trailing -& token, with the detail file recording the collision analysis and the element-count disambiguation alternative), -unindentedfields honoured for @cmd fields, and constructed (string-built) definitions able to opt into the same whole-block indent normalization file-style definitions get - with the container quoting rules (braced=literal, quoted=Tcl backslash semantics, ${ escape) promoted from defquoting.test into the define documentation. Acceptance: a definition using the chosen record-continuation mechanism parses identically to its backslash-continuation equivalent (existing definitions unchanged - continuation is additive), with the token's collision rules documented and an escape/rejection story for values that legitimately match it; @cmd -help/-summary honour -unindentedfields (the rendering.test GAP rendering_unindentedfields_cmd_help_GAP flips to aligned); a constructed definition can request whole-block normalization so embedded continuation indentation behaves as in file-style definitions (the rendering_constructed_def_indent_characterization expectations updated to the chosen semantics), and ::punk::helptopic::define_docs drops its manual pre-normalization to prove it; the quoting rules from defquoting.test appear in the punk::args::define -help documentation; the full punk::args suite (128 tests incl. the rendering invariants: nesting independence, relative-indent preservation) passes with GAP tests flipped, none weakened.

Context

Drafted 2026-07-09 after the tests-first characterization pass (user direction: implement tests before changes in this area). The pain points, in the user's framing:

  • The define-block syntax deliberately avoids Tcl dict syntax for human readability, which led to backslash line-continuations and a complex interplay between record parsing in punk::args::resolve and tstr (especially ${...} expansions keeping whitespace aligned during multiline substitutions).
  • Constructed (string-built) definitions - ::punk::helptopic::define_docs and punk::args::ensemble_subcommands_definition are the in-tree examples - have poor ergonomics for getting indentation right: unlike file-style definitions they receive no whole-block indent normalization (proven: rendering.test rendering_constructed_def_indent_characterization - continuations at exactly 4 spaces align, other depths leak), so builders pre-normalize by hand (undent/trim hacks, \n-relative authoring).
  • A key property of normal definitions that must be preserved: they do not depend on the indentation of the code block they appear in (proven and pinned: rendering_nesting_independence_plain / _tstr).
  • The user's experiment used an ad-hoc -- flag followed by a braced line-spanning empty string as a de-facto record continuation - functional but not designed-for, and unsatisfying.

The -& record-continuation candidate

The user's proposal: a special token the record parser recognises as record continuation, e.g. an unquoted -& at end of line. Design considerations recorded for implementation:

  • Collision risk is low but not zero (a value or flag legitimately spelled -&). Candidate rules: only an UNQUOTED trailing -& at end of a record line counts; and/or use the element count of the assembled record to disambiguate (an odd element count where pairs are expected implies the trailing token is a continuation marker, not a value). The detail decision must include an escape story for a literal trailing -& value (bracing it suffices if 'unquoted' is part of the rule).
  • Detection must happen in the record parser (resolve) before/alongside line splitting - the same place backslash-continuation assembly effectively happens via Tcl's own parse of braced blocks today. Unlike backslash-newline, -& survives inside braced blocks of CONSTRUCTED definitions too - which is precisely why it helps: string-built defs cannot use backslash-newline ergonomically (it is consumed by the building code's own quoting).

@cmd -unindentedfields

Accepted but ignored today (arg_error's cmd_info rendering carries an '#unindentedfields ?' todo; pinned by rendering_unindentedfields_cmd_help_GAP: left-margin-authored @cmd help renders its first line +4 vs continuations). Honouring it makes left-margin authoring available for @cmd -help/-summary as it already is for argument -help and -choicelabels.

Constructed-definition normalization

Options to decide at implementation (record the choice):

  • an explicit define option/directive requesting whole-block undent of the supplied text
  • or automatic common-prefix normalization when a definition arrives as a single text block (risk: changing existing constructed defs' rendering - the characterization test documents current expectations to update deliberately) ::punk::helptopic::define_docs currently pre-normalizes by hand (undent/trim + \n-relative help strings + -unindentedfields) - it converts to the new mechanism as the proof, and the user's uncommitted experimental hack in punk.tm is superseded.

Quoting documentation

defquoting.test pinned the container rules (braced values fully literal - $, [], two-char \n, bare backslashes; quoted values get Tcl backslash semantics - \n newline, \ -> \ - with $/[] still literal; ${...} renders a literal ${...} in tstr-processed blocks). Promote these rules into the punk::args::define -help documentation so documenters (e.g. punk::imap4's {\Deleted}/{$MDNSent} choice values) have them stated, not just tested.

Alternatives considered

  • Keeping backslash continuations + manual pre-normalization as the documented way - rejected: the friction is proven by two in-tree constructed-def workarounds and the user's punk.tm experiments.
  • Tcl dict syntax for definitions - rejected long ago by design (readability).
  • The ad-hoc -- + braced-gap trick as the blessed continuation - rejected: exploits parser behaviour that was never a contract.

Notes

  • Safety net: src/tests/modules/punk/args/testsuites/args/rendering.test (15 tests: nesting independence, relative-indent preservation, unindentedfields, constructed-def characterization, multiline tstr insertions, @dynamic) and defquoting.test (container quoting rules). GAPs to flip here: rendering_unindentedfields_cmd_help_GAP, rendering_constructed_def_indent_characterization (expectations updated to chosen semantics).
  • Related: G-046 (deferred -help resolution and rendering fixes - same code neighbourhood; sequencing between the two goals is free but they touch resolve together), G-044 (completion consumes the documentation corpus these ergonomics grow).
  • Session records 2026-07-09: probe scripts renderprobe*.tcl (scratchpad), the user's experimental define_docs hack (uncommitted punk.tm working-tree diff at the time of drafting - superseded by this goal when implemented).
  • Archived-goal references in this file: G-046 achieved 2026-07-10 (goals/archive/G-046-punkargs-deferred-help-and-fixes.md).