Browse Source

vfscommon promotion: G-176 coherent set + r2-era layout/templates sync

Release-step-(9) commit of the Step 5 promotion outputs (packages mint +
vfscommonupdate, driven by the tcllibc-accelerated family runtime):
_vfscommon.vfs module swap commandstack 0.7.1->0.8.0, punk 0.2.8->0.3.0,
ansi 0.2.0->0.2.1, args 0.18.0->0.25.2, libunknown 0.2.4->0.3.1,
ns 0.9.3->0.11.0, moduledoc tclcore 0.4.0->0.4.2 + punkboot 0.3.1->0.3.2;
templates-0.2.0.tm modpod repacked; the three layout-store make.tcl copies
re-synced (verified byte-identical to src/make.tcl - carries the
libunknown package-provide guard swap 5c47f3b9 and the 0.65.x message
rework). Kits pick all of this up at the next bake.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 day ago
parent
commit
760882aad3
  1. 20
      src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl
  2. 20
      src/project_layouts/vendor/punk/basic/src/make.tcl
  3. 20
      src/project_layouts/vendor/punk/project-0.1/src/make.tcl
  4. 153
      src/vfs/_vfscommon.vfs/modules/commandstack-0.8.0.tm
  5. 285
      src/vfs/_vfscommon.vfs/modules/punk-0.3.0.tm
  6. 8
      src/vfs/_vfscommon.vfs/modules/punk/ansi-0.2.1.tm
  7. 808
      src/vfs/_vfscommon.vfs/modules/punk/args-0.25.2.tm
  8. 15
      src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/punkboot-0.3.2.tm
  9. 39
      src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/tclcore-0.4.2.tm
  10. 132
      src/vfs/_vfscommon.vfs/modules/punk/libunknown-0.3.1.tm
  11. BIN
      src/vfs/_vfscommon.vfs/modules/punk/mix/templates-0.2.0.tm
  12. 294
      src/vfs/_vfscommon.vfs/modules/punk/ns-0.11.0.tm

20
src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl vendored

