diff --git a/CHANGELOG.md b/CHANGELOG.md index f344d292..434a2da3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to Entries are newest-first; one bullet per notable change. See the root `AGENTS.md` "Project Versioning" section for the bump policy. +## [0.12.13] - 2026-07-13 + +- G-051 achieved: punk::ns 0.4.0 - the help system's doc walk now accepts the same choice-word abbreviations parsing accepts: 'i string is tr' resolves to the 'string is true' documentation exactly as 'string is tr 1' executes (unique prefixes, aliases, nocase; ambiguous/denied/unknown words stay at the parent exactly when parse rejects them). cmdinfo also reports the truthful cmdtype 'doconly' (was 'notfound') for documentation-only levels such as 'string is ' and documented TclOO method docids. punk::lib 0.4.1 adapts its script analysis to the new value with identical behaviour. + ## [0.12.12] - 2026-07-12 - punk::ns 0.3.0: 'i ' with no argument words again signals when the command cannot be called bare - e.g 'i if' shows "Bad number of trailing values for if. Got 0 values. Expected at least 2" in the error scheme above the usage table (regression vs older builds, reported by the user). The G-046-era suppression of that render existed because the old message carried internal-looking attribution ("for punk::args::parse ..."); the G-049 -caller attribution fixed the message wording, so the suppression was reversed rather than reworded - the original 'i string is' complaint case now renders an accurate "Bad number of leading values for string is ..." instead of being hidden. diff --git a/GOALS-archive.md b/GOALS-archive.md index 00f8e37a..cb446fc7 100644 --- a/GOALS-archive.md +++ b/GOALS-archive.md @@ -58,6 +58,10 @@ Acceptance: parsing/argument resolution provably skips -help expansion (a defini Scope: src/modules/punk/args-999999.0a1.0.tm (arg_error, parse error dispatch, colour-scheme handling), src/modules/punk/ns-999999.0a1.0.tm (cmdhelp), src/tests/modules/punk/args/testsuites/args/usagemarking.test, src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test Acceptance: cmdhelp -return dict distinguishes an incomplete, a fully-valid and an invalid argument set via per-argument statuses (received/ok/bad + overall scheme/message/form) with the structure documented; the table and string renderers derive their marking from that same structure, with rendered output unchanged except where the pinned GAP tests flip: badarg marking covers type/allocation failures not just choice violations (cmdhelp_GAP_no_badarg_marking_for_failed_typed_value), an explicit -scheme is honoured on the parse-failure path (cmdhelp_GAP_explicit_scheme_ignored_on_failure), the failure message names the queried command instead of cmdhelp's internal parse source line (cmdhelp_GAP_errormsg_leaks_internal_source), and scheme rendering no longer depends on or mutates shared colour state - the documented -scheme choice value 'nocolour' takes effect and repeated renders of the same call are identical regardless of prior scheme renders (usagemarking_GAP_scheme_nocolour_renders_with_leftover_colours, usagemarking_GAP_dash_nocolour_leaks_into_shared_array, usagemarking_GAP_dash_nocolour_leak_affects_later_info_render); all non-GAP characterization tests in usagemarking.test and cmdhelp.test pass unchanged. +### G-051 [achieved 2026-07-13] cmdinfo truthful cmdtype for doc-only pseudo-commands and space-form docid prefix parity → detail: goals/archive/G-051-cmdinfo-pseudo-and-prefix.md +Scope: src/modules/punk/ns-999999.0a1.0.tm (cmdinfo, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test, src/tests/modules/punk/ns/testsuites/ns/cmdflow.test +Acceptance: the pinned GAP tests flip: cmdhelp_GAP_pseudo_command_cmdtype_notfound and cmdhelp_GAP_string_is_true_pseudo report the new cmdtype with the docid unchanged, cmdhelp_GAP_spaceform_docid_prefix_not_honoured and cmdhelp_GAP_string_is_prefix_not_honoured resolve the child docid from a prefix exactly when parse accepts that prefix (honouring -choiceprefix, -choiceprefixdenylist, -choiceprefixreservelist and -choicealiases per G-040 parity); consumers of cmdinfo's cmdtype (cmdhelp, synopsis, eg) handle the new value with no behaviour change for real commands; cmdflow.test and the non-GAP cmdhelp.test tests pass unchanged. + ### G-054 [achieved 2026-07-11] tclcore moduledoc: runtime-harvested 'string is' class choices with cross-version behavioural parity pins → detail: goals/archive/G-054-tclcore-stringis-harvest.md Scope: src/modules/punk/args/moduledoc/tclcore-999999.0a1.0.tm (+ tclcore-buildversion.txt), src/tests/modules/punk/args/testsuites/args/ (new parity test), TEMP_REFERENCE/tcl9 (read-only reference) Acceptance: parse/parse_status against ::tcl::string::is and its per-class virtual ids agrees with the real interpreter's error-vs-ok outcome for a pinned probe matrix (missing args, trailing flag-like str word, option/class unique-prefix acceptance and ambiguity rejection, unknown option/class, -failindex var consumption leaving no str, per-version class presence: dict, unicode) on Tcl 9.0.x and 8.6; the rendered choices show only classes the running interp accepts; the parity test derives expectations from the live interpreter (not version arithmetic) and passes under both; existing args/tclcore suites pass; tclcore buildversion bumped with changelog. diff --git a/GOALS.md b/GOALS.md index 5a6c399a..664b0380 100644 --- a/GOALS.md +++ b/GOALS.md @@ -222,10 +222,6 @@ Detail: goals/G-048-textblock-table-punkargs.md Scope: src/modules/punk/ns-999999.0a1.0.tm (synopsis), src/modules/punk/args-999999.0a1.0.tm (synopsis renderer), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test (synopsis pins) Detail: goals/G-050-synopsis-validity-marking.md -### G-051 [proposed] cmdinfo truthful cmdtype for doc-only pseudo-commands and space-form docid prefix parity -Scope: src/modules/punk/ns-999999.0a1.0.tm (cmdinfo, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test, src/tests/modules/punk/ns/testsuites/ns/cmdflow.test -Detail: goals/G-051-cmdinfo-pseudo-and-prefix.md - ### G-052 [proposed] TclOO method-level autodef documentation Scope: src/modules/punk/ns-999999.0a1.0.tm (generate_autodef oo branches, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test Detail: goals/G-052-oo-method-autodef.md diff --git a/goals/G-051-cmdinfo-pseudo-and-prefix.md b/goals/G-051-cmdinfo-pseudo-and-prefix.md index 98af2365..feca24aa 100644 --- a/goals/G-051-cmdinfo-pseudo-and-prefix.md +++ b/goals/G-051-cmdinfo-pseudo-and-prefix.md @@ -1,6 +1,6 @@ # G-051 cmdinfo truthful cmdtype for doc-only pseudo-commands and space-form docid prefix parity -Status: proposed +Status: achieved 2026-07-13 Scope: src/modules/punk/ns-999999.0a1.0.tm (cmdinfo, cmd_traverse), src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test, src/tests/modules/punk/ns/testsuites/ns/cmdflow.test Goal: cmdinfo reports a distinct cmdtype (e.g 'doconly') when resolution lands on a punk::args id with no corresponding real command instead of today's 'notfound', and the space-delimited docid jump accepts the same word prefixes the parser accepts - via the shared punk::args::choiceword_match resolver, not a second matching rule - so 'i string is tr' documents what 'string is tr' actually executes. Acceptance: the pinned GAP tests flip: cmdhelp_GAP_pseudo_command_cmdtype_notfound and cmdhelp_GAP_string_is_true_pseudo report the new cmdtype with the docid unchanged, cmdhelp_GAP_spaceform_docid_prefix_not_honoured and cmdhelp_GAP_string_is_prefix_not_honoured resolve the child docid from a prefix exactly when parse accepts that prefix (honouring -choiceprefix, -choiceprefixdenylist, -choiceprefixreservelist and -choicealiases per G-040 parity); consumers of cmdinfo's cmdtype (cmdhelp, synopsis, eg) handle the new value with no behaviour change for real commands; cmdflow.test and the non-GAP cmdhelp.test tests pass unchanged. @@ -53,3 +53,40 @@ cmdhelp_GAP_string_is_prefix_not_honoured (real tclcore docs). - 'string is' has a second wrinkle out of scope here: its per-class ids are generated from the parent's -choicelabels at tclcore load time; prefix parity must come from the walk, not from generating extra prefix ids. + +## Progress + +### 2026-07-13 implemented (punk::ns 0.4.0, punk::lib 0.4.1) - acceptance complete + +- doconly cmdtype: cmdinfo classifies cmdwhich-notfound + non-empty docid as + 'doconly' after the curried-alias retry. Design decision (anticipated in + Context): the TclOO documented-method case (" docmeth" docids) ADOPTS + doconly rather than a method-specific value - G-052 may refine when it takes + up method-level autodef; cmdhelp_oo_documented_method's docid assertion holds + unchanged. +- Consumers audited: cmdhelp (docid-driven; its origintype switch only branches + on 'script'; doconly implies docid non-empty so the undocumented fallback is + unreachable for it), synopsis and eg (docid-driven), cmdtrace (tests only for + 'proc'), punk::help topic fallback (uses cmdwhich whichtype, not cmdinfo), + punk::lib tclscript analysis (doconly accepted alongside notfound at the + subcommand-walk stop condition and the bucketing switch - identical behaviour + preserved, the 'string is xdigit' comment there anticipated exactly this). +- Space-form prefix parity: cmd_traverse's exact-word space-form jump gains a + choiceword_match retry (current level's choices-bearing first leader; the + shared G-040 resolver, no second matching rule) resolving the canonical word + before the id_exists retest; resolvedargs records the canonical, mirroring + parse normalization. +- GAP flips (renamed): cmdhelp_pseudo_command_cmdtype_doconly, + cmdhelp_spaceform_docid_prefix_honoured (extended with ambiguous/unknown-word + stays-at-parent guard), cmdhelp_string_is_true_pseudo_doconly, + cmdhelp_string_is_prefix_honoured. +- Live verification (punk902z src, Tcl 9.0.2): 'i string is tr' resolves docid + ::tcl::string::is true (doconly) and renders byte-identical to + 'i string is true' except the failure banner echoing the typed words + ("for string is tr" vs "for string is true" - the -caller echo of user + input, considered correct); 'string is bool' -> boolean; ambiguous 'd' and + unknown 'zz' stay at the parent docid exactly as parse rejects them. +- Suites (tclsh 9.0.3): punk::ns 53/53 (cmdflow + non-GAP cmdhelp unchanged), + punk::args 193 pass / 1 pre-existing skip, punk::lib 35/35; full source-tree + suite 827 total, 813 pass, 13 skip, 1 fail = exec-14.3 only (known + pre-existing core-test baseline) - zero regressions. diff --git a/goals/G-052-oo-method-autodef.md b/goals/G-052-oo-method-autodef.md index 4741452f..b4bde666 100644 --- a/goals/G-052-oo-method-autodef.md +++ b/goals/G-052-oo-method-autodef.md @@ -52,5 +52,8 @@ just not wired up as a general method-level (autodef) generation step in the doc documented, plainmeth undocumented). - Filters, private methods and `unknown` handlers are marked in choiceinfo today but out of scope for autodef generation. -- Coordinate the cmdtype reported for method resolutions with G-051's doconly decision. +- G-051 (achieved 2026-07-13 - see goals/archive/G-051-cmdinfo-pseudo-and-prefix.md) + decided the documented-method case ADOPTS the doconly cmdtype (docid-nonempty + + cmdwhich-notfound classification, no method-specific value). Refine here if this + goal's method-level autodef work warrants a distinct method cmdtype. - Archived-goal references in this file: G-040 achieved 2026-07-08 (goals/archive/G-040-punkargs-choicealiases.md). diff --git a/punkproject.toml b/punkproject.toml index 319a0de7..46976598 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,4 +1,4 @@ [project] name = "punkshell" -version = "0.12.12" +version = "0.12.13" license = "BSD-2-Clause" diff --git a/src/modules/punk/lib-999999.0a1.0.tm b/src/modules/punk/lib-999999.0a1.0.tm index 2537a2dc..69436eda 100644 --- a/src/modules/punk/lib-999999.0a1.0.tm +++ b/src/modules/punk/lib-999999.0a1.0.tm @@ -2455,8 +2455,11 @@ namespace eval punk::lib { #no change in origin - so we are into the arguments of the command, or have an invalid subcommand - stop looking for subcommands #todo - detect invalid subcommand and count as unknown command? break - } elseif {[dict get $test_cinfo cmdtype] in {"proc" "native" "notfound"}} { + } elseif {[dict get $test_cinfo cmdtype] in {"proc" "native" "notfound" "doconly"}} { #we have a subcommand that won't be introspectable at a deeper level. + #(doconly: G-051 - cmdinfo's truthful cmdtype for documentation-only + #levels such as 'string is xdigit', previously reported 'notfound'; + #treated identically here to preserve prior analysis behaviour) set cinfo $test_cinfo set ctype [dict get $cinfo cmdtype] break @@ -2714,7 +2717,12 @@ namespace eval punk::lib { dict lappend resultd commands_native $dispatchwords } } - "notfound" { + "notfound" - + "doconly" { + #doconly: G-051 - documentation-only level (e.g 'string is xdigit'), + #previously reported as 'notfound'; bucketed identically to preserve + #prior analysis behaviour (a future refinement may count doconly as a + #valid command word rather than notfound) if {$dispatchwords ni [dict get $resultd commands_notfound]} { dict lappend resultd commands_notfound $dispatchwords } diff --git a/src/modules/punk/lib-buildversion.txt b/src/modules/punk/lib-buildversion.txt index d742dffb..dbe56cd5 100644 --- a/src/modules/punk/lib-buildversion.txt +++ b/src/modules/punk/lib-buildversion.txt @@ -1,6 +1,7 @@ -0.4.0 +0.4.1 #First line must be a semantic version number #all other lines are ignored. +#0.4.1 - G-051 call-site adaptation: tclscript analysis accepts cmdinfo's new 'doconly' cmdtype alongside 'notfound' (subcommand-walk stop condition and the dispatchwords bucketing switch) - bucketed identically to notfound to preserve prior analysis behaviour; a future refinement may count doconly (a documented pseudo-command such as 'string is xdigit') as a valid command word. #0.4.0 - G-058: snapshot_package_paths and interp_sync_package_paths now also propagate the runtime static/builtin package baseline captured at kit boot (::punkboot::static_prefixes/static_packages - see punk_main.tcl) and seed 'package ifneeded {load {} }' entries in the target thread/interp, so statically-linked runtime packages (e.g Thread/twapi on a tcl-sfe runtime) resolve in fabricated interps whose package search paths punkshell controls. No-op when no baseline was captured (plain tclsh dev launches). #0.3.1 - Tcl 9.1 compatibility (TIP 746 removed expr behaviour from lseq operands): range (lseq branch) now normalizes int[+-]int offset operands itself via offset_expr - callers such as `range 0 [llength $list]-1` keep working; also aligned the lseq branch with the fallback contract: default by now infers direction (range 5 1 -> descending, previously empty under tcl9) and by 0 returns empty (Tcl 9.1 lseq changed by-0 to return one element). lzipn_tcl9b/lzipn_tcl9c/cols/cols2: lseq expression operands wrapped in expr. check::has_tclbug_safeinterp_compile: Tcl 9.1 safe interps hide tcl::unsupported::* - falls back to interp invokehidden tcl:unsupported:disassemble #0.3.0 - new: punk::lib::check::has_libbug_udp_threadexit + libbug_udp_threadexit_applies classifier - version-based detection of tcludp < 1.0.13 on Tcl 9 Windows (per-thread exit handler closes process-global event handles; G-036). has_libbug_* is the new check family for bundled/vendored library bugs, surfaced through 'help tcl' alongside has_tclbug_*; buginfo dicts may carry a full 'url' reference key (non tcl-core trackers) diff --git a/src/modules/punk/ns-999999.0a1.0.tm b/src/modules/punk/ns-999999.0a1.0.tm index f43b9787..5c686fb6 100644 --- a/src/modules/punk/ns-999999.0a1.0.tm +++ b/src/modules/punk/ns-999999.0a1.0.tm @@ -4845,6 +4845,15 @@ y" {return quirkykeyscript} return [cmdinfo {*}$next] } } + if {$cmdtype eq "notfound" && $docid ne ""} { + #G-051: resolution landed on a punk::args id with no corresponding real + #command - a documentation-only level below (or beside) a real command, + #e.g the per-class id "::tcl::string::is true" documenting a level below + #the real ::tcl::string::is (the class words are arguments, not + #subcommands). Report it distinctly so consumers can tell it from a + #genuinely unknown command. The docid remains authoritative for display. + set cmdtype doconly + } return [list origin $origin cmdtype $cmdtype args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack] } proc cmd_traverse {ns formid args} { @@ -5023,8 +5032,49 @@ y" {return quirkykeyscript} #(would not support shor-form prefix of subcommand - even if the proc implementation did) set docid_exists 0 set eparams [list] + set a_spaceform "" if {[punk::args::id_exists "$origin [lindex $args $i]"]} { - set a [lindex $args $i] + set a_spaceform [lindex $args $i] + } elseif {$docid ne "" && [punk::args::id_exists $docid]} { + #G-051 space-form docid prefix parity: no space-form id exists for the + #exact word - if the current level's definition has a choices-bearing + #first leader, resolve the word with the same shared resolver argument + #parsing uses (punk::args::choiceword_match - honouring -choiceprefix, + #-nocase, -choicealiases, -choiceprefixdenylist, + #-choiceprefixreservelist) and retry the space-form lookup with the + #canonical word - so 'i string is tr' lands on the documentation for + #what 'string is tr' actually executes. No second matching rule: a word + #parse would reject resolves nothing here either, and a canonical with + #no space-form id falls through to the normal per-level handling. + set pf_spec [punk::args::get_spec $docid] + set pf_fid [lindex [dict get $pf_spec form_names] 0] + set pf_leaders [dict get $pf_spec FORMS $pf_fid LEADER_NAMES] + if {[llength $pf_leaders]} { + set pf_arginfo [dict get $pf_spec FORMS $pf_fid ARG_INFO [lindex $pf_leaders 0]] + set pf_allchoices [punk::args::system::Dict_getdef $pf_arginfo -choices {}] + foreach {_pf_g pf_members} [punk::args::system::Dict_getdef $pf_arginfo -choicegroups {}] { + lappend pf_allchoices {*}$pf_members + } + if {[llength $pf_allchoices]} { + set pf_matchinfo [punk::args::choiceword_match [lindex $args $i]\ + [punk::args::system::Dict_getdef $pf_arginfo -nocase 0]\ + $pf_allchoices\ + [punk::args::system::Dict_getdef $pf_arginfo -choicealiases {}]\ + [punk::args::system::Dict_getdef $pf_arginfo -choiceprefix 1]\ + [punk::args::system::Dict_getdef $pf_arginfo -choiceprefixdenylist {}]\ + [punk::args::system::Dict_getdef $pf_arginfo -choiceprefixreservelist {}]\ + ] + if {[dict get $pf_matchinfo matched]} { + set pf_canonical [dict get $pf_matchinfo canonical] + if {$pf_canonical ne [lindex $args $i] && [punk::args::id_exists "$origin $pf_canonical"]} { + set a_spaceform $pf_canonical + } + } + } + } + } + if {$a_spaceform ne ""} { + set a $a_spaceform #review - tests? #puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'" #we can only seek beyond an undocumented subcommand level via a space delimited path, as we can make no assumption about the actual location of a subcommand relative to its parent @@ -5034,7 +5084,7 @@ y" {return quirkykeyscript} set origin [list $origin $a] incr i set queryargs [lrange $args $i end] - set resolvedargs [list $a] ;# + set resolvedargs [list $a] ;#the canonical word (a resolved prefix/alias records its canonical, as parse normalization does) set queryargs_untested $queryargs } elseif {[punk::args::id_exists $docid]} { set docid_exists 1 diff --git a/src/modules/punk/ns-buildversion.txt b/src/modules/punk/ns-buildversion.txt index 2845c9a0..742b9ecb 100644 --- a/src/modules/punk/ns-buildversion.txt +++ b/src/modules/punk/ns-buildversion.txt @@ -1,6 +1,7 @@ -0.3.0 +0.4.0 #First line must be a semantic version number #all other lines are ignored. +#0.4.0 - G-051: (a) cmdinfo reports cmdtype 'doconly' (was 'notfound') when resolution lands on a punk::args id with no corresponding real command - documentation-only levels such as the per-class id "::tcl::string::is true" below the real ::tcl::string::is, and TclOO documented-method docids like " docmeth" (method case adopts doconly; may be refined by G-052). Consumers audited: cmdhelp/synopsis/eg are docid-driven, cmdtrace only tests for 'proc', punk::lib script analysis updated in step (lib 0.4.1). (b) space-form docid prefix parity: cmd_traverse's space-delimited child docid jump, on an exact-word miss, resolves the word against the current level's choices-bearing first leader via punk::args::choiceword_match (the shared G-040 resolver - -choiceprefix/-nocase/-choicealiases/denylist/reservelist honoured) and retries with the canonical word - so 'i string is tr' resolves to "::tcl::string::is true" exactly when 'string is tr' executes, ambiguous/unknown/denied words stay at the parent exactly when parse rejects them, and resolvedargs records the canonical (as parse normalization does). Tests: the four G-051 GAP pins flipped (cmdhelp_pseudo_command_cmdtype_doconly, cmdhelp_spaceform_docid_prefix_honoured incl ambiguous/unknown guard, cmdhelp_string_is_true_pseudo_doconly, cmdhelp_string_is_prefix_honoured). #0.3.0 - reversal of the G-046-item-5 no-supplied-words suppression (user direction 2026-07-12): cmdhelp's advisory parse failing with NO supplied argument words renders the failure message and error scheme again (both the alias path and the main path; dict returns no longer rewrite the scheme to info), so 'i if'/'i while'/'i foreach' once more signal that the command cannot be called bare - e.g "Bad number of trailing values for if. Got 0 values. Expected at least 2". Rationale: the suppression (ns 0.1.4) existed because the pre-G-049 message was internal-looking ("... for punk::args::parse $args_remaining ..."); the G-049 -caller attribution (ns 0.2.0) made bare-query messages accurate - including the original 'i string is' complaint case, which now reads "Bad number of leading values for string is. Got 0 leaders. Expected exactly 1". Tests: cmdhelp_leader_required_no_args_plain_usage flipped to cmdhelp_leader_required_no_args_error_render; cmdhelp_return_dict_scheme expects scheme error for the bare-query failure. #0.2.0 - G-049: cmdhelp -return dict - machine-parsable return carrying resolution info (origin/docid/cmdtype/args_remaining) plus the parse-status structure of the supplied argument words (punk::args::parse_status shape; empty for undocumented commands); the scheme field reflects an explicit -scheme and the G-046-item-5 no-supplied-words suppression. cmdhelp's advisory parse now runs via punk::args::parse_status on both the alias path and the main path: an explicit -scheme is honoured on the parse-failure render (previously only on success/tableobject - failures returned parse's internally rendered error with the default error scheme), failure renders consume the structure via arg_error -parsestatus (badarg marking now covers type/allocation failures via the structure), and the failure message names the queried command (parse -caller: querycommand + consumed subcommand words) instead of whatever the %caller% frame walk found - at top call depth that was cmdhelp's own raw 'punk::args::parse $args_remaining ...' source text. Tests: cmdhelp.test G-049 GAP pins flipped + cmdhelp_return_dict_* added #0.1.4 - G-046 item 5: cmdhelp's advisory goodargs parse failing with NO supplied argument words (e.g 'i string is' where the definition requires leaders) now shows plain info-scheme usage instead of the internal-looking "Bad number of leading values for punk::args::parse ..." error output (both the alias path and the main path; error display for supplied-but-invalid words unchanged). The no-supplied-words advisory parse runs with -errorstyle minimal so its failure doesn't render the full usage table inside the discarded error - large argdocs (e.g 'i punk::args::define') render the table once, not twice (verified parity with pre-G-046 timings: ~5.3s first/~4.1s repeat on punk91 src, table construction dominant). Test: cmdhelp.test cmdhelp_leader_required_no_args_plain_usage diff --git a/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test b/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test index e8c99577..66252fa0 100644 --- a/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test +++ b/src/tests/modules/punk/ns/testsuites/ns/cmdhelp.test @@ -439,7 +439,14 @@ namespace eval ::testspace { #--- GAP pins: pseudo-command cmdtype + space-delimited docid prefixes (G-051) ------------ - test cmdhelp_GAP_pseudo_command_cmdtype_notfound {a space-delimited docid below a real command resolves its documentation but reports cmdtype 'notfound'}\ + #G-051 flipped pins (were cmdhelp_GAP_pseudo_command_cmdtype_notfound / + #cmdhelp_GAP_spaceform_docid_prefix_not_honoured / cmdhelp_GAP_string_is_true_pseudo / + #cmdhelp_GAP_string_is_prefix_not_honoured): cmdinfo reports cmdtype 'doconly' when + #resolution lands on a punk::args id with no corresponding real command, and the + #space-form docid jump resolves choice prefixes via punk::args::choiceword_match + #(the shared resolver - no second matching rule) when the exact word has no id. + + test cmdhelp_pseudo_command_cmdtype_doconly {a space-delimited docid below a real command resolves its documentation and reports cmdtype 'doconly'}\ -setup $common -body { set cinfo [punk::ns::cmdinfo ::testspace::helpstr is] lappend result [dict get $cinfo docid] [dict get $cinfo cmdtype] @@ -448,22 +455,26 @@ namespace eval ::testspace { }\ -cleanup { }\ - -result [list {::testspace::helpstr is} notfound {::testspace::helpstr is} hello] + -result [list {::testspace::helpstr is} doconly {::testspace::helpstr is} hello] - test cmdhelp_GAP_spaceform_docid_prefix_not_honoured {parse accepts a unique choice prefix for the subcommand word but the space-delimited docid jump requires the exact word}\ + test cmdhelp_spaceform_docid_prefix_honoured {the space-delimited docid jump accepts the choice prefixes parse accepts, resolving to the canonical child docid}\ -setup $common -body { #parse side: unique prefix 'i' of choice 'is' is accepted and normalized set argd [punk::args::parse {i} withid ::testspace::helpstr] lappend result [dict get [dict get $argd leaders] subcmd] - #doc-walk side: the same prefix does not reach the child docid + #doc-walk side: the same prefix reaches the child docid with the canonical + #word consumed set cinfo [punk::ns::cmdinfo ::testspace::helpstr i] lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining] + #an ambiguous or unknown word still stays at the parent (parse would reject it) + set cinfo [punk::ns::cmdinfo ::testspace::helpstr zz] + lappend result [dict get $cinfo docid] [dict get $cinfo args_remaining] }\ -cleanup { }\ - -result [list is ::testspace::helpstr i] + -result [list is {::testspace::helpstr is} {} ::testspace::helpstr zz] - test cmdhelp_GAP_string_is_true_pseudo {real-world pin: 'string is true' resolves its tclcore docid but reports cmdtype 'notfound'}\ + test cmdhelp_string_is_true_pseudo_doconly {real-world pin: 'string is true' resolves its tclcore docid and reports cmdtype 'doconly'}\ -constraints have_tclcoredocs\ -setup $common -body { set cinfo [punk::ns::cmdinfo ::string is true] @@ -471,9 +482,9 @@ namespace eval ::testspace { }\ -cleanup { }\ - -result [list {::tcl::string::is true} notfound] + -result [list {::tcl::string::is true} doconly] - test cmdhelp_GAP_string_is_prefix_not_honoured {real-world pin: 'string is tr' works in Tcl but the doc walk stays at the parent docid}\ + test cmdhelp_string_is_prefix_honoured {real-world pin: 'i string is tr' documents what 'string is tr' executes}\ -constraints have_tclcoredocs\ -setup $common -body { #Tcl itself accepts the class prefix @@ -483,7 +494,7 @@ namespace eval ::testspace { }\ -cleanup { }\ - -result [list 1 ::tcl::string::is tr] + -result [list 1 {::tcl::string::is true} {}] #--- TclOO methods (G-052) -----------------------------------------------------------------