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.
 
 
 
 
 
 

32 lines
31 KiB

0.12.5
#First line must be a semantic version number
#all other lines are ignored.
#0.12.5 - eg usability: punk::args::eg resolves relative/unqualified command names (via punk::ns::cmdinfo from the calling context when punk::ns is loaded - handles subcommand words too - else global qualification). Rationale: in a namespace where punk::args::eg shadows the global 'eg' alias (e.g whilst in ::punk::args itself) 'eg list' hit the raw-id API and returned empty while 'i list' resolved - Tcl name resolution, not an alias deficiency. Unknown ids now return a message naming the id instead of empty; punk::ns::eg hands the typed name through when resolution yields no docid so the message can name it. The usage-table 'Example: eg <id>' header row (the short indication an @examples block exists) now uses scheme colour CLR(check) instead of hardcoded white - the raw id is kept (not @cmd -name, which is display text and not always invocable e.g 'Autoloading Built-in: parray'); a frame-embedded bottom-right marker awaits textblock table footer-block support (candidate goal). New examples.test pins: relative-name resolution, unknown-id message.
#0.12.5 - synopsis notation documented + internal @form -synopsis overrides retired. ::punk::args::parse and ::parse_status dropped their @form -synopsis overrides - they had gone stale (omitted -cache/-caller) and their only added value (the -form member hint) is now expressed properly via -typesynopsis {<int|formname>...} on the -form option; the auto-generated lines stay current as options are added (drift pin: synopsis.test synopsis_parse_generated). @form -synopsis remains fully supported for documentors: define's directive help now documents that it is display-only text needing no Tcl-list validity, that display helpers substitute the command head, and the known warranted case (script-level/constructed ids rendering the raw id - the G-030 lesson recorded in src/modules/AGENTS.md; head-render preference for @cmd -name remains an open generation deficiency). ::punk::args::synopsis -help gains a notation legend ([...] optional, italic argname/<type> placeholders, unitalicised literals, (a|b) alternate grouping to disambiguate from -f|--file alias pipes, {a b} multi-word literal protection, --opt=<type>, text*/*text) and a new @examples block comparing Tcl man-page ?...? style (ambiguous when nested - same delimiter both ends) with the bracket style, viewable via punk::args::eg. New synopsis.test pins: non-list custom -synopsis passthrough + ns head-replacement survival, parse generated-line drift pin, examples block presence.
#0.12.5 - parse -cache overhaul. (1) The VALIDATION trap's parse_cache write is now explicitly gated on -cache - previously it was unconditional but only 'worked' by scoping accident ('variable parse_cache' was declared solely on the -cache 1 branch, so -cache 0 failures wrote to a discarded proc-local). (2) Cached validation errors are now stored as per {errorstyle callertext} render variants under a main key of {arglist definition form} (-caller removed from the main key - results don't depend on it): previously the rendered message baked in the first caller's errorstyle and %caller% attribution and replayed them verbatim to later callers wanting a different style/caller (e.g. a minimal-style render replayed to a -errorstyle standard call). A missing variant falls through to a fresh parse whose trap renders and caches it. (3) @dynamic definitions (and legacy leading '-dynamic 1') are never cached - parse -cache 1 is ignored for them so re-evaluated substitutions always take effect (dev/dynamic-cache.test known-bug pin flipped). (4) New punk::args::parse_cache convenience proc (view summary/keys/dict, -action clear - sgr_cache style); parse_cache variable init now guarded with info exists like the sibling caches; parse's -errorstyle definition default corrected to 'standard' matching the operative defaultopts (doc previously claimed enhanced). New testsuite parsecache.test.
#0.12.4 - resolve: retired the (already disabled) blanket 'called with undefined id' stderr warning - it fired on the supported inline usages (parse ... withdef, direct resolve calls) where a first-sighting cache miss is by design. In its place the miss path is now collision-aware: a first-seen rawdef whose @id is already registered with different content purges the id's existing cache entries (quiet undefine) before registering, mirroring define's re-creation behaviour - previously it repointed id_cache_rawdef while leaving the old rawdef_cache_about/rawdef_cache_argdata entries in place, so two rawdefs claimed the same id and a subsequent define with the original text was a silent no-op (stale cache-about hit) leaving withid lookups stuck on the inline definition. Guard tests id_cache_rawdef directly (id_exists also matches aliases, where the rawdef lookup would error). Known residual (comment marker retained): the miss path still records no -defspace, so @dynamic definitions first seen via resolve lack a defining namespace for re-substitution. New test define.test define_resolve_id_shadow (characterized pre-fix: re-define no-op reproduced with the purge disabled).
#0.12.3 - fixed the stringstartswith(*) arm of get_dict_can_assign_value's multi-member tail-clause reservation walk: it matched against $tp (the type string) instead of $rv (the candidate value), so for a later optional clause mixing literal(...) and stringstartswith(...) members, genuinely matching trailing words were never reserved from a greedy -multiple argument (the optional tail clause was silently lost), while a prefix text that happened to prefix the literal type string (e.g 'str' vs 'stringstartswith(str)') wrongly reserved non-matching words and raised a spurious toomanyarguments overflow. Found flagged-only in the 0.12.2 comment review; characterized pre-fix then pin flipped (allocation.test allocation_tailclause_ssw_reservation + literal-only and no-match guards). Note the walk still only runs when the tail clause's typelist contains a literal* member (the pre-existing acknowledged approximation) - a stringstartswith-only tail clause remains unreserved.
#0.12.2 - comment/documentation hygiene pass (no behaviour change). Removed ~1100 lines of superseded commented-out code: the old-signature private::check_clausecolumn, the abandoned _check_clausecolumn2 'interim version' experiment (its one keeper idea - collect per-clause validation results and report at end instead of raising on first failure - recorded in an in-place note for G-072-era rework), the pre-parsekey opts ordering loop, a disabled XXXliteral* switch arm in get_dict_can_assign_value's multi-member clause walk (open item noted: literalprefix() members unhandled there), and misc debug remnants. Expanded the leaders/values loop MAINTENANCE notes into a real refactor assessment: shared clause-assignment helper extraction is indicated (drift is real - G-082 duplicated its selection block, parsekey idents exist only values-side) but deferred to ride the G-084 leaders/values parsekey parity work under the G-046 hot-path constraints; until then edits to one loop must be mirrored or justified. Documentation corrections: get_dict PUNKARGS/doctools return shape now lists the real result keys (leaders opts values received solos multis id form + formstatus when candidacy ran); directive lists updated beyond @cmd/@leaders/@opts/@values; removed false pre-modern claims ('only supports -flag val pairs, not solo options', 'only the last value is used'); fixed the broken parse -help example (dict exists bracketing) and the module-header dofilestuff example (stray trailing 1 after -type existingfile); assorted typos. Goal cross-references annotated in code comments (G-053 -multiple occurrence ranges, G-084 values/leaders parsekey, corrected test-name refs to parsekey_repeat_ordering). Flagged (comment only, behaviour unchanged, no pins exist): suspected bug in the multi-member clause stringstartswith( arm - it string-matches against $tp (the type) instead of $rv (the value), so it always takes the success path.
#0.12.1 - G-082 single-form parse error selection: a word rejected by an OPTIONAL argument's allocation screen (G-071 restricted-choice screen, or the basic-type screen: int/double/bool/number/dict) that subsequently overflows the argument list now reports the specific rejection - choiceviolation naming the word and the allowed choices (with -badarg/-badval and the same message template as final validation's report for required args), or typemismatch naming the declared type - instead of the generic 'Received more values than can be assigned' toomanyarguments (regression vs 0.5.0 found during G-030 make.tcl dogfooding; the -optional 0 authoring workaround is no longer required). Mechanism: get_dict_can_assign_value returns a 'rejection' record (single-member clauses only; literal-category mismatches deliberately not recorded - overflow stays the clearer report for syntax-word shapes like lseq 'to'), the three allocation call sites (leader/value split trial, leaders loop, values loop) collect first-rejection-per-word into a per-form store, and the two overflow raise sites prefer a recorded rejection for the unassignable word. Genuinely-surplus words (all optionals satisfied) still report toomanyarguments; words consumed by a later slot parse unchanged; multiform selection (rank_form_failures) unchanged - per-form failures just carry the more specific class. New testsuite errorselection.test (characterized pre-fix, pins flipped deliberately).
#0.12.0 - G-074: new punk::args::formcheck - on-demand multiform ambiguity analysis. Static pairwise pass over a definition's resolved FORMS: enumerates the positional word-slot chains each form can present (leaders then values, branching on -optional arguments and ?-wrapped optional clause members, -multiple capped; options excluded - order-free), derives candidate witness arglists for aligned equal-length chains (discriminator words + type-derived witnesses, screened via choiceword_match/type tests so screening can't diverge from parse acceptance), and only reports a form pair after CONFIRMING a witness with a real single-form parse against BOTH forms (parse_status; no user-supplied words, nothing added to define/resolve cost) - so fully discriminated pairs cannot false-alarm and every reported witness is a genuine multipleformmatches arglist; the documented miss direction is witness derivation (exotic types, forms requiring options, enumeration caps). Findings classify as type_weakness (a discriminator slot - literal()/literalprefix()/restricted choices - aligned with a permissive non-validating type: any/none/string/ansistring/globstring/expr/script; the 'lseq 1 count 5' class) vs structural (forms genuinely share an argument shape; the 'after cancel id|script' class). New @form key -overlapallowed <formname-list> sanctions a KNOWN overlap on either pair member: the finding reports with sanctioned 1 and leaves the unsanctioned list (the actionable/gate subset) - parse behaviour is never affected (multipleformmatches still raises); unknown form names rejected at definition resolve. Returns machine-parsable dict (id/form_names/pairs/findings with witness+per-slot relations/unsanctioned/summary) or -return summary for the report text. New testsuite formcheck.test; @form directive doc updated. Proving consumers: tclcore ::lseq (reports range/start_count AND range/count - both real, root cause the expr-typed end slot) and ::after (exactly the sanctioned cancelid/cancelscript documented overlap).
#0.11.2 - bad-@dynamic warn-once + round-1 caching (user-reported: 'i join' emitted the "bad @dynamic tag" warning 4x, 'i join test' 6x): a @dynamic definition whose round-1 tstr output contains no round-2 parameters previously bypassed argdefcache_unresolved entirely, so EVERY resolve redid display masking plus the full round-1 tstr and re-warned - each 'i' invocation resolves several times (doc walk, advisory parse, get_spec for the render, synopsis), all cache hits for static definitions but full re-work for bad-dynamic ones. Such definitions are now cached as a zero-param unresolved entry: subsequent resolves take the cheap cached branch (consistent with the round-1 freezing legitimately dynamic definitions already get) and the warning emits once per definition per interp. Warning message corrected while there: @dynamic is NOT a complete no-op for a parse-inert definition - deferred display fields still re-expand per render instead of caching (expand_display_fields spec_dynamic gate), so the message now says removal is appropriate only if that display behaviour is unintended. Legitimately dynamic definitions unaffected (round-2 re-substitution pinned live). Also commented the dev diagnostics dump (puts of the full records list + ::testrecord global) on resolve's malformed-record error path - the raised message already carries the offending record; found when the malformed ::tcl_startOfNextWord tclcore definition triggered it (fixed in tclcore 0.3.2). New testsuite args/dynamic.test (warn-once + cached-parse pin, legit-dynamic round-2 freshness pin, stderr captured via channel transform).
#0.11.1 - documentation-only: define -help gains a 'Registration styles' section (direct define vs deferred lappend-PUNKARGS + register::NAMESPACES registration - lazy @id scan and on-demand definition via update_definitions, the module-template/moduledoc style, PUNKARGS_aliases, punk::args::status timings; prefer deferred for anything large) and an 'Interpolation (tstr placeholders) and the defspace' section (display-field deferral vs parse-field expansion at first resolve vs @dynamic re-expansion; defspace rule: direct define = calling namespace, registered PUNKARGS = the argdoc child namespace when it exists even if the PUNKARGS variable is in the parent; unresolvable placeholders left silently literal - check the defspace when a literal ${...} appears; robust patterns for load-time-computed values: explicit tstr pre-expansion, build-time string-map token, or setting the variable in argdoc). Motivated by the ::after id-shape harvest misattribution (2026-07-13, corrected record in goals/G-055).
#0.11.0 - G-041 increment 2 (doc-surface support): synopsis renderer honours the documented @form -synopsis override - the stored override now replaces the auto-calculated synopsis line in punk::args::synopsis full and summary renders (arg_error's synopsis section honoured it already; the per-form dict gains a 'synopsis' key when overridden, FORMARGS unchanged for dict consumers) - forms.test GAP forms_form_synopsis_override_stored_not_rendered_GAP flipped to forms_form_synopsis_override_rendered. Candidate-form ranking extended to choice discriminators: form_literal_affinity now treats a required argument with a RESTRICTED choice set as a discriminator (matched via choiceword_match, the shared G-040 resolver) alongside literal()/literalprefix() types - the tclcore models express subcommand-ish literals as -choices (e.g after's cancel/idle/info), so 'after cancel' now ranks the cancel forms first in noformmatch errors and parse_status best-candidate selection instead of falling back to declaration order.
#0.10.0 - G-041 multi-form candidacy: punk::args::parse/get_dict with the default -form * (or any multi-form selection) now attempts every permitted form instead of effectively parsing form 0 only - a clean match against exactly one form is auto-selected, no match raises a 'noformmatch' PUNKARGS VALIDATION error naming each candidate form's first-line failure (candidates ranked best-first: leading-literal affinity with the supplied words, then incomplete before invalid, then declaration order - private::form_selection/form_literal_affinity/rank_form_failures), and several clean matches raise 'multipleformmatches' naming the forms (no silent preference - deliberate, callers pass -form to disambiguate). -form now accepts a list of form names/indices as documented (get_dict, parse, parse_status, arg_error; supplied order preserved - arg_error renders the argument table for the first listed form and marks all listed forms' synopsis entries; parse's error render passes the ranked candidates). Parse results gain a 'form' key (the parsed form; keys appended after 'id' - positional consumers unaffected) and, when candidacy ran, a 'formstatus' key reporting every attempted form's outcome; parse_status 'form' is now the matched/best-candidate form (per-argument statuses and badarg marking built for it) and gains the documented 'formstatus' key (per-form status/failureclass/badarg/message with caller attribution) - the per-form compatibility surface the G-044 completion/hinting consumer needs. Engine body extracted verbatim to private::get_dict_form (single-form parse; argspecs resolved before selection - no caller-frame use). forms.test GAP pins flipped (auto-selection, -form list restriction) + new coverage (shared-prologue arity discrimination, noformmatch ranking/errorcode, multipleformmatches, formstatus in results and parse_status).
#0.9.0 - G-071: allocation choice screen - get_dict_can_assign_value no longer blanket-accepts any word for an argument with a RESTRICTED choice set; where allocation has an alternative (the argument is -optional, or a further occurrence of a -multiple argument) the candidate word is screened with choiceword_match (the shared G-040 implementation: exact/alias/prefix/nocase semantics; -choicemultiple words screened per list member within min/max), and a non-matching word yields onward to later elements/clauses instead of being consumed and failing validation. Fixes the lseq-class in-form failures: an optional choice noise word between required values plus a trailing optional-member clause ('lseq 0 10 2', '0 10 by 2', '1 5 by 0' now parse; noise-word variants and prefix normalization unchanged; genuinely invalid arglists now get the plain excess-values rejection instead of blaming the unrelated optional). REQUIRED arguments are deliberately not screened - the word must fill them and validation's choiceviolation reporting stays informative. -choicerestricted 0 behaviour unchanged. allocation.test GAPs flipped; parse_status -form documented-order behaviour pinned (a prior mis-premise: -form was already supported before the withid/withdef tail per its synopsis).
#0.8.3 - G-071: silenced four more unconditional debug puts on get_dict's allocation retreat paths ("get_dict cannot assign val:... (111)/(222)/(333)/(444)") - these fired on stderr during NORMAL successful parses whenever an optional element's candidate word was rejected and allocation retreated (e.g. every noise-word skip when parsing if/lseq-modelled commands), polluting interactive output. Same class as the 0.2.3/0.8.2 finds. The retreat logic they marked is the target of the G-071 allocator-correctness work; behaviour unchanged, output only. New allocation.test characterization suite (reduced lseq-range/if-shape fixtures): current mis-allocation and misblame pinned as GAP tests (flip with G-071), noise-word variants and if-shape guards pinned as regression guards, parse_status -form absence pinned as GAP.
#0.8.2 - fixed stray debug output: an unconditional 'puts' in private::get_dict_can_assign_value ("checking tp '<type>' against value '<value>'") fired on multi-element clause type checks (e.g. parsing 'try ... trap ... on ...' style arglists against the tclcore moduledoc), polluting interactive output - now commented like its 0.2.3 companion. Found during G-041 prework probing (real-vs-model divergence sweep of if/switch/try/lseq).
#0.8.1 - G-045 documentation-only: the container quoting rules pinned by defquoting.test promoted into the define -help documentation (-help key section): braced values fully literal (backslash sequences survive as typed) with only tstr placeholders and their backslash escape special; double-quoted values get Tcl backslash semantics at record parse (\n -> newline, doubled backslash collapses) while $ and [] stay literal with no variable/command substitution outside tstr placeholders; the backslash-escaped placeholder idiom renders a literal placeholder.
#0.8.0 - G-045: new bare @normalize directive - opts a definition into indent normalization of BLOCK-FORM multi-line field values (first line whitespace-only, as authored by opening a braced literal with a newline): the structural first newline and a whitespace-only trailing line are dropped, the content lines' common leading whitespace is the block's base indent, the first content line is unindented fully and subsequent lines re-based to the standard 4-space continuation convention (deeper relative indents preserved; whitespace-only inner lines become empty). Head-form values are never altered - their base indent is ambiguous (uniform continuation indent may be the deliberate +2 relative convention over base 4) - which makes @normalize a no-op on conforming file-style definitions (idempotence pinned). Fields in a record's -unindentedfields are exempt. Implemented as a resolve pre-pass over split records (private::normalize_records / rebase_multiline_value); @normalize with options is an error. Intended for constructed/string-built definitions (no whole-block indent treatment otherwise); ::punk::helptopic::define_docs converts to it as the consumer proof (punk 0.2.5). New testsuite normalize.test; define doc documents the directive; rendering.test P4 notes stay pinned as the unopted default.
#0.7.0 - G-045: record-continuation token -& - an unquoted trailing -& element on a definition record line continues the record on the next line. Implemented in private::split_definition_records: the token is dropped and the next line joins after a single space with its leading whitespace collapsed, exactly how the Tcl parser joins backslash-newline continuations before a braced definition reaches the splitter - so a -& record assembles byte-identical to its backslash-continued equivalent (proven by parse+render equality test). Motivation: constructed/string-built definitions cannot author backslash-newline ergonomically (the building code's own quoting consumes it); -& is plain text and survives any construction. Collision rules: the token must be a bare word preceded by whitespace (or the whole line), trailing whitespace after it is tolerated (more forgiving than raw backslash-newline); a braced/quoted -& is data ({-&} is the escape for a literal trailing value); -& mid-line, -& as a word suffix (abc-&), and -& on lines inside still-open braced/quoted values are all data. Backslash continuation authoring is unchanged (continuation is additive). New testsuite recordcontinuation.test; define doc documents the token alongside backslash continuation.
#0.6.1 - G-045: @cmd honours -unindentedfields for -help - arg_error's display-time indent transform (undent " "+help, max 4) is now gated by "-help" membership in the @cmd line's -unindentedfields list (same gate argument -help already had), so left-margin-authored cmd help renders its first line flush with continuations in both the table and string renderers. Previously the option was accepted on @cmd but ignored (rendering.test rendering_unindentedfields_cmd_help_GAP - flipped to rendering_unindentedfields_cmd_help). No in-tree definitions set @cmd -unindentedfields, so existing rendering is unchanged. Note: @cmd -summary has no indent transform in any renderer, so -unindentedfields membership for -summary is accepted and vacuously honoured. define doc for -unindentedfields now states where the option is valid.
#0.6.0 - synopsis display: small restricted choice sets now render as literal alternates - an argument whose choice pool (-choices plus -choicegroups members, deduplicated) has 1-3 members and -choicerestricted true (the default) displays those words unitalicised joined by | in synopses (e.g 'after cancel' shows literal cancel; a 3-choice option shows (left|centre|right)), matching the display style of literal()/literalprefix() type-alternatives. Larger or unrestricted (-choicerestricted 0) choice sets keep the italicised argname/<type> display, and an explicit -typesynopsis always takes precedence. New private helper punk::args::private::synopsis_choice_literals shared by both synopsis render paths (leaders/values via synopsis_form_arg_display, options inline in synopsis); applies only to single-element -type lists (multi-element clause display unchanged). define doc for -choices documents the rule. Tests: synopsis.test - new characterization coverage for literal/literalprefix/stringstartswith/stringendswith type-alternates, option alternate parenthesization, multi-element clause display, -typesynopsis (value element lists, option passthrough incl documenter ANSI), plus the new choice-literal rule (small sets in leader/option/value positions, choicegroups counting, >3 and unrestricted fallbacks, -typesynopsis precedence)
#0.5.0 - G-049 parse-status data model: new punk::args::parse_status - runs a parse attempt (withid/withdef) and returns a documented status structure instead of raising on validation failure (overall ok/status valid|invalid|incomplete/scheme/message/errorcode-minus-argspecs/failureclass/badarg/id/form/receivednames + per-argument argstatus with class/status ok|bad|unparsed/received/positions/hasvalue/value-in-effect incl -default fill). arg_error: new -parsestatus option - both renderers (table and string) now derive goodarg/badarg row marking and choice value-in-effect highlighting from the structure (built internally from -badarg/-parsedargs when not supplied), replacing the transient goodargs/badarg locals; scheme colours resolve per-render into a local array (scheme renders no longer mutate the shared arg_error_CLR array - the -nocolour leak) and the DOCUMENTED -scheme choice value 'nocolour' (and 'nocolor') now takes effect instead of falling through to leftover colours. parse: new -caller option overriding the %caller% frame-walk substitution in validation failure messages (parse_status defaults it to the definition's @cmd -name). get_dict: missingrequiredvalue/missingrequiredleader allocation failures now carry -badarg (type-failed words get badarg marking, not just choice violations). Tests: parsestatus.test (new), usagemarking.test nocolour/leak GAP pins flipped + -parsestatus render parity
#0.4.2 - G-046: display-field deferral - resolve no longer tstr-expands display-only content during argument resolution: ${...} in -help (@cmd/@examples/argument records) and @formdisplay -header/-body is masked with inert tokens (spec key DISPLAY_DEFERRED) and expanded on demand at display time (arg_error/eg/resolved_def/@default-copyfrom hooks; separate argdefcache_display cache for non-dynamic defs; @dynamic display content re-expands per render preserving provider refresh). First parse of heavily documented commands drops accordingly (punk::ansi::mark_columns ~4.3s -> ~12ms; tclcore ::lseq resolve ~184ms -> ~2ms) and -help content that calls punk::args-parsing commands (including against its own id) no longer stalls or loops - plus a display-time reentrancy guard (raw ${...} source substituted on nested expansion of the same id). Record splitter factored to private::split_definition_records. Also: @dynamic second-round multiline substitutions into deferred fields now get the 'line' paramindents alignment (rendering_atdynamic_multiline_help_insertion GAP flipped); prefix/alias choice normalization writeback no longer list-quotes single-element-clause values ({\Deleted} shape bug, choicegroups_imap_prefix_shape GAP flipped); -return string renderer aligns cmd-help continuations under the Description label and its Example line shows the example instead of the doc url. Tests: deferredhelp.test (new), rendering.test/choicegroups.test updated per G-046 acceptance
#0.4.1 - fixed ensemble_subcommands_definition building the definition against unloaded argdocs: subhelp/doctype-punkargs choiceinfo entries and synopsis choicelabels were omitted for documented subcommands whose registered namespace (::punk::args::register::NAMESPACES) had not yet been lazily loaded - e.g first 'i ansistring' in a fresh shell rendered the autogenerated ensemble help without subcommand-help markers until something else loaded ::punk::ansi::ansistring. The generator now runs update_definitions for the namespaces its id_exists checks could resolve in before testing them (tests: punk/args ensembledef.test, punk/ns cmdhelp.test cmdhelp_ensemble_lazy_registered_argdocs)
#0.4.0 - tidy-up (pre G-046): removed dead developer-test procs define2 and parseXXX and the unused ::punk::args::TEST definition; renamed the interactive Get_caller diagnostics test_get_dict/test_get_by_id/test_callers (+ test1 id) and lib::tstr_test_one with leading double underscores and excluded them from exports (punk::args::lib now exports {[a-z]*} instead of *). new punk::args::private namespace (namespace path to punk::args/lib/system) for internal helpers - _get_dict_can_assign_value, _split_type_expression, _check_clausecolumn, _synopsis_form_arg_display, _argerror_load_colours and lib::_parse_tstr_parts moved there with underscore prefixes dropped. documentation: PUNKARGS definitions added for every remaining exported command (errorstyle, undefine, undefine_deflist, raw_def, resolved_def_values, get_spec, is_dynamic, rawdef_id, rawdef_is_dynamic, id_exists, idaliases, set_idalias, unset_idalias, get_idalias, id_query, real_id, status, choiceword_match, get_dict; lib: string_is_dict, flatzip, zero_based_posns, choiceinfo_marks, indent, undent, undentleader, longestCommonPrefix, lunique; helpers and argdocbase B/N/I/NI); resolve's empty @cmd -help filled in; punk::args::argdocbase added to the registered definition namespaces
#0.3.2 - Tcl 9.1 compatibility (TIP 746 removed expr behaviour from lseq operands): zero_based_posns now wraps its count-1 operand in expr
#0.3.1 - fixed helpers::example -title path calling bare [a] (only resolvable where a global 'a' alias exists, e.g. punk shells) - now punk::ansi::a; found by the new examples.test running under plain tclsh
#0.3.0 - new: -choicealiases {alias canonical ...} argument option (G-040) - aliases accepted exact under any -choiceprefix/-nocase setting, join the prefix-calculation pool when -choiceprefix is true, and normalize to their canonical choice in parse results; deny applies to the matched name (alias deny requires full alias; canonical reached via alias exempt from the canonical's own deny); usage display folds aliases into the canonical entry's label as an (alias:...) note and includes alias names in display prefix calculation; alias->existing-choice and no-collision validated at definition resolve. new public helper punk::args::choiceword_match - the single choice-word matching implementation extracted from get_dict, also consumed by punk::ns cmd_traverse for doc-lookup parity
#0.2.3 - fixed "@opts -any 1" adhoc option passthrough: an option not in the definition crashed get_dict ("can't read argname") at the name-mapping stage instead of passing through - adhoc opts now fall back to their raw supplied name (argstate/arg_checks already carried them); commented out a debug puts stderr (">>>_get_dict_can_assign_value NOT alloc_ok...") that fired on every failed clause type assignment (e.g. any multiform parse miss)
#0.2.2 - documentation-only: define doc clarifies -choicerestricted 0 passthrough (non-matching/ambiguous/denied/reserved words accepted as ordinary values), -choiceprefix result normalization to the canonical choice + minimal-prefix display highlighting, -choiceprefixdenylist behaviour for shorter prefixes in both restricted modes, and -choiceprefixreservelist phantom-entry idiom for per-choice minimum-prefix control