@ -672,6 +672,9 @@ proc ::punkboot::lib::bootsupport_stale_warning {stale_modules invoked_cmd scrip
puts stderr " Recommended fix - the SAME commands launched from src/, so the updated"
puts stderr " source modules drive the update:"
puts stderr " cd $scriptfolder && tclsh make.tcl modules && tclsh make.tcl bootsupport"
puts stderr " [::punkboot::sgr 31]Afterwards return to the project root for the remaining steps (vfscommonupdate,[::punkboot::sgr]"
puts stderr " [::punkboot::sgr 31]bake ...) - routine runs are canonically root-launched on the bootsupport[::punkboot::sgr]"
puts stderr " [::punkboot::sgr 31]snapshot you just refreshed, which also re-arms this staleness check.[::punkboot::sgr]"
puts stderr "=============================================================================="
}
@ -1701,6 +1704,8 @@ if {[file tail $startdir] eq "src"} {
puts stderr "------------------------------------------------------------------"
puts stderr "Launched from within a folder ending in 'src'"
puts stderr " - modules in $startdir/modules $startdir/lib (etc) may override bootsupport modules"
puts stderr " - fine for bootsupport repair and source-tooling testing"
puts stderr " - [::punkboot::sgr 31]routine producing runs (vfscommonupdate, bake ...) are canonically launched from the project root[::punkboot::sgr]"
puts stderr "------------------------------------------------------------------"
}
}
@ -1775,12 +1780,15 @@ if {$bootsupport_paths_exist || $sourcesupport_paths_exist} {
}
}
if {$libunknown ne ""} {
if {[info commands ::punk::libunknown::package] ne ""} {
if {[package provide punk::libunknown] ne ""} {
#libunknown already active in this interp - e.g make.tcl driven by a built punk
#executable whose boot (punk_main.tcl) initialised it. init's rename of ::package
#must not be repeated (its guard would emit an 'init already done' diagnostic and
#return), and re-sourcing would silently swap the running copy for the bootsupport
#copy - leave the active one in place.
#executable whose boot (punk_main.tcl) sourced and initialised it. init's
#::package override must not be repeated, and re-sourcing would silently swap
#the running copy for the bootsupport copy - leave the active one in place.
#(G-176 follow-on: probe by package-provide, not 'info commands
#::punk::libunknown::package' - the 0.3.x commandstack-managed install no
#longer creates that proc, while every vintage's boot-site source executes
#'package provide punk::libunknown'.)
} else {
source $libunknown
if {[catch {punk::libunknown::init -caller make.tcl} errM]} {
@ -4878,7 +4886,7 @@ if {$::punkboot::command in {bakehouse packages modules libs bake vfslibs bin bo
if {![catch {chan configure stdin -inputmode}]} {
puts -nonewline stderr " proceeding despite dirty src - ctrl-c now to abort "
flush stderr
foreach tick {3 2 1} {
foreach tick {4 3 2 1} {
puts -nonewline stderr "..$tick"
flush stderr
after 1000

20
src/project_layouts/vendor/punk/basic/src/make.tcl vendored

@ -672,6 +672,9 @@ proc ::punkboot::lib::bootsupport_stale_warning {stale_modules invoked_cmd scrip
puts stderr " Recommended fix - the SAME commands launched from src/, so the updated"
puts stderr " source modules drive the update:"
puts stderr " cd $scriptfolder && tclsh make.tcl modules && tclsh make.tcl bootsupport"
puts stderr " [::punkboot::sgr 31]Afterwards return to the project root for the remaining steps (vfscommonupdate,[::punkboot::sgr]"
puts stderr " [::punkboot::sgr 31]bake ...) - routine runs are canonically root-launched on the bootsupport[::punkboot::sgr]"
puts stderr " [::punkboot::sgr 31]snapshot you just refreshed, which also re-arms this staleness check.[::punkboot::sgr]"
puts stderr "=============================================================================="
}
@ -1701,6 +1704,8 @@ if {[file tail $startdir] eq "src"} {
puts stderr "------------------------------------------------------------------"
puts stderr "Launched from within a folder ending in 'src'"
puts stderr " - modules in $startdir/modules $startdir/lib (etc) may override bootsupport modules"
puts stderr " - fine for bootsupport repair and source-tooling testing"
puts stderr " - [::punkboot::sgr 31]routine producing runs (vfscommonupdate, bake ...) are canonically launched from the project root[::punkboot::sgr]"
puts stderr "------------------------------------------------------------------"
}
}
@ -1775,12 +1780,15 @@ if {$bootsupport_paths_exist || $sourcesupport_paths_exist} {
}
}
if {$libunknown ne ""} {
if {[info commands ::punk::libunknown::package] ne ""} {
if {[package provide punk::libunknown] ne ""} {
#libunknown already active in this interp - e.g make.tcl driven by a built punk
#executable whose boot (punk_main.tcl) initialised it. init's rename of ::package
#must not be repeated (its guard would emit an 'init already done' diagnostic and
#return), and re-sourcing would silently swap the running copy for the bootsupport
#copy - leave the active one in place.
#executable whose boot (punk_main.tcl) sourced and initialised it. init's
#::package override must not be repeated, and re-sourcing would silently swap
#the running copy for the bootsupport copy - leave the active one in place.
#(G-176 follow-on: probe by package-provide, not 'info commands
#::punk::libunknown::package' - the 0.3.x commandstack-managed install no
#longer creates that proc, while every vintage's boot-site source executes
#'package provide punk::libunknown'.)
} else {
source $libunknown
if {[catch {punk::libunknown::init -caller make.tcl} errM]} {
@ -4878,7 +4886,7 @@ if {$::punkboot::command in {bakehouse packages modules libs bake vfslibs bin bo
if {![catch {chan configure stdin -inputmode}]} {
puts -nonewline stderr " proceeding despite dirty src - ctrl-c now to abort "
flush stderr
foreach tick {3 2 1} {
foreach tick {4 3 2 1} {
puts -nonewline stderr "..$tick"
flush stderr
after 1000

20
src/project_layouts/vendor/punk/project-0.1/src/make.tcl vendored

@ -672,6 +672,9 @@ proc ::punkboot::lib::bootsupport_stale_warning {stale_modules invoked_cmd scrip
puts stderr " Recommended fix - the SAME commands launched from src/, so the updated"
puts stderr " source modules drive the update:"
puts stderr " cd $scriptfolder && tclsh make.tcl modules && tclsh make.tcl bootsupport"
puts stderr " [::punkboot::sgr 31]Afterwards return to the project root for the remaining steps (vfscommonupdate,[::punkboot::sgr]"
puts stderr " [::punkboot::sgr 31]bake ...) - routine runs are canonically root-launched on the bootsupport[::punkboot::sgr]"
puts stderr " [::punkboot::sgr 31]snapshot you just refreshed, which also re-arms this staleness check.[::punkboot::sgr]"
puts stderr "=============================================================================="
}
@ -1701,6 +1704,8 @@ if {[file tail $startdir] eq "src"} {
puts stderr "------------------------------------------------------------------"
puts stderr "Launched from within a folder ending in 'src'"
puts stderr " - modules in $startdir/modules $startdir/lib (etc) may override bootsupport modules"
puts stderr " - fine for bootsupport repair and source-tooling testing"
puts stderr " - [::punkboot::sgr 31]routine producing runs (vfscommonupdate, bake ...) are canonically launched from the project root[::punkboot::sgr]"
puts stderr "------------------------------------------------------------------"
}
}
@ -1775,12 +1780,15 @@ if {$bootsupport_paths_exist || $sourcesupport_paths_exist} {
}
}
if {$libunknown ne ""} {
if {[info commands ::punk::libunknown::package] ne ""} {
if {[package provide punk::libunknown] ne ""} {
#libunknown already active in this interp - e.g make.tcl driven by a built punk
#executable whose boot (punk_main.tcl) initialised it. init's rename of ::package
#must not be repeated (its guard would emit an 'init already done' diagnostic and
#return), and re-sourcing would silently swap the running copy for the bootsupport
#copy - leave the active one in place.
#executable whose boot (punk_main.tcl) sourced and initialised it. init's
#::package override must not be repeated, and re-sourcing would silently swap
#the running copy for the bootsupport copy - leave the active one in place.
#(G-176 follow-on: probe by package-provide, not 'info commands
#::punk::libunknown::package' - the 0.3.x commandstack-managed install no
#longer creates that proc, while every vintage's boot-site source executes
#'package provide punk::libunknown'.)
} else {
source $libunknown
if {[catch {punk::libunknown::init -caller make.tcl} errM]} {
@ -4878,7 +4886,7 @@ if {$::punkboot::command in {bakehouse packages modules libs bake vfslibs bin bo
if {![catch {chan configure stdin -inputmode}]} {
puts -nonewline stderr " proceeding despite dirty src - ctrl-c now to abort "
flush stderr
foreach tick {3 2 1} {
foreach tick {4 3 2 1} {
puts -nonewline stderr "..$tick"
flush stderr
after 1000

153
src/vfs/_vfscommon.vfs/modules/commandstack-0.7.1.tm → src/vfs/_vfscommon.vfs/modules/commandstack-0.8.0.tm

@ -107,6 +107,30 @@ namespace eval commandstack {
}
}
namespace eval commandstack::stackdocs {
#Doc blocks attached by 'rename_command -punkargs' for LIVE stack records
#(G-176): PUNKARGS mirrors those records' punk::args definitionlists so a
#punk::args that loads AFTER the renames (early-boot renames precede it)
#picks them up lazily via the ::punk::args::register::NAMESPACES mechanism.
#Maintained by rename_command (attach) and remove_rename (detach - every
#removal path funnels through it). Guarded per the reload contract.
variable PUNKARGS
if {![info exists PUNKARGS]} {
set PUNKARGS [list]
}
}
namespace eval ::punk::args::register {
#inert registration - consumed if/when punk::args loads (idempotent across
#re-source; punk::args need not be present)
variable NAMESPACES
if {![info exists NAMESPACES]} {
set NAMESPACES [list]
}
if {"::commandstack::stackdocs" ni $NAMESPACES} {
lappend NAMESPACES ::commandstack::stackdocs
}
}
namespace eval commandstack::util {
#note - we can't use something like md5 to ID proc body text because we don't want to require additional packages.
#We could store the full text of the body to compare - but we need to identify magic strings from cooperating packages such as packageTrace
@ -220,6 +244,22 @@ namespace eval commandstack {
commandstack::next {*}$args
The record also carries a trailing did_rename 0|1 verdict.
set record [commandstack::rename_command -renamer <mypkg> -punkargs <deflists> <command> <procargs> <procbody>]
As above, additionally attaching punk::args doc blocks to the stack
record - each <deflists> element is one definitionlist exactly as
given to punk::args::define (e.g documenting a subcommand the
override adds, with a space-form id such as {::package epoch}).
The docs are live while the record is on the stack and are removed
with it by ANY removal path (remove_rename, pop_rename,
remove_renamer, restore_original). Renames performed BEFORE
punk::args loads are supported: definitions are mirrored in the
registered ::commandstack::stackdocs namespace and load lazily with
punk::args; when punk::args is already loaded they are defined
immediately. Use one live record per doc id - same-id declarations
in two records shadow each other, and removing either removes the
doc. The record carries the attached deflists under a trailing
punkargs key.
commandstack::remove_rename <token_or_command>
Undo a rename. Accepts the token from the rename record
([dict get $record token] = {<command> <renamer> <tokenid>}),
@ -268,8 +308,9 @@ namespace eval commandstack {
`i commandstack::rename_command` in punkshell, or
`punk::args::usage ::commandstack::rename_command` when punk::args is loaded.
In-tree users: punk::packagepreference, punk::nav::fs, punk (auto_execok),
packagetrace, packagesuppress.
In-tree users: punk::packagepreference, punk::libunknown (the ::package
epoch/forget override), punk::nav::fs, punk (auto_execok), packagetrace,
packagesuppress.
}
}
@ -458,6 +499,7 @@ namespace eval commandstack {
Returns the new stack record - a dict with keys:
token renamer next_implementor next_getter implementation did_rename
(plus a trailing punkargs key when -punkargs was given).
The tokenid (third token element) is unique and monotonic per
(renamer, command) pairing, so repeat renames by the same
renamer are individually addressable. When no rename was
@ -475,8 +517,28 @@ namespace eval commandstack {
"Identity string recorded for this rename - defaults to
the calling namespace. Cooperating packages use their
package/namespace name. Note: this flag is recognised
only as the FIRST argument (manual parse) - appearing
in any later position is an error."
only in the leading option positions (manual parse) -
appearing after the positional arguments begin is an
error."
-punkargs -type list -optional 1 -typesynopsis {list-of-definitionlists} -help -&
"punk::args doc blocks attached to this rename's stack
record - each element is one definitionlist exactly as
given to punk::args::define (e.g documenting a
subcommand the override adds, with a space-form id
such as {::package epoch}). The docs are live while
the record is on the stack and are removed with it by
ANY removal path (remove_rename, pop_rename,
remove_renamer, restore_original). Renames performed
BEFORE punk::args loads are supported: the definitions
are mirrored in the registered
::commandstack::stackdocs namespace and load lazily
with punk::args (keep such deflists free of
dollar-brace tstr substitutions needing your own
namespace context - the lazy load evaluates them in
the stackdocs namespace).
Use one live record per doc id: same-id declarations
in two records shadow each other. Recognised only in
the leading option positions, like -renamer."
@values -min 3 -max 3
command -type string -help -&
"Command to rename (resolved with 'namespace which' in
@ -493,18 +555,31 @@ namespace eval commandstack {
#todo: consider -forcebase 1 or similar to allow this rename to point to bottom of stack (original command) bypassing existing renames
# - need to consider that upon removing, that any remaining rename that was higher on the stack should not also be diverted to the base - but rather to the next lower in the stack
#
if {[lindex $args 0] eq "-renamer"} {
set renamer [lindex $args 1]
set arglist [lrange $args 2 end]
} else {
set renamer ""
set punkargs_defs [list]
set arglist $args
while {[llength $arglist] > 3 && [string match -* [lindex $arglist 0]]} {
switch -- [lindex $arglist 0] {
-renamer {
set renamer [lindex $arglist 1]
set arglist [lrange $arglist 2 end]
}
-punkargs {
set punkargs_defs [lindex $arglist 1]
set arglist [lrange $arglist 2 end]
}
default {
error "commandstack::rename_command unrecognised leading option '[lindex $arglist 0]'. usage: rename_command ?-renamer <string>? ?-punkargs <list-of-definitionlists>? command procargs procbody"
}
}
}
foreach opt {-renamer -punkargs} {
if {$opt in $arglist} {
error "commandstack::rename_command $opt is recognised only in the leading option positions. usage: rename_command ?-renamer <string>? ?-punkargs <list-of-definitionlists>? command procargs procbody"
}
if {"-renamer" in $arglist} {
error "commandstack::rename_command -renamer is recognised only as the leading argument. usage: rename_command ?-renamer <string>? command procargs procbody"
}
if {[llength $arglist] != 3} {
error "commandstack::rename_command usage: rename_command ?-renamer <string>? command procargs procbody"
error "commandstack::rename_command usage: rename_command ?-renamer <string>? ?-punkargs <list-of-definitionlists>? command procargs procbody"
}
lassign $arglist command procargs procbody
@ -646,6 +721,12 @@ namespace eval commandstack {
}
return [dict create implementation "" did_rename 0]
}
if {[llength $punkargs_defs]} {
#additive key - appended after the leading key-order contract keys
#(token idx 0-1, renamer idx 2-3); docs attach only for a rename
#that actually lands (aborted renames returned above)
dict set new_record punkargs $punkargs_defs
}
catch {rename ::commandstack::temp::testproc ""}
set nextinit [string map [list %command% $command %renamer% $renamer %next_getter% [dict get $new_record next_getter] %original_implementation% [dict get $new_record implementation]] {
#IMPLEMENTOR_%renamer%! (mechanism: 'commandstack::rename_command -renamer %renamer% %command% <procargs> <procbody> )
@ -661,10 +742,52 @@ namespace eval commandstack {
uplevel 1 [list rename ::commandstack::temp::testproc $command]
dict lappend all_stacks $command $new_record
dict set token_implementations [dict get $nextinfo token] [dict get $nextinfo next_target]
if {[llength $punkargs_defs]} {
Stackdocs_attach $punkargs_defs
}
return $new_record
}
#G-176: doc blocks attached to stack records via 'rename_command -punkargs'.
#Attach appends each definitionlist to the commandstack::stackdocs PUNKARGS
#mirror (consumed lazily if punk::args loads later - the namespace is
#registered inert at module load) and defines immediately when punk::args
#is already present (a namespace already consumed into punk::args'
#loaded_packages never lazy-loads later appends; redefining an unchanged id
#is idempotent - a define error surfaces to the rename_command caller with
#the rename already installed, inspectable via show_stack). Detach removes
#ONE mirror occurrence per deflist and undefines via
#punk::args::undefine_deflist (deflist-keyed; silently skips never-defined
#deflists). One live record per doc id is the supported shape - two records
#declaring the same id shadow each other and removing either removes the
#doc.
proc Stackdocs_attach {deflists} {
foreach deflist $deflists {
lappend ::commandstack::stackdocs::PUNKARGS $deflist
if {[llength [info commands ::punk::args::define]]} {
punk::args::define {*}$deflist
}
}
return
}
proc Stackdocs_detach {deflists} {
variable debug
upvar 0 ::commandstack::stackdocs::PUNKARGS docmirror
foreach deflist $deflists {
set posn [lsearch -exact $docmirror $deflist]
if {$posn > -1} {
set docmirror [lreplace $docmirror $posn $posn]
}
if {[llength [info commands ::punk::args::undefine_deflist]]} {
if {[catch {punk::args::undefine_deflist $deflist} errM] && $debug} {
puts stderr "(commandstack::Stackdocs_detach) WARNING: undefine_deflist failed: $errM"
}
}
}
return
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::commandstack::next
@ -800,6 +923,12 @@ namespace eval commandstack {
set stack [lreplace $stack $doomed_posn $doomed_posn]
dict set all_stacks $command $stack
dict unset token_implementations [dict get $doomed_record token]
if {[dict exists $doomed_record punkargs]} {
#G-176: docs attached with 'rename_command -punkargs' die with
#the record. Every removal path (pop_rename/remove_renamer/
#restore_original) funnels through here.
Stackdocs_detach [dict get $doomed_record punkargs]
}
}
return $stack
@ -1258,7 +1387,7 @@ namespace eval ::punk::args::register {
}
package provide commandstack [namespace eval commandstack {
set version 0.7.1
set version 0.8.0
}]

285
src/vfs/_vfscommon.vfs/modules/punk-0.2.8.tm → src/vfs/_vfscommon.vfs/modules/punk-0.3.0.tm

@ -6403,10 +6403,10 @@ namespace eval punk {
namespace eval argdoc {
punk::args::define {
@id -id ::punk::path
@cmd -name "punk::path"\
-summary\
"Display PATH executable shadowing and conflicts with TCL commands"\
-help\
@cmd -name "punk::path" -&
-summary -&
"Display PATH executable shadowing and conflicts with TCL commands" -&
-help -&
{Introspection of the PATH environment variable.
This tool will examine executables within each PATH entry and show which binaries
are overshadowed by earlier PATH entries.
@ -6431,9 +6431,24 @@ namespace eval punk {
see also the punk::auto_exec package.
}
@opts
-pathglob -type string -default {*} -multiple true -help "Case insensitive glob pattern to filter path entries. Default '*' to include all PATH directories."
-pathglob -type string -default {*} -multiple true -help -&
"Case insensitive glob pattern to filter path entries. Default '*' to include all PATH directories."
-return -type string -default table -choices {table text dict json} -help -&
"Return form of the results. 'table' (default) is the human ANSI table.
'text' is a plain-ASCII fixed-key layout (no ANSI, no table layout) for pipes/LLMs.
'dict' returns a Tcl dict of the structured data.
'json' returns a JSON string (via tcllib json::write) of the same structure.
The text/dict/json forms contain no ANSI escapes regardless of other options."
-context -type string -default {} -help -&
"Namespace whose commands are checked for conflicts with PATH executables.
Default empty = the caller's namespace (the historical behaviour).
Naming a namespace explicitly makes the conflict verdict stable for a machine consumer invoked through a wrapper."
-conflicts -type boolean -default 1 -help -&
"Whether to compute TCL-context conflicts.
Set 0 to skip (a small perf win); the dict/json/text conflict fields are then empty."
@values -min 0 -max -1
binglob -type list -default {*} -multiple true -optional 1 -help "glob pattern to filter results. Default '*' to include all entries."
binglob -type list -default {*} -multiple true -optional 1 -help -&
"glob pattern to filter results. Default '*' to include all entries."
}
}
@ -6452,6 +6467,9 @@ namespace eval punk {
lassign [dict values $argd] leaders opts values received
set pathglobs [dict get $opts -pathglob]
set binglobs [dict get $values binglob]
set returnmode [dict get $opts -return]
set context_opt [dict get $opts -context]
set do_conflicts [dict get $opts -conflicts]
if {$is_windows} {
set sep ";"
} else {
@ -6716,6 +6734,28 @@ namespace eval punk {
# }
#}
#G-173: machine-parsable return modes (text/dict/json). The table mode below
#is byte-unchanged from the historical implementation; the structured modes
#build a parallel entry list from the same collected dicts and render without
#ANSI/textblock. Conflict verdicts use a clean exact|nocase classification
#(independent of the table render's ANSI path) and are stable for a machine
#consumer via the -context option.
if {$returnmode ne "table"} {
if {$context_opt ne ""} {
set nscaller $context_opt
if {![namespace exists $nscaller]} {
return -code error "punk::path: -context namespace '$nscaller' does not exist"
}
} else {
set nscaller [uplevel 1 {::tcl::namespace::current}]
}
set machine_args [list $returnmode $is_windows $sep]
lappend machine_args {*}[list [llength $pathglobs] $matched_paths $binglobs]
lappend machine_args {*}[list $d_path_info $d_bin_info $d_index_executables $all_paths]
lappend machine_args $nscaller $do_conflicts
return [punk::path_machine_return {*}$machine_args]
}
set nscaller [uplevel 1 {::tcl::namespace::current}]
set context_commands [namespace eval $nscaller {info commands}]
@ -6963,7 +7003,236 @@ namespace eval punk {
}
#-------------------------------------------------------------------
#G-173: structured renderers for punk::path -return text/dict/json. The
#collect phase above (d_path_info/d_bin_info/d_index_executables) is shared
#with the table render; these procs walk the same dicts into an ordered entry
#list and serialise without ANSI/textblock. Conflict verdicts use a clean
#exact|nocase classification independent of the table render's ANSI path.
#Body style: no line-continuation backslashes (src/modules/AGENTS.md); dict
#literals use the expand {dict create {*}...} form, json::write builds via
#accumulators so no single call needs continuation.
#per-executable conflict set: returns a list of {command match} pairs where
#command is the resolved (namespace origin) name and match is exact|nocase.
proc path_conflicts_for_exe {exe context_commands nscaller is_windows} {
set conflicts [list]
set probe_names [list [file rootname $exe] $exe]
foreach probe $probe_names {
if {$is_windows} {
set ncmatches [lsearch -all -inline -nocase $context_commands $probe]
} else {
set ncmatches [lsearch -all -inline -exact $context_commands $probe]
}
if {![llength $ncmatches]} { continue }
set exact [expr {$probe in $context_commands}]
foreach nc $ncmatches {
set resolved [catch {namespace eval $nscaller [list namespace origin $nc]} origin]
if {$resolved} { set origin $nc }
if {$is_windows} {
set match [expr {$exact ? "exact" : "nocase"}]
} else {
set match exact
}
lappend conflicts [list command $origin match $match]
}
break
}
return $conflicts
}
#build the ordered entry list from the collected dicts. Each entry is a dict:
# idx path normalised is_directory is_duplicate duplicate_of exe_count
# overshadowed_count executables {{name overshadowed overshadowed_by tcl_conflicts {...}} ...}
proc path_collect_entries {is_windows binglobs d_path_info d_bin_info d_index_executables all_paths nscaller do_conflicts} {
if {$do_conflicts} {
set context_commands [namespace eval $nscaller {info commands}]
} else {
set context_commands [list]
}
set entries [list]
set pidx 0
foreach p $all_paths {
if {$is_windows} {
set pnorm [string tolower $p]
} else {
set pnorm $p
}
if {[string length $pnorm] > 1} {
set lastchar [string index $pnorm end]
if {$lastchar eq "/" || $lastchar eq "\\"} {
set pnorm [string range $pnorm 0 end-1]
}
}
set pinfo [dict get $d_path_info $pnorm]
set indices [dict get $pinfo indices]
set is_duplicate [expr {[lindex $indices 0] != $pidx}]
set duplicate_of [expr {$is_duplicate ? [lindex $indices 0] : -1}]
set exe_record_list [list]
set overshadowed_count 0
if {$is_duplicate} {
#a duplicate PATH entry has no own executable list in the
#collected dicts (only the first occurrence is globbed). Mirror
#the table column: exe_count from the original, executables empty.
set original_idx [lindex $indices 0]
if {[dict exists $d_index_executables $original_idx]} {
set exe_count [llength [dict get $d_index_executables $original_idx]]
} else {
set exe_count 0
}
set executables [list]
} else {
if {[dict exists $d_index_executables $pidx]} {
set executables [dict get $d_index_executables $pidx]
} else {
set executables [list]
}
set exe_count [llength $executables]
}
foreach exe $executables {
set matched_binglob 0
if {$is_windows} {
foreach bg $binglobs {
if {[string match -nocase $bg $exe]} { set matched_binglob 1; break }
}
} else {
foreach bg $binglobs {
if {[string match $bg $exe]} { set matched_binglob 1; break }
}
}
if {!$matched_binglob} { continue }
if {$is_windows} {
set exe_key [string tolower $exe]
} else {
set exe_key $exe
}
set overshadowed 0
set overshadowed_by -1
if {[dict exists $d_bin_info $exe_key]} {
set path_indices [dict get $d_bin_info $exe_key path_indices]
foreach pi $path_indices {
if {$pi < $pidx} { set overshadowed 1; set overshadowed_by $pi; break }
}
}
if {$overshadowed} { incr overshadowed_count }
set tcl_conflicts [list]
if {$do_conflicts} {
set tcl_conflicts [path_conflicts_for_exe $exe $context_commands $nscaller $is_windows]
}
lappend exe_record_list [dict create name $exe overshadowed $overshadowed overshadowed_by $overshadowed_by tcl_conflicts $tcl_conflicts]
}
set entry [dict create idx $pidx]
dict set entry path $p
dict set entry normalised $pnorm
dict set entry is_directory [file isdirectory $p]
dict set entry is_duplicate $is_duplicate
dict set entry duplicate_of $duplicate_of
dict set entry exe_count $exe_count
dict set entry overshadowed_count $overshadowed_count
dict set entry executables $exe_record_list
lappend entries $entry
incr pidx
}
return $entries
}
proc path_machine_return {returnmode is_windows sep npathglobs matched_paths binglobs d_path_info d_bin_info d_index_executables all_paths nscaller do_conflicts} {
set entries [path_collect_entries $is_windows $binglobs $d_path_info $d_bin_info $d_index_executables $all_paths $nscaller $do_conflicts]
#filter: mirror the table render's row-visibility. With any path filter
#active, show all matching paths; otherwise show only rows with exe
#matches (unless a bare * binglob is present).
set has_star [expr {[lsearch -exact $binglobs "*"] >= 0}]
set filtered [list]
if {$npathglobs && ([llength $matched_paths] < [llength $all_paths])} {
foreach e $entries {
if {[dict get $e path] in $matched_paths} { lappend filtered $e }
}
} elseif {$has_star} {
set filtered $entries
} else {
foreach e $entries {
if {[llength [dict get $e executables]] > 0} { lappend filtered $e }
}
}
if {$returnmode eq "dict"} {
set summary [dict create context $nscaller]
dict set summary is_windows $is_windows
dict set summary separator $sep
dict set summary path_entries [llength $all_paths]
dict set summary shown_entries [llength $filtered]
dict set summary executable_total [path_count_executables $filtered]
dict set summary overshadowed_total [path_count_overshadowed $filtered]
dict set summary conflict_total [path_count_conflicts $filtered]
return [dict create summary $summary entries $filtered]
} elseif {$returnmode eq "json"} {
return [path_render_json $is_windows $sep $nscaller $all_paths $filtered]
}
return [path_render_text $is_windows $sep $nscaller $all_paths $filtered]
}
proc path_count_executables {entries} {
set n 0
foreach e $entries { incr n [llength [dict get $e executables]] }
return $n
}
proc path_count_overshadowed {entries} {
set n 0
foreach e $entries { incr n [dict get $e overshadowed_count] }
return $n
}
proc path_count_conflicts {entries} {
set n 0
foreach e $entries {
foreach exe [dict get $e executables] {
incr n [llength [dict get $exe tcl_conflicts]]
}
}
return $n
}
proc path_render_text {is_windows sep nscaller all_paths entries} {
set lines [list]
lappend lines "=== punk::path context=$nscaller is_windows=$is_windows sep=$sep"
lappend lines "summary paths=[llength $all_paths] shown=[llength $entries] executables=[path_count_executables $entries] overshadowed=[path_count_overshadowed $entries] conflicts=[path_count_conflicts $entries]"
foreach e $entries {
set dup [dict get $e is_duplicate]
set dupof [dict get $e duplicate_of]
lappend lines "--- [dict get $e idx] [dict get $e path] dir=[dict get $e is_directory] dup=$dup dupof=[expr {$dup ? $dupof : -1}] exes=[dict get $e exe_count] shadow=[dict get $e overshadowed_count]"
foreach exe [dict get $e executables] {
set cl [list]
foreach c [dict get $exe tcl_conflicts] {
lappend cl "[dict get $c command]:[dict get $c match]"
}
lappend lines " [dict get $exe name] ov=[dict get $exe overshadowed] ovby=[dict get $exe overshadowed_by] conflict=[join $cl ,]"
}
}
return [join $lines \n]
}
#JSON via tcllib json::write (G-173 preferred encoder - see goals/G-173 and
#the runtests json_emit hardening that settled the choice). Lazy-required so
#the fast -discover-only boot (which loads punk::path) is not slowed by a
#tcllib load for a mode nobody has asked for. Values are built into
#accumulator lists so each json::write call stands on one line (no
#line-continuation backslashes - src/modules/AGENTS.md).
proc path_render_json {is_windows sep nscaller all_paths entries} {
package require json::write
json::write indented 1
json::write aligned 0
set summary [json::write object context [json::write string $nscaller] is_windows [expr {$is_windows ? 1 : 0}] separator [json::write string $sep] path_entries [llength $all_paths] shown_entries [llength $entries] executable_total [path_count_executables $entries] overshadowed_total [path_count_overshadowed $entries] conflict_total [path_count_conflicts $entries]]
set entry_parts [list]
foreach e $entries {
set exe_parts [list]
foreach exe [dict get $e executables] {
set conf_parts [list]
foreach c [dict get $exe tcl_conflicts] {
lappend conf_parts [json::write object command [json::write string [dict get $c command]] match [json::write string [dict get $c match]]]
}
lappend exe_parts [json::write object name [json::write string [dict get $exe name]] overshadowed [expr {[dict get $exe overshadowed] ? 1 : 0}] overshadowed_by [dict get $exe overshadowed_by] tcl_conflicts [json::write array {*}$conf_parts]]
}
lappend entry_parts [json::write object idx [dict get $e idx] path [json::write string [dict get $e path]] normalised [json::write string [dict get $e normalised]] is_directory [expr {[dict get $e is_directory] ? 1 : 0}] is_duplicate [expr {[dict get $e is_duplicate] ? 1 : 0}] duplicate_of [dict get $e duplicate_of] exe_count [dict get $e exe_count] overshadowed_count [dict get $e overshadowed_count] executables [json::write array {*}$exe_parts]]
}
return [json::write object summary $summary entries [json::write array {*}$entry_parts]]
}
#sh 'test' equivalent - to be used with exitcode of process
#
@ -9512,7 +9781,7 @@ punkcheck::cli set_alias punkcheck
package provide punk [namespace eval punk {
#FUNCTL
variable version
set version 0.2.8
set version 0.3.0
}]

8
src/vfs/_vfscommon.vfs/modules/punk/ansi-0.2.0.tm → src/vfs/_vfscommon.vfs/modules/punk/ansi-0.2.1.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::ansi 0.2.0
# Application punk::ansi 0.2.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -16,7 +16,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::ansi 0 0.2.0]
#[manpage_begin punkshell_module_punk::ansi 0 0.2.1]
#[copyright "2023"]
#[titledesc {Ansi string functions}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk Ansi library}] [comment {-- Description at end of page heading --}]
@ -1549,7 +1549,7 @@ tcl::namespace::eval punk::ansi {
#set testparts [regexp {*}$nocase -inline -- $pattern $plain_ln] ;#get fullmatch capturegroup...
#set numgroups [expr {[llength $testparts] -1}]
#option 2: use the regexp -about flag
set numgroups [lindex [regexp -about $pattern] 0]
set numgroups [lindex [regexp -about -- $pattern] 0]
set allparts [regexp -all {*}$nocase -indices -inline -- $pattern $plain_ln]
#allparts includes each full match as well as each capturing group
#early versions of tcl 8.6 still didn't support 'lsearch -stride' - avoid for now.
@ -13730,7 +13730,7 @@ namespace eval ::punk::args::register {
## Ready
package provide punk::ansi [tcl::namespace::eval punk::ansi {
variable version
set version 0.2.0
set version 0.2.1
}]
return

808
src/vfs/_vfscommon.vfs/modules/punk/args-0.18.0.tm → src/vfs/_vfscommon.vfs/modules/punk/args-0.25.2.tm

File diff suppressed because it is too large Load Diff

15
src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/punkboot-0.3.1.tm → src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/punkboot-0.3.2.tm

@ -6,7 +6,7 @@
# (C) 2026
#
# @@ Meta Begin
# Application punk::args::moduledoc::punkboot 0.3.1
# Application punk::args::moduledoc::punkboot 0.3.2
# Meta platform tcl
# Meta license BSD
# @@ Meta End
@ -122,6 +122,17 @@ tcl::namespace::eval punk::args::moduledoc::punkboot {
arguments - help flags included, 2026-08-05
single-mechanism revision - so an app may do its
own -help handling regardless.)
A multi-form definition may carry its own
'@cmd -formhint' template of the shape
' <punkexe> help <name> %formname%' (G-170): the
launcher narrows 'help <name> <formword>' (exact
form name, or decimal ordinal) to that form's
usage, so the hinted line names real navigation.
Author it with NO trailing ellipsis (display-hint
honesty): words after the form word are not a
continuation of the narrowed render - on a
parse=1 registration they dry-run through argsid
instead.
package package to require (guarded) before resolving
argsid - typically a moduledoc-style package
carrying the definition, or an app-owned docs
@ -260,6 +271,6 @@ namespace eval ::punk::args::register {
## Ready
package provide punk::args::moduledoc::punkboot [tcl::namespace::eval punk::args::moduledoc::punkboot {
variable version
set version 0.3.1
set version 0.3.2
}]
return

39
src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/tclcore-0.4.0.tm → src/vfs/_vfscommon.vfs/modules/punk/args/moduledoc/tclcore-0.4.2.tm

@ -8,7 +8,7 @@
# (C) 2025
#
# @@ Meta Begin
# Application punk::args::moduledoc::tclcore 0.4.0
# Application punk::args::moduledoc::tclcore 0.4.2
# Meta platform tcl
# Meta license MIT
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::args::moduledoc::tclcore 0 0.4.0]
#[manpage_begin punkshell_module_punk::args::moduledoc::tclcore 0 0.4.2]
#[copyright "2025"]
#[titledesc {punk::args definitions for tcl core commands}] [comment {-- Name section and table of contents description --}]
#[moddesc {tcl core argument definitions}] [comment {-- Description at end of page heading --}]
@ -4408,7 +4408,7 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
# ---------------------------------------------------------------------------------------------------------------------------
proc tclprefix_subcommands {} {
dict set groups "" {all longest match}
return [punk::args::ensemble_subcommands_definition -groupdict $groups -columns 1 tcl::prefix]
return [punk::args::ensemble_subcommands_definition -groupdict $groups -columns 1 ::tcl::prefix]
}
set DYN_TCLPREFIX_SUBCOMMANDS {${[punk::args::moduledoc::tclcore::argdoc::tclprefix_subcommands]}}
lappend PUNKARGS [list {
@ -7506,10 +7506,7 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
"This command searches the elements of list to see if one of them matches pattern. If so, the command returns
the index of the first matching element (unless the options -all or -inline are specified.) If not, the command
returns -1 or (if options -all or -inline are specified) the empty string. The option arguments indicates how
the elements of the list are to be matched against pattern.
(documentation incomplete - punk::args fixes required for grouped mutually exlusive options and prefix calculation)
"
the elements of the list are to be matched against pattern. "
@leaders -min 0 -max 0
@opts -type none -parsekey "-MATCHSTYLE" -group "MATCHING STYLE OPTIONS" -grouphelp\
"If all matching style options are omitted, the default matching style is -glob.
@ -7524,13 +7521,15 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
-regexp -typedefaults "-regexp" -help\
"Pattern is treated as a regular expression and matched against each list element using the
rules described in the re_syntax reference page."
-sorted -typedefaults "-sorted" -help\
-sorted -typedefaults "-sorted" -conflicts {-glob -regexp} -help\
"The list elements are in sorted order. If this option is specified, lsearch will use a more
efficient searching algorithm to search list. If no other options are specified, list is
assumed to be sorted in increasing order, and to contain ASCII strings. This option is
mutually exclusive with -glob and -regexp, and is treated exactly like -exact when either
-all or -not are specified."
#G-083: -sorted mutually exclusive with -glob and -regexp (per the man page) -
#modelled with per-arg -conflicts while keeping the MATCHING STYLE OPTIONS group at
#the default override mode (last-wins among -exact/-glob/-regexp).
@opts -type string -parsekey "" -group "GENERAL MODIFIER OPTIONS"
-all -type none -help\
@ -7570,7 +7569,7 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
"The list elements are sorted in decreasing order. This option is only meaningful when used with -sorted."
-increasing -typedefaults "-increasing" -default "-increasing" -help\
"The list elements are sorted in increasing order. This option is only meaningful when used with -sorted."
-bisect -typedefaults "-bisect" -help\
-bisect -typedefaults "-bisect" -conflicts {-all -not} -help\
"Inexact search when the list elements are in sorted order. For an increasing list the last index where
the element is less than or equal to the pattern is returned. For a decreasing list the last index where
the element is greater than or equal to the pattern is returned. If the pattern is before the first
@ -10074,7 +10073,19 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
#set string_class_choices [dict get [lrange [punk::args::resolved_def -types leaders ::tcl::string::is class] 1 end] -choices]
set string_class_choicelabels [dict get [lrange [punk::args::resolved_def -types leaders ::tcl::string::is class] 1 end] -choicelabels]
dict for {sclass slabel} $string_class_choicelabels {
punk::args::define [string map [list %sc% $sclass %slabel% $slabel] {
#G-166: the virtual ids for forward classes THIS runtime lacks lead their help
#with the unavailability statement. The static class description already carries
#a version annotation, but it sits at the END of the prose (dict's "(class not
#present in Tcl 8.6)" is the twelfth line) - a reader of 'i string is dict' on 8.6
#met the full class documentation before learning the class does not exist here.
#Runtimes that HAVE the class generate the id unchanged (the loop's condition is
#empty there, since string_is_unavailable is computed per-runtime above).
if {$sclass in $string_is_unavailable} {
set sclass_help " NOT AVAILABLE in this Tcl\n runtime ([info patchlevel]).\n Recognised forward class:\n the name is known and its\n prefix reserved here, but\n 'string is $sclass' is\n rejected by this\n interpreter.\n\n$slabel"
} else {
set sclass_help $slabel
}
punk::args::define [string map [list %sc% $sclass %slabel% $sclass_help] {
@id -id "::tcl::string::is %sc%"
@cmd -name "Built-in: string is %sc%" -help\
{%slabel%}
@ -11017,7 +11028,9 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
#@form -form "setvalues" -synopsis "variable ?name value...? ?name?"
@form -form "setvalues"
@values -min 0 -max -1
#todo - fix -parsekey for leaders and values
#G-084 (2026-08-07): value -parsekey now supported (name value pairs
#collect under the parsekey name_value). A leader -parsekey is settled as
#a define-time rejection (no silent ignore).
"name value" -parsekey name_value -type {string any} -optional 1 -multiple 1
name -type string -optional 1 -multiple 0
@ -12610,7 +12623,7 @@ namespace eval ::punk::args::register {
package provide punk::args::moduledoc::tclcore [tcl::namespace::eval punk::args::moduledoc::tclcore {
variable pkg punk::args::moduledoc::tclcore
variable version
set version 0.4.0
set version 0.4.2
}]
return

132
src/vfs/_vfscommon.vfs/modules/punk/libunknown-0.2.4.tm → src/vfs/_vfscommon.vfs/modules/punk/libunknown-0.3.1.tm

@ -7,7 +7,7 @@
# (C) 2025
#
# @@ Meta Begin
# Application punk::libunknown 0.2.4
# Application punk::libunknown 0.3.1
# Meta platform tcl
# Meta license MIT
# @@ Meta End
@ -18,6 +18,33 @@
# from src/modules/AGENTS.md "Versioning And Releases" - bumping means
# renaming the file AND updating the Meta line above, the manpage_begin line
# below and the provide-block version, then appending a line here):
#0.3.1 - G-176 increment 4: the 'package epoch' subcommand is now DOCUMENTED -
# a punk::args doc block with the space-form id {::package epoch} is
# attached to the override's commandstack record via the new
# 'rename_command -punkargs' mechanism (commandstack 0.8.0). The doc
# lives and dies with the override: mirrored for lazy pickup when
# punk::args loads after init (normal early boot), defined immediately
# when punk::args is already present, and removed by any commandstack
# removal path (e.g restore_original ::package). 'i package epoch' in a
# punk shell now renders real usage instead of falling back to the
# parent ::package render.
#0.3.0 - G-176 increment 2: the ::package override installs via
# commandstack::rename_command (renamer punk::libunknown) instead of the
# former 'rename ::package ::package::' + namespace-import mechanism, so
# both live ::package overrides (this + punk::packagepreference's) share
# one managed stack whatever the install order. init now does
# 'package require commandstack' (a no-op where commandstack is already
# provided, e.g whenever punk::packagepreference::install ran first) and
# re-entry is guarded by a stack query for our renamer record instead of
# the old ::punk::libunknown::package proc-existence check. The override
# body runs at :: (namespace-relative epoch_incr_* calls fully
# qualified; the dead 'variable has_package_files' declaration dropped -
# its only use was already commented out) and delegates via
# COMMANDSTACKNEXT (no ::package:: parking name; nothing in the tree
# called it). Behaviour of every arm is unchanged - pinned by
# tests/modules/punk/libunknown testsuites/discovery/packageoverride.test
# (the increment-1 characterisation; only its marked install-shape pins
# flipped with this change).
#0.2.4 - register_all_tm: skip the G-155 workdirs _mint and _bake alongside
# legacy _build, in both the filesystem directory walk and the tm-file
# filter (the latter also guards the zipfs whole-tree listing) - loose
@ -71,7 +98,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::libunknown 0 0.2.4]
#[manpage_begin punkshell_module_punk::libunknown 0 0.3.1]
#[copyright "2025"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
@ -1509,10 +1536,12 @@ tcl::namespace::eval ::punk::libunknown {
-summary\
"Install punk::libunknown's custom package unknown handlers and epoch system in the current interp."\
-help\
"Renames the builtin ::package to ::package:: and installs a custom ::package proc
that intercepts 'forget' (controlled forgetting) and adds an 'epoch' subcommand
(for introspection). Sets package unknown to a two-handler chain:
zipfs_tm_UnknownHandler (tm paths) and zipfs_tclPkgUnknown (auto_path/pkgIndex).
"Installs a ::package override via commandstack::rename_command (renamer
punk::libunknown) that intercepts 'forget' (controlled forgetting) and adds an
'epoch' subcommand (for introspection); all other subcommands delegate to the
previous implementation on the commandstack. Sets package unknown to a
two-handler chain: zipfs_tm_UnknownHandler (tm paths) and zipfs_tclPkgUnknown
(auto_path/pkgIndex).
Installs traces on ::auto_path and ::tcl::tm::paths that increment the epoch
when these change, invalidating stale scan cache entries.
@ -1571,14 +1600,22 @@ tcl::namespace::eval ::punk::libunknown {
puts stderr "punk::libunknown::init - init while empty/unreadable tcl::tm::list and empty/unreadable ::auto_path"
}
if {[info commands ::punk::libunknown::package] ne ""} {
#commandstack is the install mechanism for the ::package override (G-176).
#A no-op when already provided (e.g whenever punk::packagepreference::install
#ran first, or a boot context pre-sourced it); otherwise resolves via the
#standard package machinery - commandstack is lean and dependency-free.
#0.8- floor: rename_command -punkargs (the attached 'package epoch' doc)
#arrived at commandstack 0.8.0 - an older stable copy must fail HERE with a
#version message, not mid-call with a usage error (with the default stable
#preference an old stable copy would otherwise beat an alpha dev copy).
package require commandstack 0.8-
#re-entry guard: our override record on the ::package commandstack
foreach stackrecord [commandstack::get_stack ::package] {
if {[dict get $stackrecord renamer] eq "punk::libunknown"} {
puts stderr "punk::libunknown::init already done - unnecessary call? info frame -1: [info frame -1]"
return
}
#if {[namespace origin ::package] eq "::punk::libunknown::package"} {
# #This is far from conclusive - there may be other renamers (e.g commandstack)
# return
#}
}
@ -1686,13 +1723,57 @@ tcl::namespace::eval ::punk::libunknown {
trace add variable ::auto_path write ::punk::libunknown::epoch_incr_pkg
trace add variable ::tcl::tm::paths write ::punk::libunknown::epoch_incr_tm
#set stackrecord [commandstack::rename_command -renamer punk::libunknown package {args} {
# #::package override installed by punk::libunknown::init
#}
proc package args {
#::package override - installed via commandstack (G-176) so both live
#::package overrides (this + punk::packagepreference's) share one managed
#stack whatever the install order. The body runs at :: - namespace-relative
#references must be fully qualified.
#The added 'epoch' subcommand's documentation travels WITH the override:
#attached to the stack record via -punkargs, live while the record is on
#the stack, removed with it by any commandstack removal path. The deflist
#stays free of dollar-brace tstr substitutions - when punk::args loads
#after us (normal early boot) it is lazily evaluated in the registered
#::commandstack::stackdocs namespace, not in ours.
set epochdoc {@id -id {::package epoch}
@cmd -name "punk::libunknown override: package epoch"\
-summary\
"package/module discovery epoch introspection."\
-help\
"Introspect (or manually advance) the punk::libunknown discovery epoch
counters that key the package/module scan caches. Added by the
::package override that punk::libunknown::init installs - this
subcommand (and this documentation) is present only while that
override is live.
Forms:
package epoch - dict {tm <int> pkg <int>} - the current
epoch counters
package epoch tm|pkg - one-entry dict keyed by the current
epoch: {<epoch> <epochinfo>}
package epoch incr - increment BOTH the tm and pkg epochs,
invalidating the scan caches (e.g after
adding a .tm file to an already-scanned
directory)
package epoch tm|pkg incr - increment one epoch (also accepted as:
package epoch incr tm|pkg)
package epoch tm|pkg <idx> - the epochinfo record for epoch <idx>
(error for an unknown <idx>)
package epoch tm|pkg <idx> <key>...
- walk keys into that epochinfo record
(an unknown key errors naming the
available toplevel keys)
The epochs also advance automatically via traces on ::auto_path and
::tcl::tm::paths."
@values -min 0 -max -1
which -type string -optional 1 -choices {tm pkg incr} -choicerestricted 0 -help\
"epoch selector (tm or pkg), or incr to advance both epochs."
arg -type any -optional 1 -multiple 1 -help\
"index (or incr) and optional key path - see the forms above."
}
set stackrecord [commandstack::rename_command -renamer punk::libunknown -punkargs [list [list $epochdoc]] package {args} {
#::package override installed by punk::libunknown::init (epoch/forget arms; all else delegates)
switch -- [lindex $args 0] {
fo - for - forge - forget {
variable has_package_files
#experimental - silently disallow forgetting things that didn't involve sourcing files
#What about static libs that also sourced files?
#packages loaded by c extensions?
@ -1731,7 +1812,7 @@ tcl::namespace::eval ::punk::libunknown {
}
}
if {[llength $ok_forgets]} {
return [uplevel 1 [list ::package:: forget {*}$ok_forgets]]
return [uplevel 1 [list $COMMANDSTACKNEXT forget {*}$ok_forgets]]
} else {
return
}
@ -1756,8 +1837,8 @@ tcl::namespace::eval ::punk::libunknown {
return [dict create $cur [dict get $epoch pkg epochs $cur]]
}
incr {
epoch_incr_pkg
epoch_incr_tm
::punk::libunknown::epoch_incr_pkg
::punk::libunknown::epoch_incr_tm
}
default {
error "package epoch [lindex $epoch_args 0] unsupported - known options: tm pkg incr"
@ -1768,10 +1849,10 @@ tcl::namespace::eval ::punk::libunknown {
set a2 [list [lindex $epoch_args 0] [lindex $epoch_args 1]]
switch -- $a2 {
{pkg incr} - {incr pkg} {
epoch_incr_pkg
::punk::libunknown::epoch_incr_pkg
}
{tm incr} - {incr tm} {
epoch_incr_tm
::punk::libunknown::epoch_incr_tm
}
default {
set which [lindex $epoch_args 0]
@ -1813,13 +1894,10 @@ tcl::namespace::eval ::punk::libunknown {
}
}
default {
return [uplevel 1 [list ::package:: {*}$args]]
return [uplevel 1 [list $COMMANDSTACKNEXT {*}$args]]
}
}
}
rename ::package ::package::
#all lowercase procs already exported from ::punk::libunknown
namespace eval :: [list ::namespace import ::punk::libunknown::package]
}]
#if {[info commands ::tcl::zipfs::root] ne ""} {
# set has_zipfs_tm 0
@ -2183,7 +2261,7 @@ namespace eval ::punk::args::register {
package provide punk::libunknown [tcl::namespace::eval ::punk::libunknown {
variable pkg punk::libunknown
variable version
set version 0.2.4
set version 0.3.1
}]
return

BIN
src/vfs/_vfscommon.vfs/modules/punk/mix/templates-0.2.0.tm

Binary file not shown.

294
src/vfs/_vfscommon.vfs/modules/punk/ns-0.9.3.tm → src/vfs/_vfscommon.vfs/modules/punk/ns-0.11.0.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::ns 0.9.3
# Application punk::ns 0.11.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -4652,7 +4652,35 @@ y" {return quirkykeyscript}
-summary\
"Subcommand resolution of ensemble-like tree of commands."\
-help\
"Return a dict with command resolution info for ensemble-like tree of commands with subcommands"
"Return a dict with command resolution info for ensemble-like tree of commands with subcommands
Result keys:
origin - the resolved command (or the docid path for a
documentation-only landing)
cmdtype - what KIND of executable thing resolution landed on
(proc, native, alias, ensemble, doconly, notfound...)
unavailable - (G-166) empty string, or the canonical
-choiceunavailable name the resolution addressed.
A SEPARATE axis from cmdtype: it describes the
resolved word's availability in this
runtime/context, not the kind of thing found.
Non-empty means the landing is documentation the
current runtime cannot actually run - e.g
'string is dict' on Tcl 8.6.
overridden - (G-176) empty list, or one entry per LIVE
commandstack rename record on the BASE command
(bottom-up): a dict {renamer <string> docids
<list>} where docids are the punk::args ids of
any doc blocks the record attached via
'rename_command -punkargs'. A second axis like
'unavailable': it describes the live override
state of the command, not the kind of thing
resolution landed on. Always empty when the
commandstack package is not loaded.
args_resolved - the command words consumed by resolution
args_remaining- the trailing words resolution did not consume
docid - the punk::args definition id documenting the landing
stack - per-level record of the traversal"
@leaders -min 0 -max 0
@opts
-form -default * -help\
@ -4683,8 +4711,9 @@ y" {return quirkykeyscript}
set commands [list]
set consumed_args [list]
set docid ""
set unavailable "" ;#G-166: availability attribution of the FINAL landing (each record overwrites)
while {$final == 0} {
lassign [$reduce $origin] final origin consumed remainingargs docid
lassign [$reduce $origin] final origin consumed remainingargs docid unavailable
#if {$final != 1} {
if {[string match (autodef)* $origin]} {
set origin [string range $origin 9 end]
@ -4715,8 +4744,50 @@ y" {return quirkykeyscript}
#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]
#G-166: 'unavailable' is deliberately a SECOND axis beside cmdtype - cmdtype
#answers what kind of executable thing resolution landed on, availability
#answers whether the resolved word is selectable in this runtime/context.
#Overloading cmdtype (e.g a 'doconly_unavailable' value) would break every
#consumer switching on cmdtype eq "doconly", and the two only co-occur
#incidentally (an unavailable name has no real command behind it today).
#G-176: 'overridden' is a further second-axis key - the live commandstack
#override state of the BASE command word, queried at call time (never
#cached) so it is correct by construction as stacks change.
return [list origin $origin cmdtype $cmdtype unavailable $unavailable overridden [_cmdinfo_overridden [lindex $commands 0]] args_resolved [list [lindex $commands 0] {*}$consumed_args] args_remaining $remainingargs docid $docid stack $stack]
}
#G-176: live commandstack override records for a command - one dict
#{renamer <string> docids <list>} per record, bottom-up. docids are the
#punk::args ids of doc blocks the record attached via 'rename_command
#-punkargs' (derived with punk::args::rawdef_id - deflists whose id cannot
#be derived are simply not listed). Guarded: empty list when the
#commandstack package is not loaded - no hard dependency.
proc _cmdinfo_overridden {command} {
if {![llength [info commands ::commandstack::get_stack]]} {
return [list]
}
if {[catch {commandstack::get_stack $command} stackrecords]} {
return [list]
}
set overridden [list]
foreach crec $stackrecords {
if {![dict exists $crec renamer]} {continue}
set docids [list]
if {[dict exists $crec punkargs] && [llength [info commands ::punk::args::rawdef_id]]} {
foreach deflist [dict get $crec punkargs] {
if {![catch {punk::args::rawdef_id $deflist} rawid] && $rawid ne ""} {
lappend docids $rawid
}
}
}
lappend overridden [dict create renamer [dict get $crec renamer] docids $docids]
}
return $overridden
}
#Each record yielded/returned by cmd_traverse is:
# [list <code> <origin> <resolvedargs> <remainingargs> <docid> <unavailable>]
#<unavailable> (G-166) is the canonical -choiceunavailable name this level's
#resolution addressed, or empty. cmdinfo keeps the FINAL record's value - the
#availability of the landing it reports.
proc cmd_traverse {ns formid args} {
set autodefined [dict create]
#puts "cmd_traverse args: $args yielding: [info coroutine]"
@ -4746,7 +4817,7 @@ y" {return quirkykeyscript}
set origin $which ;#Flip our traversal to be on the documented 'which' rather than the actual origin
if {$whichtype eq "alias"} {
#*documented* alias
return [list 1 $origin {} [lrange $args 1 end] $docid]
return [list 1 $origin {} [lrange $args 1 end] $docid {}]
}
}
}
@ -4773,10 +4844,10 @@ y" {return quirkykeyscript}
#} else {
if {$docid ne "" && ![llength [lrange $args 1 end]]} {
return [list 0a $origin {} {} $docid]
return [list 0a $origin {} {} $docid {}]
}
set origin [yield [list 0 $origin {} [lrange $args 1 end] $docid]]
set origin [yield [list 0 $origin {} [lrange $args 1 end] $docid {}]]
set whichinfo [namespace eval $ns [list punk::ns::cmdwhich $cmd]]
set origin [dict get $whichinfo origin]
set origintype [dict get $whichinfo origintype]
@ -4867,7 +4938,7 @@ y" {return quirkykeyscript}
}
#}
if {[llength $args] == 1} {
return [list 2 $origin $resolvedargs {} $docid]
return [list 2 $origin $resolvedargs {} $docid {}]
}
set terminate 0
for {set i 1} {$i < [llength $args]} {incr i} {
@ -4894,19 +4965,18 @@ y" {return quirkykeyscript}
set docid_exists 0
set eparams [list]
set a_spaceform ""
if {[punk::args::id_exists "$origin [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 a_unavailable "" ;#G-166 availability attribution for this level's landing
set a_word [lindex $args $i]
#G-051 space-form docid prefix parity / G-166 availability attribution:
#resolve the word against the current level's choices-bearing first leader
#with the same shared resolver argument parsing uses
#(punk::args::choiceword_match - honouring -choiceprefix, -nocase,
#-choicealiases, -choiceprefixdenylist, -choiceprefixreservelist and
#-choiceunavailable). Computed once here because BOTH the exact-word
#space-form landing and the prefix retry consult it: the exact landing only
#for the availability verdict, the prefix retry for the canonical word too.
set lvl_matchinfo ""
if {$docid ne "" && [punk::args::id_exists $docid]} {
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]
@ -4917,7 +4987,7 @@ y" {return quirkykeyscript}
lappend pf_allchoices {*}$pf_members
}
if {[llength $pf_allchoices]} {
set pf_matchinfo [punk::args::choiceword_match [lindex $args $i]\
set lvl_matchinfo [punk::args::choiceword_match $a_word\
[punk::args::system::Dict_getdef $pf_arginfo -nocase 0]\
$pf_allchoices\
[punk::args::system::Dict_getdef $pf_arginfo -choicealiases {}]\
@ -4926,13 +4996,44 @@ y" {return quirkykeyscript}
[punk::args::system::Dict_getdef $pf_arginfo -choiceprefixreservelist {}]\
[punk::args::system::Dict_getdef $pf_arginfo -choiceunavailable {}]\
]
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 {[punk::args::id_exists "$origin $a_word"]} {
set a_spaceform $a_word
#G-166: the exact word may address a recognised-but-unavailable name.
#Its virtual docid exists by G-073 design (documentation REACHABILITY
#for unavailable words), so resolution succeeds - but the landing is
#attributed so consumers can tell it from a usable one.
if {$lvl_matchinfo ne "" && [dict get $lvl_matchinfo unavailable]} {
set a_unavailable [dict get $lvl_matchinfo canonical]
}
} elseif {$lvl_matchinfo ne "" && [dict get $lvl_matchinfo matched]} {
#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_canonical [dict get $lvl_matchinfo canonical]
if {$pf_canonical ne $a_word && [punk::args::id_exists "$origin $pf_canonical"]} {
set a_spaceform $pf_canonical
}
} elseif {$lvl_matchinfo ne "" && [dict get $lvl_matchinfo unavailable]} {
#G-166 DECISION (enacting the G-073 follow-on): a unique prefix landing
#on an unavailable name resolves that name's virtual docid, marked -
#it no longer conservatively resolves nothing. Rationale: documentation
#ADDRESSING and word AVAILABILITY are separate axes (the whole point of
#the attribution added here). Encoding availability as
#resolve-vs-don't-resolve conflated them and made addressing
#inconsistent - 'string is tr' resolved but 'string is dic' did not,
#while exact 'string is true' and 'string is dict' both did. Now every
#form of address that names a documented word resolves it, and the
#availability key (plus cmdhelp's marking) carries the rejection story
#that parse reports for the same word.
set pf_canonical [dict get $lvl_matchinfo canonical]
if {[punk::args::id_exists "$origin $pf_canonical"]} {
set a_spaceform $pf_canonical
set a_unavailable $pf_canonical
}
}
if {$a_spaceform ne ""} {
@ -4966,7 +5067,7 @@ y" {return quirkykeyscript}
#review - get_spec needs to resolve if @dynamic
#we don't really need the spec if we have no queryargs
if {![llength $queryargs]} {
return [list X $origin $resolvedargs $queryargs_untested $docid]
return [list X $origin $resolvedargs $queryargs_untested $docid $a_unavailable]
}
@ -5063,7 +5164,7 @@ y" {return quirkykeyscript}
#ledit queryargs_untested 0 0
#jjj
#continue
return [list 3 $origin $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid]
return [list 3 $origin $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid $a_unavailable]
break
}
#G-040: resolve the subcommand word with the same shared resolver argument
@ -5078,9 +5179,10 @@ y" {return quirkykeyscript}
#doc-only ids without implying the word parses - that is how per-class ids
#like 'string is true' have always documented argument words, and how an
#UNAVAILABLE word's virtual id ('string is dict' on 8.6) documents since
#G-073. Consequence: cmdinfo classes both landings 'doconly' with no
#availability distinction - surfacing that (cmdinfo axis / render marking)
#is deliberately not decided here.
#G-073. G-166 settled the surfacing: the addressing branches above resolve
#such landings and cmdinfo reports them on its own 'unavailable' axis,
#while THIS traverse keeps its parity claim intact - an unavailable word
#still identifies no subcommand here, it is only attributed below.
set ct_matchinfo [punk::args::choiceword_match $q\
[punk::args::system::Dict_getdef $arginfo -nocase 0]\
$allchoices\
@ -5093,7 +5195,14 @@ y" {return quirkykeyscript}
if {![dict get $ct_matchinfo matched]} {
#no match under parse rules (covers: unknown word, ambiguous prefix,
#reserved word, denied prefix, and non-exact word when -choiceprefix 0)
return [list 4 $origin $resolvedargs $queryargs_untested $docid]
#G-166: a landing on a recognised-but-unavailable name is still not a
#subcommand match, but it IS attributed - this is the path taken when
#the unavailable name has no space-form virtual docid to address.
set ct_unavailable ""
if {[dict get $ct_matchinfo unavailable]} {
set ct_unavailable [dict get $ct_matchinfo canonical]
}
return [list 4 $origin $resolvedargs $queryargs_untested $docid $ct_unavailable]
break
}
set resolved_q [dict get $ct_matchinfo canonical]
@ -5191,10 +5300,10 @@ y" {return quirkykeyscript}
#punk::args::update_definitions [list [namespace qualifiers $mapped_subcmd]]
if {[llength $queryargs_untested] == 0} {
return [list 6 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid]
return [list 6 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid {}]
}
set origin [yield [list 0 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid]]
set origin [yield [list 0 $mapped_subcmd $resolvedargs [list {*}$eparams {*}$queryargs_untested] $docid {}]]
#set resolvedargs [list]
#incr i [expr {-1 * [llength $resolvedargs]+1}] ;#wrong e.g test trace add execution blah enterstep cmd
@ -5223,22 +5332,22 @@ y" {return quirkykeyscript}
break ;#out of foreach q $queryargs ...
} else {
#test with: i namespace which -v x
return [list 7 $origin $resolvedargs $queryargs_untested $prevdocid]
return [list 7 $origin $resolvedargs $queryargs_untested $prevdocid {}]
}
} ;#end loop foreach q $queryargs lname $leadernames_matched
} else {
#??
#puts stderr "cmdinfo.cmd_traverse returning 8 origin: $origin resolved: $resolvedargs remaining: [lrange $args $i end] docid: $docid"
return [list 8 $origin $resolvedargs [lrange $args $i end] $docid]
return [list 8 $origin $resolvedargs [lrange $args $i end] $docid $a_unavailable]
}
} else {
#puts stderr "origin $origin not documented"
return [list 9 $origin {} [lrange $args $i end] ""]
return [list 9 $origin {} [lrange $args $i end] "" {}]
}
}
#REVIEW!!!
#puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
return [list 10 $origin $resolvedargs $queryargs_untested $docid]
return [list 10 $origin $resolvedargs $queryargs_untested $docid $a_unavailable]
}
@ -5494,12 +5603,18 @@ y" {return quirkykeyscript}
} -help\
"Return form of the usage information.
'dict' returns a dict with keys origin, docid, cmdtype,
args_remaining and parsestatus - where parsestatus is the
parse-status structure of the supplied argument words against
the resolved definition (see punk::args::parse_status for the
documented structure; empty if the command is undocumented).
unavailable, args_remaining and parsestatus - where parsestatus
is the parse-status structure of the supplied argument words
against the resolved definition (see punk::args::parse_status for
the documented structure; empty if the command is undocumented).
Its per-argument statuses distinguish a fully-valid, an invalid
and an incomplete argument set machine-parsably.
'unavailable' (G-166) is empty, or the canonical
-choiceunavailable name the resolution addressed - a subject the
current runtime/context documents but cannot run (e.g
'string is dict' on Tcl 8.6). The other return forms carry the
same fact as a visible marking, and never present such a subject
as a cleanly usable command line.
'text' returns plain text with no ANSI codes and no table
layout, rendering the argument section of every command form
(or of each form in an explicit -form selection) in a single
@ -5542,6 +5657,35 @@ y" {return quirkykeyscript}
form (no words, an ambiguous match, or words no form
accepts) keep the whole-command render."
}
#G-166: the single wording for cmdhelp's recognised-but-unavailable marking, shared
#by the table and text return forms so every surface says the same thing. Vocabulary
#deliberately mirrors punk::args' tailored parse rejection
#(private::unavailable_choice_msg, G-073) - a user who meets both reads one story.
#The runtime-specific WHY is not repeated here: it belongs to the definition, and the
#unavailable subject's own help leads with it (the tclcore virtual ids do since G-166).
proc _cmdhelp_unavailable_marking {name} {
#(wording stays position-neutral: the table/string renderers place the message
#below the usage, the text form leads with it)
return "'$name' is a recognised name here, but is not available in this runtime/context - this command line is not usable here and the usage shown is reference documentation only."
}
#G-176: one-line override-in-place notice from cmdinfo's 'overridden' axis.
#basecmd is the command the records belong to (the cmdhelp subject);
#overridden is the list of {renamer .. docids ..} dicts (bottom-up). Returns
#the bare notice - the table render prefixes 'note: ', -return text prefixes
#'OVERRIDDEN: ' (its machine-facing leading-line convention).
proc _cmdhelp_override_notice {basecmd overridden} {
set renamers [list]
set docids [list]
foreach rec $overridden {
lappend renamers [dict get $rec renamer]
lappend docids {*}[dict get $rec docids]
}
set notice "'$basecmd' is currently overridden/extended via commandstack by: [join $renamers {, }]"
if {[llength $docids]} {
append notice " (override-attached docs: '[join $docids {', '}]')"
}
return $notice
}
proc cmdhelp {args} {
set nscaller [uplevel 1 [list ::tcl::namespace::current]]
lassign [dict values [punk::args::parse $args -cache 1 withid ::punk::ns::cmdhelp]] leaders opts values received
@ -5589,9 +5733,15 @@ y" {return quirkykeyscript}
#string renderer and the sections are joined below the common header.
set dinfo [uplevel 1 [list ::punk::ns::cmdhelp -return dict -form $opt_form -- $querycommand {*}$queryargs]]
set docid [dict get $dinfo docid]
set text_overridden [punk::args::system::Dict_getdef $dinfo overridden {}] ;#G-176
if {$docid eq ""} {
return "Undocumented command [dict get $dinfo origin]. Type: [dict get $dinfo cmdtype]"
set undoc "Undocumented command [dict get $dinfo origin]. Type: [dict get $dinfo cmdtype]"
if {[llength $text_overridden]} {
set undoc "OVERRIDDEN: [_cmdhelp_override_notice $querycommand $text_overridden]\n$undoc"
}
return $undoc
}
set unavail [dict get $dinfo unavailable] ;#G-166 (the dict form always carries it)
set spec [punk::args::get_spec $docid]
set pstatus [dict get $dinfo parsestatus]
if {$opt_form ne "*"} {
@ -5632,6 +5782,16 @@ y" {return quirkykeyscript}
}
set result [string trimright $result \n]
}
if {[llength $text_overridden]} {
#G-176: override-in-place leading line for the machine/LLM-facing
#surface (sits below UNAVAILABLE when both apply)
set result "OVERRIDDEN: [_cmdhelp_override_notice $querycommand $text_overridden]\n$result"
}
if {$unavail ne ""} {
#G-166: mark the plain-text form too - it is the machine/LLM-facing
#surface, so the marking leads rather than trailing the usage block.
set result "UNAVAILABLE: [_cmdhelp_unavailable_marking $unavail]\n$result"
}
if {$opt_grepstr ne ""} {
if {[llength $opt_grepstr] == 1} {
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
@ -5682,13 +5842,19 @@ y" {return quirkykeyscript}
} else {
dict set nextopts -form [dict get $pstatus form]
}
set alias_overridden [punk::args::system::Dict_getdef $testinfo overridden {}] ;#G-176
if {$opt_return eq "dict"} {
if {$scheme_received} {
dict set pstatus scheme [dict get $opts -scheme]
}
return [dict create origin $rootorigin docid $rootdoc cmdtype $rootorigintype args_remaining $queryargs parsestatus $pstatus]
return [dict create origin $rootorigin docid $rootdoc cmdtype $rootorigintype unavailable [dict get $testinfo unavailable] overridden $alias_overridden args_remaining $queryargs parsestatus $pstatus]
}
if {[dict get $pstatus ok]} {
#G-166: an unavailable subject never renders as a cleanly usable
#command line - see the matching site in the main cmdhelp body.
set unavail [dict get $testinfo unavailable]
if {$unavail ne ""} {
set result [punk::args::arg_error [_cmdhelp_unavailable_marking $unavail] [punk::args::get_spec $rootdoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
} elseif {[dict get $pstatus ok]} {
#show usage - with goodargs marked
if {!$scheme_received} {
dict set nextopts -scheme info
@ -5697,6 +5863,10 @@ y" {return quirkykeyscript}
} else {
set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $rootdoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
}
if {[llength $alias_overridden]} {
#G-176: override-in-place notice leads the render
set result "note: [_cmdhelp_override_notice $querycommand $alias_overridden]\n$result"
}
if {$opt_grepstr ne ""} {
if {[llength $opt_grepstr] == 1} {
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
@ -5753,6 +5923,8 @@ y" {return quirkykeyscript}
set origindoc [dict get $cinfo docid]
set args_remaining [dict get $cinfo args_remaining]
set origintype [dict get $cinfo cmdtype]
set unavail [dict get $cinfo unavailable] ;#G-166
set overridden [punk::args::system::Dict_getdef $cinfo overridden {}] ;#G-176
switch -- $origintype {
script {
@ -5800,9 +5972,21 @@ y" {return quirkykeyscript}
if {$scheme_received} {
dict set pstatus scheme [dict get $opts -scheme]
}
return [dict create origin $origin docid $origindoc cmdtype $origintype args_remaining $args_remaining parsestatus $pstatus]
}
if {[dict get $pstatus ok]} {
return [dict create origin $origin docid $origindoc cmdtype $origintype unavailable $unavail overridden $overridden args_remaining $args_remaining parsestatus $pstatus]
}
#G-166: a recognised-but-unavailable subject is never presented as cleanly
#usable. The advisory parse can succeed against the subject's virtual id
#(the id documents the word, and an argument tail like 'string is dict 5'
#satisfies it) - so an ok parse would otherwise switch to the 'info' scheme
#and mark the words good, rendering exactly like a usable command line. The
#unavailability marking takes precedence over BOTH the ok-parse info render
#and any parse failure message: the subject not existing here is the more
#fundamental report, and it is the one a parse against a virtual id cannot
#make. The parse status is still passed through, so argument positions keep
#their marking under the (non-info) scheme.
if {$unavail ne ""} {
set result [punk::args::arg_error [_cmdhelp_unavailable_marking $unavail] [punk::args::get_spec $origindoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
} elseif {[dict get $pstatus ok]} {
#show usage - with goodargs marked
if {!$scheme_received} {
dict set nextopts -scheme info
@ -5811,6 +5995,10 @@ y" {return quirkykeyscript}
} else {
set result [punk::args::arg_error [dict get $pstatus message] [punk::args::get_spec $origindoc] {*}$nextopts -aserror 0 -parsestatus $pstatus]
}
if {[llength $overridden]} {
#G-176: override-in-place notice leads the render
set result "note: [_cmdhelp_override_notice $querycommand $overridden]\n$result"
}
if {$opt_grepstr ne ""} {
if {[llength $opt_grepstr] == 1} {
set result [punk::ansi::grepstr --ignore-case -return all [lindex $opt_grepstr 0] $result]
@ -5821,9 +6009,13 @@ y" {return quirkykeyscript}
return $result
} else {
if {$opt_return eq "dict"} {
return [dict create origin $origin docid "" cmdtype $origintype args_remaining $args_remaining parsestatus {}]
return [dict create origin $origin docid "" cmdtype $origintype unavailable $unavail overridden $overridden args_remaining $args_remaining parsestatus {}]
}
return "Undocumented command $origin. Type: $origintype"
set result "Undocumented command $origin. Type: $origintype"
if {[llength $overridden]} {
set result "note: [_cmdhelp_override_notice $querycommand $overridden]\n$result"
}
return $result
}
}
@ -6746,6 +6938,6 @@ namespace eval ::punk::args::register {
## Ready
package provide punk::ns [tcl::namespace::eval punk::ns {
variable version
set version 0.9.3
set version 0.11.0
}]
return
Loading…
Cancel
Save