Browse Source

overtype lib update and bootsupport update

master
Julian Noble 3 months ago
parent
commit
ce5819a715
  1. 150
      src/bootsupport/modules/natsort-0.1.1.6.tm
  2. 818
      src/bootsupport/modules/overtype-1.6.4.tm
  3. 1791
      src/bootsupport/modules/punk/ansi-0.1.1.tm
  4. 674
      src/bootsupport/modules/punk/args-0.1.0.tm
  5. 118
      src/bootsupport/modules/punk/assertion-0.1.0.tm
  6. 115
      src/bootsupport/modules/punk/cap-0.1.0.tm
  7. 19
      src/bootsupport/modules/punk/cap/handlers/templates-0.1.0.tm
  8. 999
      src/bootsupport/modules/punk/char-0.1.0.tm
  9. 11
      src/bootsupport/modules/punk/console-0.1.1.tm
  10. 12
      src/bootsupport/modules/punk/du-0.1.0.tm
  11. 21
      src/bootsupport/modules/punk/fileline-0.1.0.tm
  12. 523
      src/bootsupport/modules/punk/lib-0.1.1.tm
  13. 34
      src/bootsupport/modules/punk/mix-0.2.tm
  14. 7
      src/bootsupport/modules/punk/mix/base-0.1.tm
  15. 9
      src/bootsupport/modules/punk/mix/cli-0.3.tm
  16. 14
      src/bootsupport/modules/punk/mix/commandset/layout-0.1.0.tm
  17. 93
      src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm
  18. 46
      src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  19. 2
      src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm
  20. 2
      src/bootsupport/modules/punk/mix/templates-0.1.0.tm
  21. 4
      src/bootsupport/modules/punk/mix/templates/layouts/project/src/make.tcl
  22. 101
      src/bootsupport/modules/punk/ns-0.1.0.tm
  23. 84
      src/bootsupport/modules/punk/overlay-0.1.tm
  24. 17
      src/bootsupport/modules/punk/path-0.1.0.tm
  25. 6
      src/bootsupport/modules/punk/repo-0.1.1.tm
  26. 8
      src/bootsupport/modules/punk/winpath-0.1.0.tm
  27. 41
      src/bootsupport/modules/punkcheck-0.1.0.tm
  28. 2444
      src/bootsupport/modules/textblock-0.1.1.tm
  29. 2252
      src/bootsupport/modules/textutil/wcswidth-35.2.tm
  30. 543
      src/vendormodules/overtype-1.6.3.tm
  31. 3685
      src/vendormodules/overtype-1.6.4.tm
  32. 3588
      src/vendormodules/tcltest-2.5.8.tm
  33. 2252
      src/vendormodules/textutil/wcswidth-35.2.tm

150
src/bootsupport/modules/natsort-0.1.1.6.tm

@ -242,7 +242,7 @@ namespace eval natsort {
proc hex2dec {largeHex} {
#todo - use punk::lib::hex2dec - (scan supports ll so can do larger hex values directly)
set res 0
set largeHex [string map [list _ ""] $largeHex]
set largeHex [string map {_ {}} $largeHex]
if {[string length $largeHex] <=7} {
#scan can process up to FFFFFFF and does so quickly
return [scan $largeHex %x]
@ -392,7 +392,7 @@ namespace eval natsort {
proc get_char_count {str char} {
#faster than lsearch on split for str of a few K
expr {[string length $str]-[string length [string map [list $char {}] $str]]}
expr {[tcl::string::length $str]-[tcl::string::length [tcl::string::map "$char {}" $str]]}
}
proc build_key {chunk splitchars topdict tagconfig debug} {
@ -856,10 +856,39 @@ namespace eval natsort {
return [csv::join $line {*}$opts]
}
#----------------------------------------
variable sort_flagspecs
set sort_flagspecs [dict create\
-caller natsort::sort \
-return supplied|defaults \
-defaults [list -collate nocase \
-winlike 0 \
-splits "\uFFFF" \
-topchars {. _} \
-showsplits 1 \
-sortmethod ascii \
-collate "\uFFFF" \
-inputformat raw \
-inputformatapply {index data} \
-inputformatoptions "" \
-outputformat raw \
-outputformatoptions "" \
-cols "\uFFFF" \
-debug 0 -db "" -stacktrace 0 -splits "\uFFFF" -showsplits 0] \
-required {all} \
-extras {none} \
-commandprocessors {}\
]
proc sort {stringlist args} {
#puts stdout "natsort::sort args: $args"
variable debug
variable sort_flagspecs
if {![llength $stringlist]} return
if {[llength $stringlist] == 1} {
if {"-inputformat" ni $args && "-outputformat" ni $args} {
return $stringlist
}
}
#allow pass through of the check_flags flag -debugargs so it can be set by the caller
set debugargs 0
@ -874,49 +903,43 @@ namespace eval natsort {
#-return flagged|defaults doesn't work Review.
#flagfilter global processor/allocator not working 2023-08
set args [check_flags \
-caller natsort::sort \
-return supplied|defaults \
-debugargs $debugargs \
-defaults [list -collate nocase \
-winlike 0 \
-splits "\uFFFF" \
-topchars {. _} \
-showsplits 1 \
-sortmethod ascii \
-collate "\uFFFF" \
-inputformat raw \
-inputformatapply {index data} \
-inputformatoptions "" \
-outputformat raw \
-outputformatoptions "" \
-cols "\uFFFF" \
-debug 0 -db "" -stacktrace 0 -splits "\uFFFF" -showsplits 0] \
-required {all} \
-extras {none} \
-commandprocessors {} \
-values $args]
#csv unimplemented
set winlike [dict get $args -winlike]
set topchars [dict get $args -topchars]
set cols [dict get $args -cols]
set debug [dict get $args -debug]
set stacktrace [dict get $args -stacktrace]
set showsplits [dict get $args -showsplits]
set splits [dict get $args -splits]
set sortmethod [dict get $args -sortmethod]
set opt_collate [dict get $args -collate]
set opt_inputformat [dict get $args -inputformat]
set opt_inputformatapply [dict get $args -inputformatapply]
set opt_inputformatoptions [dict get $args -inputformatoptions]
set opt_outputformat [dict get $args -outputformat]
set opt_outputformatoptions [dict get $args -outputformatoptions]
dict unset args -showsplits
dict unset args -splits
set opts [check_flags {*}$sort_flagspecs -debugargs $debugargs -values $args]
#we can only shortcircuit input list of single element at this point if there aren't non-default -inputformat or -outputformat transformations
if {[llength $stringlist] == 1} {
set is_basic 1
foreach fname [list -inputformat -outputformat] {
if {[dict get $sort_flagspecs -defaults $fname] ne [dict get $opts $fname]} {
set is_basic 0
break
}
}
if {$is_basic} {
return $stringlist
}
}
set winlike [dict get $opts -winlike]
set topchars [dict get $opts -topchars]
set cols [dict get $opts -cols]
set debug [dict get $opts -debug]
set stacktrace [dict get $opts -stacktrace]
set showsplits [dict get $opts -showsplits]
set splits [dict get $opts -splits]
set sortmethod [dict get $opts -sortmethod]
set opt_collate [dict get $opts -collate]
set opt_inputformat [dict get $opts -inputformat]
set opt_inputformatapply [dict get $opts -inputformatapply]
set opt_inputformatoptions [dict get $opts -inputformatoptions]
set opt_outputformat [dict get $opts -outputformat]
set opt_outputformatoptions [dict get $opts -outputformatoptions]
if {$debug} {
puts stdout "natsort::sort processed_args: $args"
#dict unset opts -showsplits
#dict unset opts -splits
puts stdout "natsort::sort processed_args: $opts"
if {$debug == 1} {
puts stdout "natsort::sort - try also -debug 2, -debug 3"
}
@ -1428,23 +1451,26 @@ namespace eval natsort {
}
}
set is_namematch [called_directly_namematch]
set is_inodematch [called_directly_inodematch]
####
#review - reliability of mechanisms to determine direct calls
# we don't want application being called when being used as a library, but we need it to run if called directly or from symlinks etc
#-- choose a policy and leave the others commented.
#set is_called_directly $is_namematch
#set is_called_directly $is_inodematch
set is_called_directly [expr {$is_namematch || $is_inodematch}]
#set is_called_directly [expr {$is_namematch && $is_inodematch}]
###
#puts stdout "called_directly_name: [called_directly_namematch] called_directly_inode: [called_directly_inodematch]"
if {![interp issafe]} {
set is_namematch [called_directly_namematch]
set is_inodematch [called_directly_inodematch]
####
#review - reliability of mechanisms to determine direct calls
# we don't want application being called when being used as a library, but we need it to run if called directly or from symlinks etc
#-- choose a policy and leave the others commented.
#set is_called_directly $is_namematch
#set is_called_directly $is_inodematch
set is_called_directly [expr {$is_namematch || $is_inodematch}]
#set is_called_directly [expr {$is_namematch && $is_inodematch}]
###
#puts stdout "called_directly_name: [called_directly_namematch] called_directly_inode: [called_directly_inodematch]"
} else {
#safe interp
set is_called_directly 0
}
#
proc test_pass_fail_message {pass {additional ""}} {
@ -1709,9 +1735,9 @@ namespace eval natsort {
set debug [dict get $args -debug]
set collate [dict get $args -collate]
set db [dict get $args -db]
set winlike [dict get $args -winlike]
set collate [dict get $args -collate]
set db [dict get $args -db]
set winlike [dict get $args -winlike]
set topchars [dict get $args -topchars]

818
src/vendormodules/overtype-1.6.2.tm → src/bootsupport/modules/overtype-1.6.4.tm

File diff suppressed because it is too large Load Diff

1791
src/bootsupport/modules/punk/ansi-0.1.1.tm

File diff suppressed because it is too large Load Diff

674
src/bootsupport/modules/punk/args-0.1.0.tm

File diff suppressed because it is too large Load Diff

118
src/bootsupport/modules/punk/assertion-0.1.0.tm

@ -69,11 +69,11 @@ package require Tcl 8.6-
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::assertion::class {
tcl::namespace::eval punk::assertion::class {
#*** !doctools
#[subsection {Namespace punk::assertion::class}]
#[para] class definitions
if {[info commands [namespace current]::interface_sample1] eq ""} {
if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} {
#*** !doctools
#[list_begin enumerated]
@ -100,16 +100,16 @@ namespace eval punk::assertion::class {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#keep 2 namespaces for assertActive and assertInactive so there is introspection available via namespace origin
namespace eval punk::assertion::primary {
namespace export *
tcl::namespace::eval punk::assertion::primary {
#tcl::namespace::export {[a-z]*}
tcl::namespace::export assertActive assertInactive
proc assertActive {expr args} {
set code [catch {uplevel 1 [list expr $expr]} res]
if {$code} {
return -code $code $res
}
if {![string is boolean -strict $res]} {
if {![tcl::string::is boolean -strict $res]} {
return -code error "invalid boolean expression: $expr"
}
@ -124,28 +124,40 @@ namespace eval punk::assertion::primary {
upvar ::punk::assertion::CallbackCmd CallbackCmd
# Might want to catch this
namespace eval :: $CallbackCmd [list $msg]
tcl::namespace::eval :: $CallbackCmd [list $msg]
}
proc assertInactive args {}
}
namespace eval punk::assertion::secondary {
namespace export *
tcl::namespace::eval punk::assertion::secondary {
tcl::namespace::export *
#we need to actually define these procs here, (not import then re-export) - or namespace origin will report the original source namespace - which isn't what we want.
proc assertActive {expr args} [info body ::punk::assertion::primary::assertActive]
proc assertActive {expr args} [tcl::info::body ::punk::assertion::primary::assertActive]
proc assertInactive args {}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::assertion {
tcl::namespace::eval punk::assertion {
variable CallbackCmd [list return -code error]
namespace import ::punk::assertion::primary::assertActive
#puts --------AAA
#*very* slow in safe interp - why?
#tcl::namespace::import ::punk::assertion::primary::assertActive
proc do_ns_import {} {
uplevel 1 [list tcl::namespace::import ::punk::assertion::primary::assertActive]
}
do_ns_import
#puts --------BBB
rename assertActive assert
namespace export *
}
tcl::namespace::eval punk::assertion {
tcl::namespace::export *
#variable xyz
#*** !doctools
@ -177,7 +189,7 @@ namespace eval punk::assertion {
set n [llength $args]
if {$n > 1} {
return -code error "wrong # args: should be\
\"[lindex [info level 0] 0] ?command?\""
\"[lindex [tcl::info::level 0] 0] ?command?\""
}
if {$n} {
set cb [lindex $args 0]
@ -187,41 +199,41 @@ namespace eval punk::assertion {
}
proc active {{on_off ""}} {
set nscaller [uplevel 1 [list namespace current]]
set which_assert [namespace eval $nscaller {namespace which assert}]
set nscaller [uplevel 1 [list tcl::namespace::current]]
set which_assert [tcl::namespace::eval $nscaller {tcl::namespace::which assert}]
#puts "nscaller:'$nscaller'"
#puts "which_assert: $which_assert"
if {$on_off eq ""} {
if {$which_assert eq ""} {return 0}
set assertorigin [namespace origin $which_assert]
set assertorigin [tcl::namespace::origin $which_assert]
#puts "ns which assert: $which_assert"
#puts "ns origin assert: $assertorigin"
return [expr {"assertActive" eq [namespace tail $assertorigin]}]
return [expr {"assertActive" eq [tcl::namespace::tail $assertorigin]}]
}
if {![string is boolean -strict $on_off]} {
if {![tcl::string::is boolean -strict $on_off]} {
error "invalid boolean value : $on_off"
} else {
set info_command [namespace eval $nscaller {info commands assert}]
set info_command [tcl::namespace::eval $nscaller {tcl::info::commands assert}]
if {$on_off} {
#Enable it in calling namespace
if {"assert" eq $info_command} {
#There is an assert command reachable - due to namespace path etc, it could be in another namespace entirely - (not necessarily in an ancestor namespace of the namespace's tree structure)
if {$which_assert eq [punk::assertion::system::nsjoin ${nscaller} assert]} {
namespace eval $nscaller {
set assertorigin [namespace origin assert]
tcl::namespace::eval $nscaller {
set assertorigin [tcl::namespace::origin assert]
set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin]
switch -- $assertorigin_ns {
::punk::assertion {
#original import - switch to primary origin
rename assert {}
namespace import ::punk::assertion::primary::assertActive
tcl::namespace::import ::punk::assertion::primary::assertActive
rename assertActive assert
}
::punk::assertion::primary - ::punk::assertion::secondary {
#keep using from same origin ns
rename assert {}
namespace import ${assertorigin_ns}::assertActive
tcl::namespace::import ${assertorigin_ns}::assertActive
rename assertActive assert
}
default {
@ -232,10 +244,10 @@ namespace eval punk::assertion {
return 1
} else {
#assert is available, but isn't in the calling namespace - we should enable it in a way that is distinguishable from case where assert was explicitly imported to this namespace
namespace eval $nscaller {
set assertorigin [namespace origin assert]
if {[string match ::punk::assertion::* $assertorigin]} {
namespace import ::punk::assertion::secondary::assertActive
tcl::namespace::eval $nscaller {
set assertorigin [tcl::namespace::origin assert]
if {[tcl::string::match ::punk::assertion::* $assertorigin]} {
tcl::namespace::import ::punk::assertion::secondary::assertActive
rename assertActive assert
} else {
error "The reachable assert command at '$which_assert' is not from punk::assertion package. Import punk::assertion::assert - or use the enable mechanism from the package associated with $assertorigin"
@ -254,20 +266,20 @@ namespace eval punk::assertion {
if {"assert" eq $info_command} {
if {$which_assert eq [punk::assertion::system::nsjoin ${nscaller} assert]} {
#assert is present in callers NS
namespace eval $nscaller {
set assertorigin [namespace origin assert]
tcl::namespace::eval $nscaller {
set assertorigin [tcl::namespace::origin assert]
set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin]
switch -glob -- $assertorigin_ns {
::punk::assertion {
#original import
rename assert {}
namespace import punk::assertion::primary::assertInactive
tcl::namespace::import punk::assertion::primary::assertInactive
rename assertInactive assert
}
::punk::assertion::primary - ::punk::assertion::secondary {
#keep using from same origin ns
rename assert {}
namespace import ${assertorigin_ns}::assertInactive
tcl::namespace::import ${assertorigin_ns}::assertInactive
rename assertInactive assert
}
default {
@ -278,11 +290,11 @@ namespace eval punk::assertion {
return 0
} else {
#assert not present in callers NS - first install of secondary (if assert is from punk::assertion::*)
namespace eval $nscaller {
set assertorigin [namespace origin assert]
tcl::namespace::eval $nscaller {
set assertorigin [tcl::namespace::origin assert]
set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin]
if {[string match ::punk::assertion::* $assertorigin]} {
namespace import ::punk::assertion::secondary::assertInactive
if {[tcl::string::match ::punk::assertion::* $assertorigin]} {
tcl::namespace::import ::punk::assertion::secondary::assertInactive
rename assertInactive assert
} else {
error "The reachable assert command at '$which_assert' is not from punk::assertion package. Import punk::assertion::assert - or use the enable mechanism from the package associated with $assertorigin"
@ -310,9 +322,9 @@ namespace eval punk::assertion {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::assertion::lib {
namespace export *
namespace path [namespace parent]
tcl::namespace::eval punk::assertion::lib {
tcl::namespace::export *
tcl::namespace::path [tcl::namespace::parent]
#*** !doctools
#[subsection {Namespace punk::assertion::lib}]
#[para] Secondary functions that are part of the API
@ -337,7 +349,7 @@ namespace eval punk::assertion::lib {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval punk::assertion::system {
tcl::namespace::eval punk::assertion::system {
#*** !doctools
#[subsection {Namespace punk::assertion::system}]
#[para] Internal functions that are not part of the API
@ -346,33 +358,33 @@ namespace eval punk::assertion::system {
#nsprefix/nstail are string functions - they do not concern themselves with what namespaces are present in the system
proc nsprefix {{nspath {}}} {
#normalize the common case of ::::
set nspath [string map [list :::: ::] $nspath]
set rawprefix [string range $nspath 0 end-[string length [nstail $nspath]]]
set nspath [tcl::string::map [list :::: ::] $nspath]
set rawprefix [tcl::string::range $nspath 0 end-[tcl::string::length [nstail $nspath]]]
if {$rawprefix eq "::"} {
return $rawprefix
} else {
if {[string match *:: $rawprefix]} {
return [string range $rawprefix 0 end-2]
if {[tcl::string::match *:: $rawprefix]} {
return [tcl::string::range $rawprefix 0 end-2]
} else {
return $rawprefix
}
#return [string trimright $rawprefix :]
#return [tcl::string::trimright $rawprefix :]
}
}
#see also punk::ns - keep in sync
proc nstail {nspath args} {
#normalize the common case of ::::
set nspath [string map [list :::: ::] $nspath]
set mapped [string map [list :: \u0FFF] $nspath]
set nspath [tcl::string::map [list :::: ::] $nspath]
set mapped [tcl::string::map [list :: \u0FFF] $nspath]
set parts [split $mapped \u0FFF]
set defaults [list -strict 0]
set opts [dict merge $defaults $args]
set strict [dict get $opts -strict]
set opts [tcl::dict::merge $defaults $args]
set strict [tcl::dict::get $opts -strict]
if {$strict} {
foreach p $parts {
if {[string match :* $p]} {
if {[tcl::string::match :* $p]} {
error "nstail unpaired colon ':' in $nspath"
}
}
@ -381,7 +393,7 @@ namespace eval punk::assertion::system {
return [lindex $parts end]
}
proc nsjoin {prefix name} {
if {[string match ::* $name]} {
if {[tcl::string::match ::* $name]} {
if {"$prefix" ne ""} {
error "nsjoin: won't join non-empty prefix to absolute namespace path '$name'"
}
@ -400,7 +412,7 @@ namespace eval punk::assertion::system {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::assertion [namespace eval punk::assertion {
package provide punk::assertion [tcl::namespace::eval punk::assertion {
variable pkg punk::assertion
variable version
set version 0.1.0

115
src/bootsupport/modules/punk/cap-0.1.0.tm

@ -48,12 +48,12 @@ package require oolib
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::cap {
variable pkgcapsdeclared [dict create]
variable pkgcapsaccepted [dict create]
variable caps [dict create]
tcl::namespace::eval punk::cap {
variable pkgcapsdeclared [tcl::dict::create]
variable pkgcapsaccepted [tcl::dict::create]
variable caps [tcl::dict::create]
namespace eval class {
if {[info commands [namespace current]::interface_caphandler.registry] eq ""} {
if {[tcl::info::commands ::punk::cap::class::interface_caphandler.registry] eq ""} {
#*** !doctools
#[subsection {Namespace punk::cap::class}]
#[para] class definitions
@ -62,7 +62,7 @@ namespace eval punk::cap {
# [para] [emph {handler_classes}]
# [list_begin enumerated]
oo::class create [namespace current]::interface_caphandler.registry {
oo::class create ::punk::cap::class::interface_caphandler.registry {
#*** !doctools
#[enum] CLASS [class interface_caphandler.registry]
#[list_begin definitions]
@ -83,7 +83,7 @@ namespace eval punk::cap {
#[list_end]
}
oo::class create [namespace current]::interface_caphandler.sysapi {
oo::class create ::punk::cap::class::interface_caphandler.sysapi {
#*** !doctools
#[enum] CLASS [class interface_caphandler.sysapi]
#[list_begin definitions]
@ -103,7 +103,7 @@ namespace eval punk::cap {
# [list_begin enumerated]
#Provider classes
oo::class create [namespace current]::interface_capprovider.registration {
oo::class create ::punk::cap::class::interface_capprovider.registration {
#*** !doctools
# [enum] CLASS [class interface_cappprovider.registration]
# [para]Your provider package will need to instantiate this object under a sub-namespace called [namespace capsystem] within your package namespace.
@ -140,7 +140,7 @@ namespace eval punk::cap {
# [list_end]
}
oo::class create [namespace current]::interface_capprovider.provider {
oo::class create ::punk::cap::class::interface_capprovider.provider {
#*** !doctools
# [enum] CLASS [class interface_capprovider.provider]
# [para] Your provider package will need to instantiate this directly under it's own namespace with the command name of [emph {provider}]
@ -157,7 +157,7 @@ namespace eval punk::cap {
#*** !doctools
#[call class::interface_capprovider.provider [method constructor] [arg providerpkg]]
variable provider_pkg
if {$providerpkg in [list "" "::"]} {
if {$providerpkg in {"" "::"}} {
error "interface_capprovider.provider constructor error. Invalid provider '$providerpkg'"
}
if {![namespace exists ::$providerpkg]} {
@ -165,12 +165,12 @@ namespace eval punk::cap {
}
set registrationobj ::${providerpkg}::capsystem::capprovider.registration
if {[info commands $registrationobj] eq ""} {
if {[tcl::info::commands $registrationobj] eq ""} {
error "capprovider.provider constructor error. Missing capprovider.registration interface at '$obj' (command not found) interface_capprovider.regstration instantiation must precede interface_capprovider.provider"
}
set provider_pkg [string trim $providerpkg ""]
#review - what are we trying to achieve here?
set provider_pkg [tcl::string::trim $providerpkg ""]
}
method register {{capabilityname_glob *}} {
#*** !doctools
@ -232,13 +232,13 @@ namespace eval punk::cap {
#such unregistered capabilitynames may be used just to flag something, or have datamembers significant to callers cooperatively interested in that capname.
#we allow registering a capability with an empty handler (capnamespace) - but this means another handler could be registered later.
proc register_capabilityname {capname capnamespace} {
puts stderr "REGISTER_CAPABILITYNAME $capname $capnamespace"
#puts stderr "REGISTER_CAPABILITYNAME $capname $capnamespace"
variable caps
variable pkgcapsdeclared
variable pkgcapsaccepted
if {$capnamespace ne ""} {
#normalize with leading :: in case caller passed in package name rather than fully qualified namespace
if {![string match ::* $capnamespace]} {
if {![tcl::string::match ::* $capnamespace]} {
set capnamespace ::$capnamespace
}
}
@ -250,20 +250,21 @@ namespace eval punk::cap {
return
}
#assertion: capnamespace may or may not be empty string, capname may or may not already exist in caps dict, caps $capname providers may have existing entries.
dict set caps $capname handler $capnamespace
if {![dict exists $caps $capname providers]} {
dict set caps $capname providers [list]
tcl::dict::set caps $capname handler $capnamespace
if {![tcl::dict::exists $caps $capname providers]} {
tcl::dict::set caps $capname providers [list]
}
if {[llength [set providers [dict get $caps $capname providers]]]} {
if {[llength [set providers [tcl::dict::get $caps $capname providers]]]} {
#some provider(s) were in place before the handler was registered
if {[set capreg [punk::cap::capsystem::get_caphandler_registry $capname]] ne ""} {
foreach pkg $providers {
set fullcapabilitylist [dict get $pkgcapsdeclared $pkg]
foreach capspec $fullcapabilitylist {
set fullcapabilitylist [tcl::dict::get $pkgcapsdeclared $pkg]
set capname_capabilitylist [lsearch -all -inline -index 0 $fullcapabilitylist $capname]
foreach capspec $capname_capabilitylist {
lassign $capspec cn capdict
if {$cn ne $capname} {
continue
}
#if {$cn ne $capname} {
# continue
#}
if {[catch {$capreg pkg_register $pkg $capdict $fullcapabilitylist} do_register]} {
puts stderr "punk::cap::register_capabilityname '$capname' '$capnamespace' failed to register provider package '$pkg' - possible error in handler or provider"
puts stderr "error message:"
@ -271,22 +272,22 @@ namespace eval punk::cap {
set do_register 0
}
set list_accepted [dict get $pkgcapsaccepted $pkg]
set list_accepted [tcl::dict::get $pkgcapsaccepted $pkg]
if {$do_register} {
if {$capspec ni $list_accepted} {
dict lappend pkgcapsaccepted $pkg $capspec
tcl::dict::lappend pkgcapsaccepted $pkg $capspec
}
} else {
set posn [lsearch $list_accepted $capspec]
if {$posn >=0} {
set list_accepted [lreplace $list_accepted $posn $posn]
dict set pkgcapsaccepted $pkg $list_accepted
tcl::dict::set pkgcapsaccepted $pkg $list_accepted
}
}
}
#check if any accepted for this cap and remove from caps as necessary
set count 0
foreach accepted_capspec [dict get $pkgcapsaccepted $pkg] {
foreach accepted_capspec [tcl::dict::get $pkgcapsaccepted $pkg] {
if {[lindex $accepted_capspec 0] eq $capname} {
incr count
}
@ -295,7 +296,7 @@ namespace eval punk::cap {
set pkgposn [lsearch $providers $pkg]
if {$pkgposn >= 0} {
set updated_providers [lreplace $providers $posn $posn]
dict set caps $capname providers $updated_providers
tcl::dict::set caps $capname providers $updated_providers
}
}
}
@ -309,14 +310,14 @@ namespace eval punk::cap {
# [call [fun capability_exists] [arg capname]]
# Return a boolean indicating if the named capability exists (0|1)
variable caps
return [dict exists $caps $capname]
return [tcl::dict::exists $caps $capname]
}
proc capability_has_handler {capname} {
#*** !doctools
# [call [fun capability_has_handler] [arg capname]]
#Return a boolean indicating if the named capability has a handler package installed (0|1)
variable caps
return [expr {[dict exists $caps $capname handler] && [dict get $caps $capname handler] ne ""}]
return [expr {[tcl::dict::exists $caps $capname handler] && [tcl::dict::get $caps $capname handler] ne ""}]
}
proc capability_get_handler {capname} {
#*** !doctools
@ -324,8 +325,8 @@ namespace eval punk::cap {
#Return the base namespace of the active handler package for the named capability.
#[para] The base namespace for a handler will always be the package name, but prefixed with ::
variable caps
if {[dict exists $caps $capname]} {
return [dict get $caps $capname handler]
if {[tcl::dict::exists $caps $capname]} {
return [tcl::dict::get $caps $capname handler]
}
return ""
}
@ -338,8 +339,8 @@ namespace eval punk::cap {
}
proc get_providers {capname} {
variable caps
if {[dict exists $caps $capname]} {
return [dict get $caps $capname providers]
if {[tcl::dict::exists $caps $capname]} {
return [tcl::dict::get $caps $capname providers]
}
return [list]
}
@ -356,26 +357,26 @@ namespace eval punk::cap {
foreach {k v} $args {
switch -- $k {
-nowarnings {
dict set opts $k $v
tcl::dict::set opts $k $v
}
default {
error "Unrecognized option $k. Known options [dict keys $opts]"
error "Unrecognized option $k. Known options [tcl::dict::keys $opts]"
}
}
}
set warnings [expr {! [dict get $opts -nowarnings]}]
set warnings [expr {! [tcl::dict::get $opts -nowarnings]}]
if {[string match ::* $pkg]} {
set pkg [string range $pkg 2 end]
if {[tcl::string::match ::* $pkg]} {
set pkg [tcl::string::range $pkg 2 end]
}
if {[dict exists $pkgcapsaccepted $pkg]} {
set pkg_already_accepted [dict get $pkgcapsaccepted $pkg]
if {[tcl::dict::exists $pkgcapsaccepted $pkg]} {
set pkg_already_accepted [tcl::dict::get $pkgcapsaccepted $pkg]
} else {
set pkg_already_accepted [list]
}
package require $pkg
set providerapi ::${pkg}::provider
if {[info commands $providerapi] eq ""} {
if {[tcl::info::commands $providerapi] eq ""} {
error "register_package error. pkg '$pkg' doesn't seem to be a punk::cap capability provider (no object found at $providerapi)"
}
set defined_caps [$providerapi capabilities]
@ -397,13 +398,13 @@ namespace eval punk::cap {
if {[llength $capname] !=1} {
puts stderr "register_package error. pkg: '$pkg' An entry in the capability list doesn't appear to have a single-word name. Problematic entry:'$capspec'"
set reason "First element of capspec not a single-word name"
lappend errorlist [dict create msg $reason capspec $capspec]
lappend errorlist [tcl::dict::create msg $reason capspec $capspec]
continue
}
if {[expr {[llength $capdict] %2 != 0}]} {
puts stderr "register_package error. pkg:'$pkg' The second element for capname:'$capname' doesn't appear to be a valid dict. Problematic entry: '$capspec'"
set reason "The second element of the capspec isn't a valid dict"
lappend errorlist [dict create msg $reason capspec $capspec]
lappend errorlist [tcl::dict::create msg $reason capspec $capspec]
continue
}
if {$capspec in $pkg_already_accepted} {
@ -411,13 +412,13 @@ namespace eval punk::cap {
if {$warnings} {
puts stderr "WARNING: register_package pkg $pkg already has capspec marked as accepted: $capspec"
}
lappend warninglist [dict create msg "pkg $pkg already has this capspec marked as accepted" capspec $capspec]
lappend warninglist [tcl::dict::create msg "pkg $pkg already has this capspec marked as accepted" capspec $capspec]
continue
}
if {[dict exists $caps $capname]} {
set cap_pkgs [dict get $caps $capname providers]
if {[tcl::dict::exists $caps $capname]} {
set cap_pkgs [tcl::dict::get $caps $capname providers]
} else {
dict set caps $capname [dict create handler "" providers [list]]
dict set caps $capname [tcl::dict::create handler "" providers [list]]
set cap_pkgs [list]
}
#todo - if there's a caphandler - call it's init/validation callback for the pkg
@ -429,31 +430,31 @@ namespace eval punk::cap {
if {$do_register} {
if {$pkg ni $cap_pkgs} {
lappend cap_pkgs $pkg
dict set caps $capname providers $cap_pkgs
tcl::dict::set caps $capname providers $cap_pkgs
}
dict lappend pkgcapsaccepted $pkg $capspec ;#if pkg is being registered prior to handler-registration - the handler may undo this entry
tcl::dict::lappend pkgcapsaccepted $pkg $capspec ;#if pkg is being registered prior to handler-registration - the handler may undo this entry
}
}
#another call to register_pkg with same pkg may have been made (most likely with different capname) so we must append - but check not already present
#dict lappend pkgcapsdeclared $pkg $capabilitylist
if {[dict exists $pkgcapsdeclared $pkg]} {
if {[tcl::dict::exists $pkgcapsdeclared $pkg]} {
#review - untested
set mergecapspecs [dict get $pkgcapsdeclared $pkg]
set mergecapspecs [tcl::dict::get $pkgcapsdeclared $pkg]
foreach spec $capabilitylist {
if {$spec ni $mergecapspecs} {
lappend mergecapspecs $spec
}
}
dict set pkgcapsdeclared $pkg $mergecapspecs
tcl::dict::set pkgcapsdeclared $pkg $mergecapspecs
} else {
dict set pkgcapsdeclared $pkg $capabilitylist
tcl::dict::set pkgcapsdeclared $pkg $capabilitylist
}
set resultdict [list num_capabilities $capabilitylist_count num_accepted $accepted_count]
if {[llength $errorlist]} {
dict set resultdict errors $errorlist
tcl::dict::set resultdict errors $errorlist
}
if {[llength $warninglist]} {
dict set resultdict warnings $warninglist
tcl::dict::set resultdict warnings $warninglist
}
return $resultdict
}

19
src/bootsupport/modules/punk/cap/handlers/templates-0.1.0.tm

@ -61,7 +61,7 @@ namespace eval punk::cap::handlers::templates {
set path [dict get $capdict path]
set cname [string map [list . _] $capname]
set cname [string map {. _} $capname]
set multivendor_package_whitelist [list punk::mix::templates]
@ -85,8 +85,19 @@ namespace eval punk::cap::handlers::templates {
module {
set provide_statement [package ifneeded $pkg [package require $pkg]]
set tmfile [lindex $provide_statement end]
if {[interp issafe]} {
#default safe interp can't use file exists/normalize etc.. but safe interp may have a policy/alias set allowing file access to certain paths - so test if file exists is usable
if {[catch {file exists $tmfile} tm_exists]} {
puts stderr "punk::cap::handlers::templates::capsystem::pkg_register WARNING (expected in most safe interps) - unable to determine base folder for package '$pkg' which is attempting to register with punk::cap as a provider of '$capname' capability"
flush stderr
return 0
}
} else {
set tm_exists [file exists $tmfile]
}
if {![file exists $tmfile]} {
puts stderr "punk::cap::handlers::templates::capsystem::pkg_register WARNING - unable to determine base folder for package '$pkg' which is attempting to register with punk::cap as a provider of '$capname' capability"
flush stderr
return 0
}
@ -215,7 +226,7 @@ namespace eval punk::cap::handlers::templates {
method pkg_unregister {pkg} {
upvar ::punk::cap::handlers::templates::handled_caps hcaps
foreach capname $hcaps {
set cname [string map [list . _] $capname]
set cname [string map {. _} $capname]
upvar ::punk::cap::handlers::templates::provider_info_$cname my_provider_info
dict unset my_provider_info $pkg
#destroy api objects?
@ -238,7 +249,7 @@ namespace eval punk::cap::handlers::templates {
constructor {capname} {
variable capabilityname
variable cname
set cname [string map [list . _] $capname]
set cname [string map {. _} $capname]
set capabilityname $capname
}
method folders {args} {
@ -635,6 +646,7 @@ namespace eval punk::cap::handlers::templates {
#and a name determining command -command_get_item_name
method _get_itemdict {args} {
set argd [punk::args::get_dict {
*proc -name _get_itemdict
*opts -anyopts 0
-startdir -default ""
-templatefolder_subdir -optional 0
@ -646,6 +658,7 @@ namespace eval punk::cap::handlers::templates {
} $args]
set opts [dict get $argd opts]
set globsearches [dict get $argd values globsearches]; #note that in this case our globsearch won't reduce the machine's effort in scannning the filesystem - as we need to search on the renamed results
#puts stderr "=-=============>globsearches:$globsearches"
# -- --- --- --- --- --- --- --- ---
set opt_startdir [dict get $opts -startdir]
set opt_templatefolder_subdir [dict get $opts -templatefolder_subdir]

999
src/bootsupport/modules/punk/char-0.1.0.tm

File diff suppressed because it is too large Load Diff

11
src/bootsupport/modules/punk/console-0.1.1.tm

@ -20,10 +20,10 @@
package require punk::ansi
if {"windows" eq $::tcl_platform(platform)} {
#package require zzzload
#zzzload::pkg_require twapi
}
#if {"windows" eq $::tcl_platform(platform)} {
# #package require zzzload
# #zzzload::pkg_require twapi
#}
#see https://learn.microsoft.com/en-us/windows/console/classic-vs-vt
#https://learn.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session
@ -765,6 +765,7 @@ namespace eval punk::console {
} ;#end namespace eval internal
variable colour_disabled 0
#todo - move to punk::config
# https://no-color.org
if {[info exists ::env(NO_COLOR)]} {
if {$::env(NO_COLOR) ne ""} {
@ -779,7 +780,7 @@ namespace eval punk::console {
#stdout
variable ansi_wanted
if {$ansi_wanted <= 0} {
puts -nonewline [punk::ansi::stripansi [::punk::ansi::a?]]
puts -nonewline [punk::ansi::stripansiraw [::punk::ansi::a?]]
} else {
tailcall ansi::a? {*}$args
}

12
src/bootsupport/modules/punk/du-0.1.0.tm

@ -901,7 +901,7 @@ namespace eval punk::du {
set hlinks [glob -nocomplain -dir $folderpath -types {hidden l} * .*]
#set hlinks {}
set links [glob -nocomplain -dir $folderpath -types l * .*] ;#links may have dupes - we don't care. struct::set difference will remove
set links [glob -nocomplain -dir $folderpath -types l * .*] ;#links may have dupes - we don't care. struct::set difference will remove (?)
#set links [lsort -unique [concat $hlinks $links[unset links]]]
set hfiles [glob -nocomplain -dir $folderpath -types {hidden f} * .*]
@ -913,18 +913,20 @@ namespace eval punk::du {
set dirs [glob -nocomplain -dir $folderpath -types d $opt_glob]
set hlinks [glob -nocomplain -dir $folderpath -types {hidden l} $opt_glob]
set links [glob -nocomplain -dir $folderpath -types l $opt_glob] ;#links may have dupes - we don't care. struct::set difference will remove
set links [glob -nocomplain -dir $folderpath -types l $opt_glob] ;#links may have dupes - we don't care. struct::set difference will remove (?)
set hfiles [glob -nocomplain -dir $folderpath -types {hidden f} $opt_glob]
set files [glob -nocomplain -dir $folderpath -types f $opt_glob]
}
#note struct::set difference produces unordered result
#struct::set difference removes duplicates
#struct::set difference removes duplicates (but not always.. e.g if using tcl impl and 2nd element empty!)
#relying on struct::set to remove dupes is somewhat risky. It is not well documented - and behaviour of dupes in inputs is underspecified as it appears to be intended for mathematical 'sets'
#remove links and . .. from directories, remove links from files
#struct::set will affect order: tcl vs critcl give different ordering!
set files [struct::set difference [concat $hfiles $files[unset files]] $links]
set dirs [struct::set difference [concat $hdirs $dirs[unset dirs]] [concat $links [list [file join $folderpath .] [file join $folderpath ..] ]]]
set links [lsort -unique [concat $links $hlinks]]
#set links [lsort -unique [concat $links $hlinks]]
#----
@ -1022,7 +1024,7 @@ namespace eval punk::du {
dict set effective_opts -with_times $timed_types
dict set effective_opts -with_sizes $sized_types
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times $alltimes flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
return [list dirs $dirs vfsmounts $vfsmounts links $links files $files filesizes [dict get $mdata_lists fsizes] sizes [dict get $mdata_lists allsizes] times [dict get $mdata_lists alltimes] flaggedhidden {} flaggedsystem {} flaggedreadonly {} altname {} opts $effective_opts errors $errors]
}
#we can halve the number of round trips on unix-like systems, where 'hidden' always corresponds to dotted files

21
src/bootsupport/modules/punk/fileline-0.1.0.tm

@ -1555,10 +1555,10 @@ namespace eval punk::fileline::lib {
}
proc range_boundaries {start end chunksizes args} {
lassign [punk::get_leading_opts_and_values {\
-offset 0\
} $args] _opts opts _vals remainingargs
set argd [punk::args::get_dict {
-offset -default 0
} $args]
lassign [dict values $argd] opts remainingargs
}
@ -1650,16 +1650,19 @@ namespace eval punk::fileline::system {
#gets very slow (comparitively) with large resultsets
proc _range_spans_chunk_boundaries_tcl {start end chunksize args} {
if {$chunksize < 1} {error "chunksize must be > 0"} ;#sanitycheck in case called directly
set defaults [dict create\
set opts [dict create\
-offset 0\
]
set known_opts [dict keys $defaults]
foreach {k v} $args {
if {$k ni $known_opts} {
error "unknown option '$k'. Known options: $known_opts"
switch -- $k {
-offset {
dict set opts $k $v
}
default {
error "unknown option '$k'. Known options: [dict keys $opts]"
}
}
}
set opts [dict merge $defaults $args]
# -- --- --- ---
set opt_offset [dict get $opts -offset]
# -- --- --- ---

523
src/bootsupport/modules/punk/lib-0.1.1.tm

@ -66,11 +66,11 @@ package require Tcl 8.6-
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::lib::class {
tcl::namespace::eval punk::lib::class {
#*** !doctools
#[subsection {Namespace punk::lib::class}]
#[para] class definitions
if {[info commands [namespace current]::interface_sample1] eq ""} {
if {[info commands [tcl::namespace::current]::interface_sample1] eq ""} {
#*** !doctools
#[list_begin enumerated]
@ -96,46 +96,46 @@ namespace eval punk::lib::class {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::lib::ensemble {
tcl::namespace::eval punk::lib::ensemble {
#wiki.tcl-lang.org/page/ensemble+extend
# extend an ensemble-like routine with the routines in some namespace
proc extend {routine extension} {
if {![string match ::* $routine]} {
set resolved [uplevel 1 [list ::namespace which $routine]]
set resolved [uplevel 1 [list ::tcl::namespace::which $routine]]
if {$resolved eq {}} {
error [list {no such routine} $routine]
}
set routine $resolved
}
set routinens [namespace qualifiers $routine]
set routinens [tcl::namespace::qualifiers $routine]
if {$routinens eq {::}} {
set routinens {}
}
set routinetail [namespace tail $routine]
set routinetail [tcl::namespace::tail $routine]
if {![string match ::* $extension]} {
set extension [uplevel 1 [
list [namespace which namespace] current]]::$extension
list [tcl::namespace::which namespace] current]]::$extension
}
if {![namespace exists $extension]} {
if {![tcl::namespace::exists $extension]} {
error [list {no such namespace} $extension]
}
set extension [namespace eval $extension [
list [namespace which namespace] current]]
set extension [tcl::namespace::eval $extension [
list [tcl::namespace::which namespace] current]]
namespace eval $extension [
list [namespace which namespace] export *]
tcl::namespace::eval $extension [
list [tcl::namespace::which namespace] export *]
while 1 {
set renamed ${routinens}::${routinetail}_[info cmdcount]
if {[namespace which $renamed] eq {}} break
if {[tcl::namespace::which $renamed] eq {}} break
}
rename $routine $renamed
namespace eval $extension [
tcl::namespace::eval $extension [
list namespace ensemble create -command $routine -unknown [
list apply {{renamed ensemble routine args} {
list $renamed $routine
@ -147,7 +147,7 @@ namespace eval punk::lib::ensemble {
}
}
namespace eval punk::lib::compat {
tcl::namespace::eval punk::lib::compat {
#*** !doctools
#[subsection {Namespace punk::lib::compat}]
#[para] compatibility functions for features that may not be available in earlier Tcl versions
@ -315,8 +315,8 @@ namespace eval punk::lib::compat {
}
# Bind [string insert] to [::tcl::string::insert].
namespace ensemble configure string -map [dict replace\
[namespace ensemble configure string -map]\
tcl::namespace::ensemble configure string -map [tcl::dict::replace\
[tcl::namespace::ensemble configure string -map]\
insert ::tcl::string::insert]
}
#*** !doctools
@ -327,7 +327,7 @@ namespace eval punk::lib::compat {
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::lib {
namespace export *
tcl::namespace::export *
#variable xyz
#*** !doctools
@ -335,15 +335,192 @@ namespace eval punk::lib {
#[para] Core API functions for punk::lib
#[list_begin definitions]
proc range {from to args} {
if {[info commands lseq] ne ""} {
#tcl 8.7+ lseq significantly faster for larger ranges
return [lseq $from $to]
if {[info commands lseq] ne ""} {
#tcl 8.7+ lseq significantly faster, especially for larger ranges
#support minimal set from to
proc range {from to} {
lseq $from $to
}
} else {
#lseq accepts basic expressions e.g 4-2 for both arguments
#e.g we can do lseq 0 [llength $list]-1
#if range is to be consistent with the lseq version above - it should support that, even though we don't support most lseq functionality in either wrapper.
proc range {from to} {
set to [offset_expr $to]
set from [offset_expr $from]
if {$to > $from} {
set count [expr {($to -$from) + 1}]
if {$from == 0} {
return [lsearch -all [lrepeat $count 0] *]
} else {
incr from -1
return [lmap v [lrepeat $count 0] {incr from}]
}
#slower methods.
#2)
#set i -1
#set L [lrepeat $count 0]
#lmap v $L {lset L [incr i] [incr from];lindex {}}
#return $L
#3)
#set L {}
#for {set i 0} {$i < $count} {incr i} {
# lappend L [incr from]
#}
#return $L
} elseif {$from > $to} {
set count [expr {$from - $to} + 1]
#1)
if {$to == 0} {
return [lreverse [lsearch -all [lrepeat $count 0] *]]
} else {
incr from
return [lmap v [lrepeat $count 0] {incr from -1}]
}
#2)
#set i -1
#set L [lrepeat $count 0]
#lmap v $L {lset L [incr i] [incr from -1];lindex {}}
#return $L
#3)
#set L {}
#for {set i 0} {$i < $count} {incr i} {
# lappend L [incr from -1]
#}
#return $L
} else {
return [list $from]
}
}
set count [expr {($to -$from) + 1}]
incr from -1
return [lmap v [lrepeat $count 0] {incr from}]
}
proc pdict {args} {
set argd [punk::args::get_dict {
*proc -name pdict -help {Print dict keys,values to channel
(see also showdict)}
*opts -any 1
#default separator to provide similarity to tcl's parray function
-separator -default " = "
-channel -default stdout -help "existing channel - or 'none' to return as string"
*values -min 1 -max -1
dictvar -type string -help "name of dict variable"
patterns -type string -default * -multiple 1
} $args]
set opts [dict get $argd opts]
set dvar [dict get $argd values dictvar]
set patterns [dict get $argd values patterns]
set dvalue [uplevel 1 [list set $dvar]]
showdict {*}$opts $dvalue {*}$patterns
}
proc showdict {args} { ;# analogous to parray (except that it takes the dict as a value)
set argd [punk::args::get_dict {
*id punk::lib::pdict
*proc -name punk::lib::pdict -help "display dictionary keys and values"
#todo - table tableobject
-return -default "tailtohead" -choices {tailtohead sidebyside}
-channel -default none
-trimright -default 1 -type boolean -help "Trim whitespace off rhs of each line.
This can help prevent a single long line that wraps in terminal from making every line wrap due to long rhs padding
"
-separator -default " " -help "Separator column between keys and values"
-ansibase_keys -default ""
-ansibase_values -default ""
-keysorttype -default "none" -choices {none dictionary ascii integer real}
-keysortdirection -default ascending -choices {ascending descending}
*values -min 1 -max -1
dictvalue -type dict -help "dict value"
patterns -default * -type string -multiple 1 -help "key or key glob pattern"
} $args]
set opt_sep [dict get $argd opts -separator]
set opt_keysorttype [dict get $argd opts -keysorttype]
set opt_keysortdirection [dict get $argd opts -keysortdirection]
set opt_trimright [dict get $argd opts -trimright]
set opt_ansibase_key [dict get $argd opts -ansibase_keys]
set opt_ansibase_value [dict get $argd opts -ansibase_values]
set opt_return [dict get $argd opts -return]
set dval [dict get $argd values dictvalue]
set patterns [dict get $argd values patterns]
set result ""
set filtered_keys [list]
foreach p $patterns {
lappend filtered_keys {*}[dict keys $dval $p]
}
if {$opt_keysorttype eq "none"} {
#we can only get duplicate keys if there are multiple patterns supplied
#ignore keysortdirection - doesn't apply
if {[llength $patterns] > 1} {
#order-maintaining (order of keys as they appear in dict)
set filtered_keys [punk::lib::lunique $filtered_keys]
}
} else {
set filtered_keys [lsort -unique -$opt_keysorttype $opt_keysortdirection $filtered_keys]
}
if {[llength $filtered_keys]} {
#both keys and values could have newline characters.
#simple use of 'format' won't cut it for more complex dict keys/values
#use block::width or our columns won't align in some cases
set maxl [::tcl::mathfunc::max {*}[lmap v $filtered_keys {textblock::width $v}]]
set RST [a]
switch -- $opt_return {
"tailtohead" {
#last line of key is side by side (possibly with separator) with first line of value
#This is more intelligible when terminal wrapping occurs - and is closer to what happens with parray multiline keys and values
#we still pad the key to max width so that the separator appears in the same column - which in the case of wide keys could cause that to wrap for all entries
foreach key $filtered_keys {
lassign [textblock::size $key] _kw kwidth _kh kheight
lassign [textblock::size [dict get $dval $key]] _vw vwidth _vh vheight
set totalheight [expr {$kheight + $vheight -1}]
set blanks_above [string repeat \n [expr {$kheight -1}]]
set blanks_below [string repeat \n [expr {$vheight -1}]]
set sepwidth [textblock::width $opt_sep]
#append result [textblock::pad $opt_ansibase_key$key$RST -width $maxl] $opt_sep $opt_ansibase_value[dict get $dval $key]$RST \n
set kblock [textblock::pad $opt_ansibase_key$key$RST$blanks_below -width $maxl]
set sblock [textblock::pad $blanks_above$opt_sep$blanks_below -width $sepwidth]
set vblock $blanks_above$opt_ansibase_value[dict get $dval $key]$RST
#only vblock is ragged - we can do a basic join because we don't care about rhs whitespace
append result [textblock::join_basic $kblock $sblock $vblock] \n
}
}
"sidebyside" {
#This is nice for multiline keys and values of reasonable length, will produce unintuitive results when line-wrapping occurs.
#use ansibase_key etc to make the output more comprehensible in that situation.
#This is why it is not the default. (review - terminal width detection and wrapping?)
foreach key $filtered_keys {
#append result [format "%-*s = %s" $maxl $key [dict get $dval $key]] \n
#differing height blocks (ie ragged) so we need a full textblock::join rather than join_basic
append result [textblock::join -- [textblock::pad $opt_ansibase_key$key$RST -width $maxl] $opt_sep "$opt_ansibase_value[dict get $dval $key]$RST"] \n
}
}
}
}
if {$opt_trimright} {
set result [::join [lines_as_list -line trimright $result] \n]
}
if {[string last \n $result] == [string length $result]-1} {
set result [string range $result 0 end-1]
}
#stdout/stderr can exist but not be in 'chan names' (e.g when transforms in place)
set chan [dict get $argd opts -channel]
switch -- $chan {
stderr - stdout {
puts $chan $result
}
none {
return $result
}
default {
#review - check member of chan names?
#just try outputting to the supplied channel for now
puts $chan $result
}
}
}
proc is_list_all_in_list {small large} {
package require struct::list
package require struct::set
@ -356,7 +533,87 @@ namespace eval punk::lib {
return [expr {[llength $i] == 0}]
}
#somewhat like struct::set difference - but order preserving, and doesn't treat as a 'set' so preserves dupes in fromlist
#struct::set difference may happen to preserve ordering when items are integers, but order can't be relied on,
# especially as struct::set has 2 differing implementations (tcl vs critcl) which return results with different ordering to each other and different deduping behaviour in some cases (e.g empty 2nd arg)
proc ldiff {fromlist removeitems} {
if {[llength $removeitems] == 0} {return $fromlist}
set result {}
foreach item $fromlist {
if {$item ni $removeitems} {
lappend result $item
}
}
return $result
}
proc ldiff2 {fromlist removeitems} {
set doomed [list]
foreach item $removeitems {
lappend doomed {*}[lsearch -all -exact $fromlist $item]
}
lremove $fromlist {*}$doomed
}
#non-dupe preserving - for consistency in dedupe behaviour we don't shortcircuit empty B
#consistent dedupe and order-maintenance of remaining items in A differentiate this from struct::set difference
#also struct::set difference with critcl is faster
proc setdiff {A B} {
if {[llength $A] == 0} {return {}}
set d [dict create]
foreach x $A {dict set d $x {}}
foreach x $B {dict unset d $x}
return [dict keys $d]
}
#bulk dict remove is slower than a foreach with dict unset
#proc setdiff2 {fromlist removeitems} {
# #if {[llength $fromlist] == 0} {return {}}
# set d [dict create]
# foreach x $fromlist {
# dict set d $x {}
# }
# return [dict keys [dict remove $d {*}$removeitems]]
#}
#array is about 15% faster than dict - but unordered. (which is ok for sets - but we have struct::set for that)
proc setdiff_unordered {A B} {
if {[llength $A] == 0} {return {}}
array set tmp {}
foreach x $A {::set tmp($x) .}
foreach x $B {catch {unset tmp($x)}}
return [array names tmp]
}
package require struct::set
if {[struct::set equal [struct::set union {a a} {}] {a}]} {
proc lunique_unordered {list} {
struct::set union $list {}
}
} else {
puts stderr "WARNING: struct::set union <list> <emptylist> no longer dedupes!"
#we could also test a sequence of: struct::set add
proc lunique_unordered {list} {
tailcall lunique $list
}
}
#order-preserving
proc lunique {list} {
set new {}
foreach item $list {
if {$item ni $new} {
lappend new $item
}
}
return $new
}
proc lunique2 {list} {
set doomed [list]
#expr 'in' probably faster than using a dict - for lists approx < 20,000 items. (wiki wisdom - url?)
for {set i 0} {$i < [llength $list]} {} {
set item [lindex $list $i]
lappend doomed {*}[lrange [lsearch -all -exact -start $i $list $item] 1 end]
while {[incr i] in $doomed} {}
}
lremove $list {*}$doomed
}
#The closure-like behaviour is *very* slow especially when called from a context such as the global namespace with lots of vars and large arrays such as ::env
proc lmapflat_closure {varnames list script} {
set result [list]
@ -368,29 +625,29 @@ namespace eval punk::lib {
#capture - use uplevel 1 or namespace eval depending on context
set capture [uplevel 1 {
apply { varnames {
set capturevars [dict create]
set capturearrs [dict create]
set capturevars [tcl::dict::create]
set capturearrs [tcl::dict::create]
foreach fullv $varnames {
set v [namespace tail $fullv]
set v [tcl::namespace::tail $fullv]
upvar 1 $v var
if {[info exists var]} {
if {(![array exists var])} {
dict set capturevars $v $var
tcl::dict::set capturevars $v $var
} else {
dict set capturearrs capturedarray_$v [array get var]
tcl::dict::set capturearrs capturedarray_$v [array get var]
}
} else {
#A variable can show in the results for 'info vars' but still not 'exist'. e.g a 'variable x' declaration in the namespace where the variable has never been set
}
}
return [dict create vars $capturevars arrs $capturearrs]
return [tcl::dict::create vars $capturevars arrs $capturearrs]
} } [info vars]
} ]
# -- --- ---
set cvars [dict get $capture vars]
set carrs [dict get $capture arrs]
set cvars [tcl::dict::get $capture vars]
set carrs [tcl::dict::get $capture arrs]
set apply_script ""
foreach arrayalias [dict keys $carrs] {
foreach arrayalias [tcl::dict::keys $carrs] {
set realname [string range $arrayalias [string first _ $arrayalias]+1 end]
append apply_script [string map [list %realname% $realname %arrayalias% $arrayalias] {
array set %realname% [set %arrayalias%][unset %arrayalias%]
@ -409,9 +666,9 @@ namespace eval punk::lib {
foreach $varnames $list {
lappend result {*}[apply\
[list\
[concat $varnames [dict keys $cvars] [dict keys $carrs] ]\
[concat $varnames [tcl::dict::keys $cvars] [tcl::dict::keys $carrs] ]\
$apply_script\
] {*}[subst $values] {*}[dict values $cvars] {*}[dict values $carrs] ]
] {*}[subst $values] {*}[tcl::dict::values $cvars] {*}[tcl::dict::values $carrs] ]
}
return $result
}
@ -447,8 +704,15 @@ namespace eval punk::lib {
return $result
}
proc lmapflat {varnames list script} {
concat {*}[uplevel 1 [list lmap $varnames $list $script]]
#proc lmapflat {varnames list script} {
# concat {*}[uplevel 1 [list lmap $varnames $list $script]]
#}
#lmap can accept multiple var list pairs
proc lmapflat {args} {
concat {*}[uplevel 1 [list lmap {*}$args]]
}
proc lmapflat2 {args} {
concat {*}[uplevel 1 lmap {*}$args]
}
proc dict_getdef {dictValue args} {
@ -456,8 +720,8 @@ namespace eval punk::lib {
error {wrong # args: should be "dict_getdef dictValue ?key ...? key default"}
}
set keys [lrange $args -1 end-1]
if {[dict exists $dictValue {*}$keys]} {
return [dict get $dictValue {*}$keys]
if {[tcl::dict::exists $dictValue {*}$keys]} {
return [tcl::dict::get $dictValue {*}$keys]
} else {
return [lindex $args end]
}
@ -475,6 +739,23 @@ namespace eval punk::lib {
# return "ok"
#}
#supports *safe* ultra basic offset expressions as used by lindex etc, but without the 'end' features
#safe in that we don't evaluate the expression as a string.
proc offset_expr {expression} {
set expression [tcl::string::map {_ {}} $expression]
if {[tcl::string::is integer -strict $expression]} {
return [expr {$expression}]
}
if {[regexp {(.*)([+-])(.*)} $expression _match a op b] && [tcl::string::is integer -strict $a] && [tcl::string::is integer -strict $b]} {
if {$op eq "-"} {
return [expr {$a - $b}]
} else {
return [expr {$a + $b}]
}
} else {
error "bad expression '$expression': must be integer?\[+-\]integer?"
}
}
proc lindex_resolve {list index} {
#*** !doctools
@ -492,7 +773,7 @@ namespace eval punk::lib {
if {![llength $list]} {
return -1
}
set index [string map [list _ ""] $index] ;#forward compatibility with integers such as 1_000
set index [tcl::string::map {_ {}} $index] ;#forward compatibility with integers such as 1_000
if {[string is integer -strict $index]} {
#can match +i -i
if {$index < 0} {
@ -566,7 +847,7 @@ namespace eval punk::lib {
} else {
#we still don't know the actual integer index for an index such as end-x or int-int without parsing and evaluating ourself.
#we can return the value - but only in a way that won't collide with our -1 out-of-range indicator
return [dict create value [lindex $resultlist 0]]
return [tcl::dict::create value [lindex $resultlist 0]]
}
}
@ -661,17 +942,17 @@ namespace eval punk::lib {
if {[llength $argopts]%2 !=0} {
error "[namespace current]::hex2dec arguments prior to list_largeHex must be option/value pairs - received '$argopts'"
}
set opts [dict create\
set opts [tcl::dict::create\
-validate 1\
-empty_as_hex "INVALID set -empty_as_hex to a hex string e.g FF if empty values should be replaced"\
]
set known_opts [dict keys $opts]
set known_opts [tcl::dict::keys $opts]
foreach {k v} $argopts {
dict set opts [tcl::prefix match -message "options for hex2dec. Unexpected option" $known_opts $k] $v
tcl::dict::set opts [tcl::prefix match -message "options for hex2dec. Unexpected option" $known_opts $k] $v
}
# -- --- --- ---
set opt_validate [dict get $opts -validate]
set opt_empty [dict get $opts -empty_as_hex]
set opt_validate [tcl::dict::get $opts -validate]
set opt_empty [tcl::dict::get $opts -empty_as_hex]
# -- --- --- ---
set list_largeHex [lmap h $list_largeHex[unset list_largeHex] {string map [list _ ""] [string trim $h]}]
@ -710,21 +991,21 @@ namespace eval punk::lib {
if {[llength $argopts]%2 !=0} {
error "[namespace current]::dec2hex arguments prior to list_decimals must be option/value pairs - received '$argopts'"
}
set defaults [dict create\
set defaults [tcl::dict::create\
-width 1\
-case upper\
-empty_as_decimal "INVALID set -empty_as_decimal to a number if empty values should be replaced"\
]
set known_opts [dict keys $defaults]
set fullopts [dict create]
set known_opts [tcl::dict::keys $defaults]
set fullopts [tcl::dict::create]
foreach {k v} $argopts {
dict set fullopts [tcl::prefix match -message "options for [namespace current]::dec2hex. Unexpected option" $known_opts $k] $v
tcl::dict::set fullopts [tcl::prefix match -message "options for [tcl::namespace::current]::dec2hex. Unexpected option" $known_opts $k] $v
}
set opts [dict merge $defaults $fullopts]
set opts [tcl::dict::merge $defaults $fullopts]
# -- --- --- ---
set opt_width [dict get $opts -width]
set opt_case [dict get $opts -case]
set opt_empty [dict get $opts -empty_as_decimal]
set opt_width [tcl::dict::get $opts -width]
set opt_case [tcl::dict::get $opts -case]
set opt_empty [tcl::dict::get $opts -empty_as_decimal]
# -- --- --- ---
@ -933,35 +1214,35 @@ namespace eval punk::lib {
proc sieve n {
set primes [list]
if {$n < 2} {return $primes}
set nums [dict create]
set nums [tcl::dict::create]
for {set i 2} {$i <= $n} {incr i} {
dict set nums $i ""
tcl::dict::set nums $i ""
}
set next 2
set limit [expr {sqrt($n)}]
while {$next <= $limit} {
for {set i $next} {$i <= $n} {incr i $next} {dict unset nums $i}
for {set i $next} {$i <= $n} {incr i $next} {tcl::dict::unset nums $i}
lappend primes $next
dict for {next -} $nums break
tcl::dict::for {next -} $nums break
}
return [concat $primes [dict keys $nums]]
return [concat $primes [tcl::dict::keys $nums]]
}
proc sieve2 n {
set primes [list]
if {$n < 2} {return $primes}
set nums [dict create]
set nums [tcl::dict::create]
for {set i 2} {$i <= $n} {incr i} {
dict set nums $i ""
tcl::dict::set nums $i ""
}
set next 2
set limit [expr {sqrt($n)}]
while {$next <= $limit} {
for {set i $next} {$i <= $n} {incr i $next} {dict unset nums $i}
for {set i $next} {$i <= $n} {incr i $next} {tcl::dict::unset nums $i}
lappend primes $next
#dict for {next -} $nums break
set next [lindex $nums 0]
}
return [concat $primes [dict keys $nums]]
return [concat $primes [tcl::dict::keys $nums]]
}
proc hasglobs {str} {
@ -1002,7 +1283,7 @@ namespace eval punk::lib {
#[para]This function merges the two dicts whilst maintaining the key order of main followed by defaults.
#1st merge (inner merge) with wrong values taking precedence - but right key-order - then (outer merge) restore values
return [dict merge [dict merge $main $defaults] $main]
return [tcl::dict::merge [tcl::dict::merge $main $defaults] $main]
}
proc askuser {question} {
@ -1044,7 +1325,7 @@ namespace eval punk::lib {
set answer [gets stdin]
}
} finally {
fconfigure stdin -blocking [dict get $stdin_state -blocking]
fconfigure stdin -blocking [tcl::dict::get $stdin_state -blocking]
}
return $answer
}
@ -1162,13 +1443,13 @@ namespace eval punk::lib {
}
proc list_as_lines2 {args} {
#eat or own dogfood version - shows the implementation is simpler - but unfortunately not suitable for a simple function like this which should be as fast as possible?
lassign [dict values [punk::args::get_dict {
lassign [tcl::dict::values [punk::args::get_dict {
-joinchar -default \n
*values -min 1 -max 1
} $args]] opts values
puts "opts:$opts"
puts "values:$values"
return [join [dict get $values 0] [dict get $opts -joinchar]]
return [join [tcl::dict::get $values 0] [tcl::dict::get $opts -joinchar]]
}
proc lines_as_list {args} {
@ -1189,7 +1470,7 @@ namespace eval punk::lib {
} else {
set opts [lrange $args 0 end-1]
}
#set opts [dict merge {-block {}} $opts]
#set opts [tcl::dict::merge {-block {}} $opts]
set bposn [lsearch $opts -block]
if {$bposn < 0} {
lappend opts -block {}
@ -1203,11 +1484,11 @@ namespace eval punk::lib {
#-anyopts 1 avoids having to know what to say if odd numbers of options passed etc
#we don't have to decide what is an opt vs a value
#even if the caller provides the argument -block without a value the next function's validation will report a reasonable error because there is now nothing in $values (consumed by -block)
lassign [dict values [punk::args::get_dict {
lassign [tcl::dict::values [punk::args::get_dict {
*opts -any 1
-block -default {}
} $args]] opts valuedict
tailcall linelist {*}$opts {*}[dict values $valuedict]
tailcall linelist {*}$opts {*}[tcl::dict::values $valuedict]
}
# important for pipeline & match_assign
@ -1222,7 +1503,7 @@ namespace eval punk::lib {
set text [string map [list \r\n \n] $text] ;#review - option?
set arglist [lrange $args 0 end-1]
set opts [dict create\
set opts [tcl::dict::create\
-block {trimhead1 trimtail1}\
-line {}\
-commandprefix ""\
@ -1232,7 +1513,7 @@ namespace eval punk::lib {
foreach {o v} $arglist {
switch -- $o {
-block - -line - -commandprefix - -ansiresets - -ansireplays {
dict set opts $o $v
tcl::dict::set opts $o $v
}
default {
error "linelist: Unrecognized option '$o' usage:$usage"
@ -1240,7 +1521,7 @@ namespace eval punk::lib {
}
}
# -- --- --- --- --- ---
set opt_block [dict get $opts -block]
set opt_block [tcl::dict::get $opts -block]
if {[llength $opt_block]} {
foreach bo $opt_block {
switch -- $bo {
@ -1272,7 +1553,7 @@ namespace eval punk::lib {
# -- --- --- --- --- ---
set opt_line [dict get $opts -line]
set opt_line [tcl::dict::get $opts -line]
set tl_left 0
set tl_right 0
set tl_both 0
@ -1299,11 +1580,11 @@ namespace eval punk::lib {
set tl_both 1
}
# -- --- --- --- --- ---
set opt_commandprefix [dict get $opts -commandprefix]
set opt_commandprefix [tcl::dict::get $opts -commandprefix]
# -- --- --- --- --- ---
set opt_ansiresets [dict get $opts -ansiresets]
set opt_ansiresets [tcl::dict::get $opts -ansiresets]
# -- --- --- --- --- ---
set opt_ansireplays [dict get $opts -ansireplays]
set opt_ansireplays [tcl::dict::get $opts -ansireplays]
if {$opt_ansireplays} {
if {$opt_ansiresets eq "auto"} {
set opt_ansiresets 1
@ -1414,7 +1695,11 @@ namespace eval punk::lib {
set replaycodes $RST ;#todo - default?
set transformed [list]
#shortcircuit common case of no ansi
if {![punk::ansi::ta::detect $linelist]} {
#NOTE: running ta::detect on a list (or dict) as a whole can be problematic if items in the have backslash escapes due to Tcl list quoting and escaping behaviour.
#This commonly happens if there is an unbalanced brace (which is a normal occurrence and needs to be handled)
#ta::detect on a list of ansi-containing string may appear to work for some simple inputs but is not reliable
#detect_in_list will check at first level. (not intended for detecting ansi in deeper structures)
if {![punk::ansi::ta::detect_in_list $linelist]} {
if {$opt_ansiresets} {
foreach ln $linelist {
lappend transformed $RST$ln$RST
@ -1604,8 +1889,29 @@ namespace eval punk::lib {
}
#we are interested in seeing jumpTable line and following lines up until next line starting with "Command" or bracketed number e.g (164)
proc show_jump_tables {procname} {
set data [tcl::unsupported::disassemble proc $procname]
proc show_jump_tables {args} {
#avoiding use of 'info cmdtype' as unavaliable in safe interps as at 2024-06.
if {[llength $args] == 1} {
set data [tcl::unsupported::disassemble proc [lindex $args 0]]
} elseif {[llength $args] == 2} {
#review - this looks for direct methods on the supplied object/class, and then tries to disassemble method on the supplied class or class of supplied object if it isn't a class itself.
#not sure if this handles more complex hierarchies or mixins etc.
lassign $args obj method
if {![info object isa object $obj]} {
error "show_jump_tables unable to examine '$args'. $obj is not an oo object"
}
#classes are objects too and can have direct methods
if {$method in [info object methods $obj]} {
set data [tcl::unsupported::disassemble objmethod $obj $method]
} else {
if {![info object isa class $obj]} {
set obj [info object class $obj]
}
set data [tcl::unsupported::disassemble method $obj $method]
}
} else {
error "show_jump_tables expected a procname or a class/object and method"
}
set result ""
set in_jt 0
foreach ln [split $data \n] {
@ -1626,6 +1932,12 @@ namespace eval punk::lib {
return $result
}
proc temperature_f_to_c {deg_fahrenheit} {
return [expr {($deg_fahrenheit -32) * (5/9.0)}]
}
proc temperature_c_to_f {deg_celsius} {
return [expr {($deg_celsius * (9/5.0)) + 32}]
}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::lib ---}]
}
@ -1639,7 +1951,7 @@ namespace eval punk::lib {
#todo - way to generate 'internal' docs separately?
#*** !doctools
#[section Internal]
namespace eval punk::lib::system {
tcl::namespace::eval punk::lib::system {
#*** !doctools
#[subsection {Namespace punk::lib::system}]
#[para] Internal functions that are not part of the API
@ -1664,6 +1976,51 @@ namespace eval punk::lib::system {
return false
}
}
proc has_safeinterp_compile_bug {{show 0}} {
#ensemble calls within safe interp not compiled
namespace eval [namespace current]::testcompile {
proc ensembletest {} {string index a 0}
}
set has_bug 0
set bytecode_outer [tcl::unsupported::disassemble proc [namespace current]::testcompile::ensembletest]
if {$show} {
puts outer:
puts $bytecode_outer
}
if {![interp issafe]} {
#test of safe subinterp only needed if we aren't already in a safe interp
if {![catch {
interp create x -safe
} errMsg]} {
x eval {proc ensembletest {} {string index a 0}}
set bytecode_safe [x eval {tcl::unsupported::disassemble proc ::ensembletest}]
if {$show} {
puts safe:
puts $bytecode_safe
}
interp delete x
#mainly we expect the safe interp might contain invokeStk - indicating not byte compiled (or we would see strindex instead)
#It's possible the interp we're running in is also not compiling ensembles.
#we could then get a result of 2 - which still indicates a problem
if {[string last "invokeStk" $bytecode_safe] >= 1} {
incr has_bug
}
} else {
#our failure to create a safe interp here doesn't necessarily mean the Tcl version doesn't have the problem - but we could end up returning zero if somehow safe interp can't be created from unsafe interp?
#unlikely - but we should warn
puts stderr "Unable to create a safe sub-interp to test - result only indicates status of current interpreter"
}
}
namespace delete [namespace current]::testcompile
if {[string last "invokeStk" $bytecode_outer] >= 1} {
incr has_bug
}
return $has_bug
}
proc mostFactorsBelow {n} {
##*** !doctools
@ -1888,7 +2245,7 @@ namespace eval punk::lib::system {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::lib [namespace eval punk::lib {
package provide punk::lib [tcl::namespace::eval punk::lib {
variable pkg punk::lib
variable version
set version 0.1.1

34
src/bootsupport/modules/punk/mix-0.2.tm

@ -1,25 +1,31 @@
package require punk::cap
package require punk::cap::handlers::templates ;#handler for templates cap
punk::cap::register_capabilityname punk.templates ::punk::cap::handlers::templates
package require punk::mix::templates ;#registers as provider pkg for 'punk.templates' capability with punk::cap
if {[catch {punk::mix::templates::provider register *} errM]} {
puts stderr "punk::mix failure during punk::mix::templates::provider register *"
puts stderr $errM
puts stderr "-----"
puts stderr $::errorInfo
tcl::namespace::eval punk::mix {
proc init {} {
package require punk::cap::handlers::templates ;#handler for templates cap
punk::cap::register_capabilityname punk.templates ::punk::cap::handlers::templates ;#time taken should generally be sub 200us
package require punk::mix::templates ;#registers as provider pkg for 'punk.templates' capability with punk::cap
set t [time {
if {[catch {punk::mix::templates::provider register *} errM]} {
puts stderr "punk::mix failure during punk::mix::templates::provider register *"
puts stderr $errM
puts stderr "-----"
puts stderr $::errorInfo
}
}]
puts stderr "->punk::mix::templates::provider register * t=$t"
}
init
}
package require punk::mix::base
package require punk::mix::cli
namespace eval punk::mix {
}
package provide punk::mix [namespace eval punk::mix {
package provide punk::mix [tcl::namespace::eval punk::mix {
variable version
set version 0.2

7
src/bootsupport/modules/punk/mix/base-0.1.tm

@ -394,7 +394,7 @@ namespace eval punk::mix::base {
proc module_subpath {modulename} {
set modulename [string trim $modulename :]
set nsq [namespace qualifiers $modulename]
return [string map [list :: /] $nsq]
return [string map {:: /} $nsq]
}
proc get_build_workdir {path} {
@ -420,8 +420,11 @@ namespace eval punk::mix::base {
}
#not just used by cksum_path. used by caller (e.g fill_relativecksums_from_base_and_relativepathdict via cksum_filter_opts) to determine what opt names passed through
variable cksum_default_opts
set cksum_default_opts [dict create -cksum_content 1 -cksum_meta auto -cksum_acls 0 -cksum_usetar auto -cksum_algorithm sha1]
proc cksum_default_opts {} {
return [dict create -cksum_content 1 -cksum_meta auto -cksum_acls 0 -cksum_usetar auto -cksum_algorithm sha1]
variable cksum_default_opts
return $cksum_default_opts
}
#crc::cksum is extremely slow in tcllib as at 2023 e.g 20x slower (no c implementation?)

9
src/bootsupport/modules/punk/mix/cli-0.3.tm

@ -123,8 +123,9 @@ namespace eval punk::mix::cli {
}
#review - why can't we be anywhere in the project?
#also - if no make.tcl - can we use the running shell's make.tcl ? (after prompting user?)
if {([file tail $sourcefolder] ne "src") || (![file exists $sourcefolder/make.tcl])} {
puts stderr "deck make must be run from src folder containing make.tcl - unable to proceed (cwd: [pwd])"
puts stderr "dev make must be run from src folder containing make.tcl - unable to proceed (cwd: [pwd])"
if {[string length $project_base]} {
if {[file exists $project_base/src] && [string tolower [pwd]] ne [string tolower $project_base/src]} {
puts stderr "Try cd to $project_base/src"
@ -224,7 +225,7 @@ namespace eval punk::mix::cli {
# -- --- --- --- --- --- --- --- --- --- --- --- --- ---
validate_name_not_empty_or_spaced $modulename -errorprefix $opt_errorprefix
set testname [string map [list :: ""] $modulename]
set testname [string map {:: {}} $modulename]
if {[string first : $testname] >=0} {
error "$opt_errorprefix '$modulename' can only contain paired colons"
}
@ -366,13 +367,13 @@ namespace eval punk::mix::cli {
if {"project" in $repotypes} {
#punk project
if {![catch {package require textblock; package require patternpunk}]} {
set result [textblock::join [>punk . logo] " " $result]
set result [textblock::join -- [>punk . logo] " " $result]
append result \n
}
}
set timeline [exec fossil timeline -n 5 -t ci]
set timeline [string map [list \r\n \n] $timeline]
set timeline [string map {\r\n \n} $timeline]
append result $timeline
if {$opt_v} {
set repostate [punk::repo::workingdir_state $repopath -repopaths $repopaths -repotypes fossil]

14
src/bootsupport/modules/punk/mix/commandset/layout-0.1.0.tm

@ -31,7 +31,12 @@ namespace eval punk::mix::commandset::layout {
#per layout functions
proc files {layout} {
proc files {{layout ""}} {
set argd [punk::args::get_dict {
*values -min 1 -max 1
layout -type string -minlen 1
} [list $layout]]
set allfiles [lib::layout_all_files $layout]
return [join $allfiles \n]
}
@ -77,6 +82,13 @@ namespace eval punk::mix::commandset::layout {
}
proc _default {args} {
punk::args::get_dict [subst {
*proc -name ::punk::mix::commandset::layout::collection::_default
-startdir -type string
-not -type string -multiple 1
globsearches -default * -multiple 1
}] $args
set tdict_low_to_high [as_dict {*}$args]
#convert to screen order - with higher priority at the top
set tdict [dict create]

93
src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm

@ -26,33 +26,102 @@ package require punk::lib
namespace eval punk::mix::commandset::loadedlib {
namespace export *
#search automatically wrapped in * * - can contain inner * ? globs
proc search {searchstring} {
proc search {args} {
set argspecs {
*proc -name "punk::mix::commandset::loadedlib search" -help "search all Tcl libraries available to your local interpreter"
-return -type string -default table -choices {table tableobject list lines}
-present -type integer -default 2 -choices {0 1 2} -choicelabels {absent present both} -help "(unimplemented) Display only those that are 0:absent 1:present 2:both"
-highlight -type boolean -default 1 -help "Highlight which version is present with ansi underline and colour"
-refresh -default 0 -type boolean -help "Re-scan the tm and library folders"
searchstrings -default * -multiple 1 -help "Names to search for, may contain glob chars (* ?) e.g *lib*
If no glob chars are explicitly specified, the searchstring will be wrapped with star globs.
eg name -> *name*
"
}
set argd [punk::args::get_dict $argspecs $args]
set searchstrings [dict get $argd values searchstrings]
set opts [dict get $argd opts]
set opt_return [dict get $opts -return]
set opt_highlight [dict get $opts -highlight]
catch {package require frobznodule666} ;#ensure pkg system has loaded/searched for everything
if {[catch {package require natsort}]} {
set has_natsort 0
} else {
set has_natsort 1
}
if {[regexp {[?*]} $searchstring]} {
#caller has specified specific glob pattern - use it
#todo - respect supplied case only if uppers present? require another flag?
set matches [lsearch -all -inline -nocase [package names] $searchstring]
} else {
#make it easy to search for anything
set matches [lsearch -all -inline -nocase [package names] "*$searchstring*"]
set packages [package names]
set matches [list]
foreach search $searchstrings {
if {[regexp {[?*]} $search]} {
#caller has specified specific glob pattern - use it
#todo - respect supplied case only if uppers present? require another flag?
lappend matches {*}[lsearch -all -inline -nocase $packages $search]
} elseif {[string match =* $search]} {
lappend matches {*}[lsearch -all -inline -exact $packages [string range $search 1 end]]
} else {
#make it easy to search for anything
lappend matches {*}[lsearch -all -inline -nocase $packages "*$search*"]
}
}
set matches [lsort -unique $matches][unset matches]
set matchinfo [list]
set highlight_ansi [a+ web-limegreen underline]
set RST [a]
foreach m $matches {
set versions [package versions $m]
if {![llength $versions]} {
#e.g builtins such as zlib - shows no versions - but will show version when package present/provide used
set versions [package provide $m]
#if {![catch {package present $m} v]} {
# set versions $v
#}
}
if {$has_natsort} {
set versions [natsort::sort $versions]
} else {
set versions [lsort $versions]
}
if {$opt_highlight} {
set v [package provide $m]
if {$v ne ""} {
set posn [lsearch $versions $v]
if {$posn >= 0} {
#FIXME! (probably in textblock::pad ?)
#TODO - determine why underline is extended to padding even with double reset. (space or other char required to prevent)
set highlighted "$highlight_ansi$v$RST $RST"
set versions [lreplace $versions $posn $posn $highlighted]
} else {
#shouldn't be possible?
puts stderr "failed to find version '$v' in versions:$versions for package $m"
}
}
}
lappend matchinfo [list $m $versions]
}
return [join [lsort $matchinfo] \n]
switch -- $opt_return {
list {
return $matchinfo
}
lines {
return [join $matchinfo \n]
}
table - tableobject {
set t [textblock::class::table new]
$t add_column -headers "Package"
$t add_column -headers "Version"
$t configure -show_hseps 0
foreach m $matchinfo {
$t add_row [list [lindex $m 0] [join [lindex $m 1] " "]]
}
if {$opt_return eq "tableobject"} {
return $t
}
set result [$t print]
$t destroy
return $result
}
}
}
proc loaded.search {searchstring} {
set search_result [search $searchstring]
@ -251,7 +320,7 @@ namespace eval punk::mix::commandset::loadedlib {
}
set loadinfo [package ifneeded $libfound $ver]
set loadinfo [string map [list \r\n \n] $loadinfo]
set loadinfo [string map {\r\n \n} $loadinfo]
set loadinfo_lines [split $loadinfo \n]
if {[catch {llength $loadinfo}]} {
set loadinfo_is_listshaped 0
@ -316,7 +385,7 @@ namespace eval punk::mix::commandset::loadedlib {
#we only follow one level of package require redirection - seems unlikely/imprudent to follow arbitrarily in a while loop(?)
set libfound $lib_diversion_name
set loadinfo [package ifneeded $libfound $ver]
set loadinfo [string map [list \r\n \n] $loadinfo]
set loadinfo [string map {\r\n \n} $loadinfo]
set loadinfo_lines [split $loadinfo \n]
if {[catch {llength $loadinfo}]} {
set loadinfo_is_listshaped 0

46
src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm

@ -111,7 +111,7 @@ namespace eval punk::mix::commandset::module {
set tablewidth [expr {$widest(name) + 1 + $widest(pathtype) + 1 + $widest(name)}]
set table ""
append table [string repeat - $tablewidth] \n
append table "[textblock::join [overtype::left $col(name) $title(name)] " " [overtype::left $col(pathtype) $title(pathtype)] " " [overtype::left $col(path) $title(path)]]" \n
append table "[textblock::join -- [overtype::left $col(name) $title(name)] " " [overtype::left $col(pathtype) $title(pathtype)] " " [overtype::left $col(path) $title(path)]]" \n
append table [string repeat - $tablewidth] \n
foreach n $names pt $pathtypes p $paths {
@ -122,6 +122,14 @@ namespace eval punk::mix::commandset::module {
}
#return all module templates with repeated ones suffixed with .2 .3 etc
proc templates_dict {args} {
set argspec {
*proc -name templates_dict -help "Templates from module and project paths"
-startdir -default "" -help "Project folder used in addition to module paths"
-not -default "" -multiple 1
*values
globsearches -default * -multiple 1
}
set argd [punk::args::get_dict $argspec $args]
package require punk::cap
if {[punk::cap::capability_has_handler punk.templates]} {
set template_folder_dict [punk::cap::call_handler punk.templates get_itemdict_moduletemplates {*}$args]
@ -129,18 +137,26 @@ namespace eval punk::mix::commandset::module {
put stderr "get_template_basefolders WARNING - no handler available for the 'punk.templates' capability - template providers will be unable to provide template locations"
}
}
proc new {module args} {
proc new {args} {
set year [clock format [clock seconds] -format %Y]
set defaults [list\
-project \uFFFF\
-version \uFFFF\
-license <unspecified>\
-template punk.module\
-type \uFFFF\
-force 0\
-quiet 0\
]
set opts [dict merge $defaults $args]
set moduletypes [punk::mix::cli::lib::module_types]
# use \uFFFD because unicode replacement char should consistently render as 1 wide
set argspecs [subst {
-project -default \uFFFD
-version -default \uFFFD
-license -default <unspecified>
-template -default punk.module
-type -default \uFFFD -choices {$moduletypes}
-force -default 0 -type boolean
-quiet -default 0 -type boolean
*values -min 1 -max 1
module -type string
}]
set argd [punk::args::get_dict $argspecs $args]
lassign [dict values $argd] opts values
set module [dict get $values module]
#set opts [dict merge $defaults $args]
#todo - review compatibility between -template and -type
#-type is the wrapping technology e.g 'plain' for none or tarjar/zipkit etc (consider also snappy/snappy-tcl)
@ -152,7 +168,7 @@ namespace eval punk::mix::commandset::module {
# we need this value before looking at the named argument
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_version_supplied [dict get $opts -version]
if {$opt_version_supplied eq "\uFFFF"} {
if {$opt_version_supplied eq "\uFFFD"} {
set opt_version "0.1.0"
} else {
set opt_version $opt_version_supplied
@ -178,7 +194,7 @@ namespace eval punk::mix::commandset::module {
} else {
set vmsg "from -version option: $opt_version_supplied"
}
if {$opt_version_supplied ne "\uFFFF"} {
if {$opt_version_supplied ne "\uFFFD"} {
if {$vcompare_is_mversion_bigger != 0} {
#is bigger or smaller
puts stderr "module.new WARNING: version supplied in module argument as well as -version option. Using the higher version number $vmsg"
@ -269,7 +285,7 @@ namespace eval punk::mix::commandset::module {
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_type [dict get $opts -type]
if {$opt_type eq "\uFFFF"} {
if {$opt_type eq "\uFFFD"} {
set opt_type [lindex [punk::mix::cli::lib::module_types] 0] ;#default to plain
}
if {$opt_type ni [punk::mix::cli::lib::module_types]} {

2
src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm

@ -73,7 +73,7 @@ namespace eval punk::mix::commandset::scriptwrap {
set tablewidth [expr {$widest(name) + 1 + $widest(pathtype) + $widest(path)}]
set table ""
append table [string repeat - $tablewidth] \n
append table [textblock::join [overtype::left $col(name) $title(name)] " " [overtype::left $col(pathtype) $title(pathtype)] " " [overtype::left $col(path) $title(path)]] \n
append table [textblock::join -- [overtype::left $col(name) $title(name)] " " [overtype::left $col(pathtype) $title(pathtype)] " " [overtype::left $col(path) $title(path)]] \n
append table [string repeat - $tablewidth] \n
foreach n $names pt $pathtypes p $paths {

2
src/bootsupport/modules/punk/mix/templates-0.1.0.tm

@ -59,7 +59,7 @@ namespace eval punk::mix::templates {
oo::objdefine provider {
method register {{capabilityname_glob *}} {
#puts registering punk::mix::templates $capabilityname
next
next $capabilityname_glob
}
method capabilities {} {
next

4
src/bootsupport/modules/punk/mix/templates/layouts/project/src/make.tcl

@ -281,7 +281,7 @@ if {$::punkmake::command eq "bootsupport"} {
foreach {relpath module} $bootsupport_modules {
set module [string trim $module :]
set module_subpath [string map [list :: /] [namespace qualifiers $module]]
set module_subpath [string map {:: /} [namespace qualifiers $module]]
set srclocation [file join $projectroot $relpath $module_subpath]
#puts stdout "$relpath $module $module_subpath $srclocation"
set pkgmatches [glob -nocomplain -dir $srclocation -tail [namespace tail $module]-*]
@ -617,7 +617,7 @@ if {[file exists $mapfile]} {
fconfigure $fdmap -translation binary
set mapdata [read $fdmap]
close $fdmap
set mapdata [string map [list \r\n \n] $mapdata]
set mapdata [string map {\r\n \n} $mapdata]
set missing [list]
foreach ln [split $mapdata \n] {
set ln [string trim $ln]

101
src/bootsupport/modules/punk/ns-0.1.0.tm

@ -20,12 +20,12 @@
package require punk::lib
package require punk::args
namespace eval ::punk_dynamic::ns {
tcl::namespace::eval ::punk_dynamic::ns {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::ns {
tcl::namespace::eval punk::ns {
variable ns_current "::"
variable ns_re_cache [dict create] ;#cache regular expressions used in globmatchns
namespace export nsjoin nsprefix nstail nsparts nseval nsimport_noclobber corp
@ -58,7 +58,7 @@ namespace eval punk::ns {
set has_globchars [regexp {[*?]} $ns_or_glob]
if {$is_absolute} {
if {!$has_globchars} {
if {![namespace exists $ns_or_glob]} {
if {![tcl::namespace::exists $ns_or_glob]} {
error "cannot change to namespace $ns_or_glob"
}
set ns_current $ns_or_glob
@ -71,7 +71,7 @@ namespace eval punk::ns {
} else {
if {!$has_globchars} {
set nsnext [nsjoin $ns_current $ns_or_glob]
if {![namespace exists $nsnext]} {
if {![tcl::namespace::exists $nsnext]} {
error "cannot change to namespace $ns_or_glob"
}
set ns_current $nsnext
@ -86,7 +86,7 @@ namespace eval punk::ns {
set ns_display "\n$ns_queried"
if {$ns_current eq $ns_queried} {
if {$ns_current in [info commands $ns_current] } {
if {![catch [list namespace ensemble configure $ns_current] ensemble_info]} {
if {![catch [list tcl::namespace::ensemble configure $ns_current] ensemble_info]} {
if {[llength $ensemble_info] > 0} {
#this namespace happens to match ensemble command.
#todo - keep cache of encountered ensembles from commands.. and examine namespace in the configure info.
@ -119,13 +119,13 @@ namespace eval punk::ns {
set nspath [nsjoinall $ns_current {*}$args]
}
set ns_exists [nseval [nsprefix $nspath] [list ::namespace exists [nstail $nspath] ]]
set ns_exists [nseval [nsprefix $nspath] [list ::tcl::namespace::exists [nstail $nspath] ]]
if {$ns_exists} {
error "Namespace $nspath already exists"
}
#namespace eval [nsprefix $nspath] [list namespace eval [nstail $nspath] {}]
nseval [nsprefix $nspath] [list ::namespace eval [nstail $nspath] {}]
#tcl::namespace::eval [nsprefix $nspath] [list tcl::namespace::eval [nstail $nspath] {}]
nseval [nsprefix $nspath] [list ::tcl::namespace::eval [nstail $nspath] {}]
n/ $nspath
}
@ -157,7 +157,7 @@ namespace eval punk::ns {
}
#recursive nseval - for introspection of weird namespace trees
#approx 10x slower than normal namespace eval - but still only a few microseconds.. fine for repl introspection
#approx 10x slower than normal tcl::namespace::eval - but still only a few microseconds.. fine for repl introspection
proc nseval_script {location} {
set parts [nsparts $location]
if {[lindex $parts 0] eq ""} {
@ -171,7 +171,7 @@ namespace eval punk::ns {
set i 0
set tails [lrepeat [llength $parts] ""]
foreach ns $parts {
set cmdlist [list ::namespace eval $ns]
set cmdlist [list ::tcl::namespace::eval $ns]
set t ""
if {$i > 0} {
append body " <lb>"
@ -194,7 +194,7 @@ namespace eval punk::ns {
set scr {[::list ::eval [::uplevel <i> {::set script}]]}
set up [expr {$i - 1}]
set scr [string map [list <i> $up] $scr]
set scr [string map "<i> $up" $scr]
set body [string map [list <script> $scr] $body]
return $body
@ -203,7 +203,7 @@ namespace eval punk::ns {
if {![string match ::* $fqns]} {
error "nseval only accepts a fully qualified namespace"
}
set loc [string map [list :: "_sep_"] $fqns]
set loc [string map {:: _sep_} $fqns]
#set cmd ::punk::pipecmds::nseval_$loc
set cmd ::punk_dynamic::ns::eval-$loc
if {$cmd ni [info commands $cmd]} {
@ -221,7 +221,7 @@ namespace eval punk::ns {
set tail [nstail $fqns]
#puts ">>> parent $parent tail $tail"
#set nslist [nseval $parent [list ::namespace children $tail]]
set nslist [namespace eval $parent [list ::namespace children $tail]]
set nslist [tcl::namespace::eval $parent [list ::tcl::namespace::children $tail]]
return [lsort $nslist]
}
@ -281,7 +281,7 @@ namespace eval punk::ns {
#
proc nsprefix {{nspath ""}} {
#normalize the common case of ::::
set nspath [string map [list :::: ::] $nspath]
set nspath [string map {:::: ::} $nspath]
set rawprefix [string range $nspath 0 end-[string length [nstail $nspath]]]
if {$rawprefix eq "::"} {
return $rawprefix
@ -299,8 +299,8 @@ namespace eval punk::ns {
#review - consider making -strict raise an error for unexpected sequences such as :::: or any situation with more than 2 colons together.
proc nstail {nspath args} {
#normalize the common case of ::::
set nspath [string map [list :::: ::] $nspath]
set mapped [string map [list :: \u0FFF] $nspath]
set nspath [string map {:::: ::} $nspath]
set mapped [string map {:: \u0FFF} $nspath]
set parts [split $mapped \u0FFF]
set defaults [list -strict 0]
@ -324,7 +324,7 @@ namespace eval punk::ns {
#Can be used to either support use of such namespaces/commands - or as part of validation to disallow them
#as opposed to silent behaviour of Tcl namespace commands which don't handle them consistently (for tcl 8.x anyway Review tcl 9)
#Note that for ::x:: the trailing :: cannot represent a trailing namespace part being an empty string
#This is because Tcl's 'namespace eval "" ""' reports 'only global namespace can have empty name'
#This is because Tcl's 'tcl::namespace::eval "" ""' reports 'only global namespace can have empty name'
#NOTE tcl allows creating ambiguous namespaces. e.g ::punk:::etc:::blah
# is this :: punk :etc :blah or :: punk :etc: blah
#clearly leading/trailing colons in namespaces and commands are just a bad idea.
@ -332,8 +332,8 @@ namespace eval punk::ns {
#This is important to support leading colon commands such as :/
# ie ::punk:::jjj:::etc -> :: punk :jjj :etc
proc nsparts {nspath} {
set nspath [string map [list :::: ::] $nspath]
set mapped [string map [list :: \u0FFF] $nspath]
set nspath [string map {:::: ::} $nspath]
set mapped [string map {:: \u0FFF} $nspath]
set parts [split $mapped \u0FFF]
if {[lindex $parts end] eq ""} {
@ -387,7 +387,8 @@ namespace eval punk::ns {
} elseif {$seg eq "**"} {
lappend pats {.*}
} else {
set seg [string map [list . {[.]}] $seg]
#set seg [string map [list . {[.]}] $seg]
set seg [string map {. [.]} $seg]
if {[regexp {[*?]} $seg]} {
set pat [string map [list ** {.*} * {[^:]*} ? {[^:]}] $seg]
lappend pats "$pat"
@ -469,14 +470,14 @@ namespace eval punk::ns {
set base $location
set tailparts $subnslist
}
if {![namespace exists $base]} {
if {![tcl::namespace::exists $base]} {
return [list]
}
#set parent [nsprefix $ns_absolute]
#set tail [nstail $ns_absolute]
#set allchildren [lsort [nseval $base [list ::namespace children]]]
set allchildren [lsort [namespace eval $base [list ::namespace children]]]
set allchildren [lsort [tcl::namespace::eval $base [list ::namespace children]]]
#puts "->base:$base tailparts:$tailparts allchildren: $allchildren"
#puts "->base:$base tailparts:$tailparts childcount: [llength $allchildren]"
@ -994,7 +995,19 @@ namespace eval punk::ns {
}
#info cmdtype available in 8.7+
#safe interps also seem to have it disabled for some reason
proc cmdtype {cmd} {
if {[interp issafe]} {
if {[catch {::tcl::info::cmdtype $cmd} result]} {
if {[info commands ::cmdtype] ne ""} {
#hack - look for an alias that may have been specifically enabled to bring this back
tailcall ::cmdtype $cmd
}
return na
} else {
return $result
}
}
if {[info commands ::tcl::info::cmdtype] ne ""} {
tailcall info cmdtype $cmd
}
@ -1072,8 +1085,8 @@ namespace eval punk::ns {
#JMN
set location $ch
set exportpatterns [namespace eval $location {::namespace export}]
set nspathlist [namespace eval $location {::namespace path}]
set exportpatterns [tcl::namespace::eval $location {::namespace export}]
set nspathlist [tcl::namespace::eval $location {::namespace path}]
set nspathdict [dict create]
if {$nspathcommands} {
foreach pathns $nspathlist {
@ -1092,7 +1105,7 @@ namespace eval punk::ns {
foreach p $exportpatterns {
if {[regexp {[*?]} $p]} {
#lappend matched {*}[nseval $location [list ::info commands [nsjoin ${location} $p]]]
lappend matched {*}[namespace eval $location [list ::info commands [nsjoin ${location} $p]]]
lappend matched {*}[tcl::namespace::eval $location [list ::info commands [nsjoin ${location} $p]]]
foreach m $matched {
lappend allexported [nstail $m]
}
@ -1101,8 +1114,8 @@ namespace eval punk::ns {
}
}
set allexported [lsort -unique $allexported]
#NOTE: info procs within namespace eval is different to 'info commands' within namespace eval (info procs doesn't look outside of namespace)
set allprocs [namespace eval $location {::info procs}]
#NOTE: info procs within tcl::namespace::eval is different to 'info commands' within tcl::namespace::eval (info procs doesn't look outside of namespace)
set allprocs [tcl::namespace::eval $location {::info procs}]
#set allprocs [nseval $location {::info procs}]
set childtails [lmap v $allchildren {nstail $v}]
set allaliases [list]
@ -1120,7 +1133,7 @@ namespace eval punk::ns {
set interp_aliases [interp aliases ""]
#use aliases glob - because aliases can be present with or without leading ::
#NOTE: alias may not have matching command in the relevant namespce (renamed alias) so we can't just start with commands and check if it's an alias if we want to show all aliases
set raw_aliases [namespace eval $location [list ::aliases $glob]] ;#'aliases $glob' must be passed as list, not separate args to namespace eval.
set raw_aliases [tcl::namespace::eval $location [list ::aliases $glob]] ;#'aliases $glob' must be passed as list, not separate args to namespace eval.
#set raw_aliases [nseval $location [list ::aliases $glob]] ;#'aliases $glob' must be passed as list, not separate args to namespace eval.
set aliases [list]
foreach a $raw_aliases {
@ -1363,8 +1376,8 @@ namespace eval punk::ns {
}
::set all_ns_commands [::info commands [::punk::ns::nsjoin $base $what]]
#important not to call namespace eval (or punk::ns::nseval) on non-existant base - or it will be created
::if {![::namespace exists $base]} {
#important not to call tcl::namespace::eval (or punk::ns::nseval) on non-existant base - or it will be created
::if {![::tcl::namespace::exists $base]} {
::continue
}
@ -1374,7 +1387,7 @@ namespace eval punk::ns {
#this was to support weird namespaces with leading/trailing colons - not an important usecase for the cost
::set matchedcommands [::pipeswitch {
::pipecase \
caseresult.= ::list $base $what |,basens/0,g/1> {namespace eval $basens [::list ::info commands $g]}
caseresult.= ::list $base $what |,basens/0,g/1> {tcl::namespace::eval $basens [::list ::info commands $g]}
}]
#lappend commandlist {*}[@@ok/result= $matchedcommands]
#need to pull result from matchedcommands dict
@ -1450,8 +1463,8 @@ namespace eval punk::ns {
}
::set all_ns_commands [::info commands [::punk::ns::nsjoin $base $what]]
#important not to call namespace eval (or punk::ns::nseval) on non-existant base - or it will be created
::if {![::namespace exists $base]} {
#important not to call tcl::namespace::eval (or punk::ns::nseval) on non-existant base - or it will be created
::if {![::tcl::namespace::exists $base]} {
::continue
}
::set all_ns_tails [::lmap v $all_ns_commands {::punk::ns::nstail $v}]
@ -1615,7 +1628,7 @@ namespace eval punk::ns {
}
namespace eval internal {
tcl::namespace::eval internal {
#maintenance: similar in punk::winrun
@ -1701,7 +1714,7 @@ namespace eval punk::ns {
}
default {
if {[string match ::* $pkg_or_existing_ns]} {
if {![namespace exists $pkg_or_existing_ns]} {
if {![tcl::namespace::exists $pkg_or_existing_ns]} {
set ver [package require [string range $pkg_or_existing_ns 2 end]]
} else {
set ver ""
@ -1713,7 +1726,7 @@ namespace eval punk::ns {
}
}
}
if {[namespace exists $ns]} {
if {[tcl::namespace::exists $ns]} {
if {[llength $cmdargs]} {
set binding {}
#if {[info level] == 1} {
@ -1724,10 +1737,10 @@ namespace eval punk::ns {
#}
#set vars [uplevel 1 {*}$get_vars]
#set vars [namespace eval $ns {info vars}]
#set vars [tcl::namespace::eval $ns {info vars}]
#review - upvar in apply within ns eval vs direct access of ${ns}::varname
set capture [namespace eval $ns {
set capture [tcl::namespace::eval $ns {
apply { varnames {
while {"prev_args[incr n]" in $varnames} {}
set capturevars [dict create]
@ -1799,8 +1812,8 @@ namespace eval punk::ns {
lassign [dict values [punk::args::get_dict $argspecs $args]] opts values
set sourcepattern [dict get $values sourcepattern]
set source_ns [namespace qualifiers $sourcepattern]
if {![namespace exists $source_ns]} {
set source_ns [tcl::namespace::qualifiers $sourcepattern]
if {![tcl::namespace::exists $source_ns]} {
error "nsimport_noclobber error namespace $source_ns not found"
}
set target_ns [dict get $opts -targetnamespace]
@ -1811,9 +1824,9 @@ namespace eval punk::ns {
set target_ns [punk::nsjoin $nscaller $target_ns]
}
set a_export_patterns [namespace eval $source_ns {namespace export}]
set a_export_patterns [tcl::namespace::eval $source_ns {namespace export}]
set a_commands [info commands $sourcepattern]
set a_tails [lmap v $a_commands {namespace tail $v}]
set a_tails [lmap v $a_commands {tcl::namespace::tail $v}]
set a_exported_tails [list]
foreach epattern $a_export_patterns {
set matches [lsearch -all -inline $a_tails $epattern]
@ -1825,7 +1838,7 @@ namespace eval punk::ns {
}
set imported_commands [list]
foreach e $a_exported_tails {
set imported [namespace eval $target_ns [string map [list <func> $e <a> $source_ns] {
set imported [tcl::namespace::eval $target_ns [string map [list <func> $e <a> $source_ns] {
set cmd ""
if {![catch {namespace import <a>::<func>}]} {
set cmd <func>
@ -1890,7 +1903,7 @@ namespace eval punk::ns {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::ns [namespace eval punk::ns {
package provide punk::ns [tcl::namespace::eval punk::ns {
variable version
set version 0.1.0
}]

84
src/bootsupport/modules/punk/overlay-0.1.tm

@ -2,37 +2,37 @@
package require punk::mix::util
namespace eval ::punk::overlay {
tcl::namespace::eval ::punk::overlay {
#based *loosely* on: wiki.tcl-lang.org/page/ensemble+extend
# extend an ensemble-like routine with the routines in some namespace
#
# e.g custom_from_base ::punk::mix::cli ::punk::mix::base
#
proc custom_from_base {routine base} {
if {![string match ::* $routine]} {
set resolved [uplevel 1 [list ::namespace which $routine]]
if {![tcl::string::match ::* $routine]} {
set resolved [uplevel 1 [list ::tcl::namespace::which $routine]]
if {$resolved eq {}} {
error [list {no such routine} $routine]
}
set routine $resolved
}
set routinens [namespace qualifiers $routine]
set routinens [tcl::namespace::qualifiers $routine]
if {$routinens eq {::}} {
set routinens {}
}
set routinetail [namespace tail $routine]
set routinetail [tcl::namespace::tail $routine]
if {![string match ::* $base]} {
if {![tcl::string::match ::* $base]} {
set base [uplevel 1 [
list [namespace which namespace] current]]::$base
list [tcl::namespace::which namespace] current]]::$base
}
if {![namespace exists $base]} {
if {![tcl::namespace::exists $base]} {
error [list {no such namespace} $base]
}
set base [namespace eval $base [
list [namespace which namespace] current]]
set base [tcl::namespace::eval $base [
list [tcl::namespace::which namespace] current]]
#while 1 {
@ -40,42 +40,42 @@ namespace eval ::punk::overlay {
# if {[namespace which $renamed] eq {}} break
#}
namespace eval $routine [
list namespace ensemble configure $routine -unknown [
list apply {{base ensemble subcommand args} {
list ${base}::_redirected $ensemble $subcommand
tcl::namespace::eval $routine [
::list tcl::namespace::ensemble configure $routine -unknown [
::list ::apply {{base ensemble subcommand args} {
::list ${base}::_redirected $ensemble $subcommand
}} $base
]
]
punk::mix::util::namespace_import_pattern_to_namespace_noclobber ::punk::mix::util::* ${routine}::util
#namespace eval ${routine}::util {
#namespace import ::punk::mix::util::*
#::namespace import ::punk::mix::util::*
#}
punk::mix::util::namespace_import_pattern_to_namespace_noclobber ${base}::lib::* ${routine}::lib
#namespace eval ${routine}::lib [string map [list <base> $base] {
# namespace import <base>::lib::*
# ::namespace import <base>::lib::*
#}]
namespace eval ${routine}::lib [string map [list <base> $base <routine> $routine] {
if {[namespace exists <base>::lib]} {
set current_paths [namespace path]
tcl::namespace::eval ${routine}::lib [tcl::string::map [list <base> $base <routine> $routine] {
if {[tcl::namespace::exists <base>::lib]} {
::set current_paths [tcl::namespace::path]
if {"<routine>" ni $current_paths} {
lappend current_paths <routine>
::lappend current_paths <routine>
}
namespace path $current_paths
tcl::namespace::path $current_paths
}
}]
namespace eval $routine {
set exportlist [list]
foreach cmd [info commands [namespace current]::*] {
set c [namespace tail $cmd]
if {![string match _* $c]} {
lappend exportlist $c
tcl::namespace::eval $routine {
::set exportlist [::list]
::foreach cmd [tcl::info::commands [tcl::namespace::current]::*] {
::set c [tcl::namespace::tail $cmd]
if {![tcl::string::match _* $c]} {
::lappend exportlist $c
}
}
namespace export {*}$exportlist
tcl::namespace::export {*}$exportlist
}
return $routine
@ -96,20 +96,20 @@ namespace eval ::punk::overlay {
}
#namespace may or may not be a package
# allow with or without leading ::
if {[string range $cmdnamespace 0 1] eq "::"} {
set cmdpackage [string range $cmdnamespace 2 end]
if {[tcl::string::range $cmdnamespace 0 1] eq "::"} {
set cmdpackage [tcl::string::range $cmdnamespace 2 end]
} else {
set cmdpackage $cmdnamespace
set cmdnamespace ::$cmdnamespace
}
if {![namespace exists $cmdnamespace]} {
if {![tcl::namespace::exists $cmdnamespace]} {
#only do package require if the namespace not already present
catch {package require $cmdpackage} pkg_load_info
#recheck
if {![namespace exists $cmdnamespace]} {
if {![tcl::namespace::exists $cmdnamespace]} {
set prov [package provide $cmdpackage]
if {[string length $prov]} {
if {[tcl::string::length $prov]} {
set provinfo "(package $cmdpackage is present with version $prov)"
} else {
set provinfo "(package $cmdpackage not present)"
@ -121,21 +121,21 @@ namespace eval ::punk::overlay {
punk::mix::util::namespace_import_pattern_to_namespace_noclobber ::punk::mix::util::* ${cmdnamespace}::util
#let child namespace 'lib' resolve parent namespace and thus util::xxx
namespace eval ${cmdnamespace}::lib [string map [list <cmdns> $cmdnamespace] {
set nspaths [namespace path]
tcl::namespace::eval ${cmdnamespace}::lib [tcl::string::map [list <cmdns> $cmdnamespace] {
::set nspaths [tcl::namespace::path]
if {"<cmdns>" ni $nspaths} {
lappend nspaths <cmdns>
::lappend nspaths <cmdns>
}
namespace path $nspaths
tcl::namespace::path $nspaths
}]
set imported_commands [list]
set nscaller [uplevel 1 [list namespace current]]
set nscaller [uplevel 1 [list tcl::namespace::current]]
if {[catch {
#review - noclobber?
namespace eval ${nscaller}::temp_import [list namespace import ${cmdnamespace}::*]
foreach cmd [info commands ${nscaller}::temp_import::*] {
set cmdtail [namespace tail $cmd]
tcl::namespace::eval ${nscaller}::temp_import [list tcl::namespace::import ${cmdnamespace}::*]
foreach cmd [tcl::info::commands ${nscaller}::temp_import::*] {
set cmdtail [tcl::namespace::tail $cmd]
if {$cmdtail eq "_default"} {
set import_as ${nscaller}::${prefix}
} else {
@ -153,7 +153,7 @@ namespace eval ::punk::overlay {
}
package provide punk::overlay [namespace eval punk::overlay {
package provide punk::overlay [tcl::namespace::eval punk::overlay {
variable version
set version 0.1
}]

17
src/bootsupport/modules/punk/path-0.1.0.tm

@ -131,7 +131,8 @@ namespace eval punk::path {
** {lappend pats {.*}}
default {
set seg [string map [list {^ {\^} $ {\$} [} {\[} ( {\(} \{ \\\{ \\ {\\}] $seg] ;#treat regex characters in the input as literals
set seg [string map [list . {[.]}] $seg]
#set seg [string map [list . {[.]}] $seg]
set seg [string map {. [.]} $seg]
if {[regexp {[*?]} $seg]} {
set pat [string map [list ** {.*} * {[^/]*} ? {[^/]}] $seg]
lappend pats "$pat"
@ -212,12 +213,14 @@ namespace eval punk::path {
#[para] list of path patterns to exclude - may include * and ** path segments e.g /usr/**
#[para]no natsorting - so order is dependent on filesystem
lassign [punk::get_leading_opts_and_values {
-directory "\uFFFF"
-call-depth-internal 0
-antiglob_paths {}
} $args] _o opts _v tailglobs
set argd [punk::args::get_dict {
-directory -default "\uFFFF"
-call-depth-internal -default 0 -type integer
-antiglob_paths -default {}
*values -min 0 -max -1 -type string
} $args]
lassign [dict values $argd] opts values
set tailglobs [dict values $values]
# -- --- --- --- --- --- ---
set opt_antiglob_paths [dict get $opts -antiglob_paths]
set CALLDEPTH [dict get $opts -call-depth-internal]

6
src/bootsupport/modules/punk/repo-0.1.1.tm

@ -1303,7 +1303,7 @@ namespace eval punk::repo {
if {[catch {exec {*}$fossilcmd all ls} repolines]} {
error "fossil_get_configdb cannot find repositories"
} else {
set repolines [string map [list \r\n \n] $repolines]
set repolines [string map {\r\n \n} $repolines]
set repolist [split $repolines \n]
set dbcmd "fossil_get_configdb_tempdb"
foreach repodb $repolist {
@ -1383,12 +1383,12 @@ namespace eval punk::repo {
return [lindex [split $content \x1A] 0]
}
proc grep {pattern data} {
set data [string map [list \r\n \n] $data]
set data [string map {\r\n \n} $data]
return [lsearch -all -inline -glob [split $data \n] $pattern]
}
proc rgrep {pattern data} {
set data [string map [list \r\n \n] $data]
set data [string map {\r\n \n} $data]
return [lsearch -all -inline -regexp [split $data \n] $pattern]
}

8
src/bootsupport/modules/punk/winpath-0.1.0.tm

@ -31,10 +31,10 @@ namespace eval punk::winpath {
#\\servername\share etc or \\?\UNC\servername\share etc.
proc is_unc_path {path} {
set strcopy_path [punk::objclone $path]
set strcopy_path [string map [list \\ /] $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway)
set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway)
if {[string first "//" $strcopy_path] == 0} {
#check for "Dos device path" syntax
if {[string range $strcopy_path 0 3] in [list "//?/" "//./"]} {
if {[string range $strcopy_path 0 3] in {//?/ //./}} {
#Note that //./ doesn't appear to be supported in Tcl as at 2023-08 - but //?/ works (except for //?/UNC/Server/share)
if {[string range $strcopy_path 4 6] eq "UNC"} {
return 1
@ -78,8 +78,8 @@ namespace eval punk::winpath {
#(can exist on server shares and on NTFS - but standard apps can't access without dos device syntax)
proc is_dos_device_path {path} {
set strcopy_path [punk::objclone $path]
set strcopy_path [string map [list \\ /] $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway)
if {[string range $strcopy_path 0 3] in [list "//?/" "//./"]} {
set strcopy_path [string map {\\ /} $strcopy_path] ;#normalize to forward slashes for testing purposes (and forward slashes seem to be auto-translated by windows anyway)
if {[string range $strcopy_path 0 3] in {//?/ //./}} {
return 1
} else {
return 0

41
src/bootsupport/modules/punkcheck-0.1.0.tm

@ -1,5 +1,5 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'deck make' or src/make.tcl to update from <pkg>-buildversion.txt
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'dev make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem.
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository.
@ -116,16 +116,21 @@ namespace eval punkcheck {
}
method as_record {} {
set fields [list\
#set fields [list\
# -targets $o_targets\
# -keep_installrecords $o_keep_installrecords\
# -keep_skipped $o_keep_skipped\
# -keep_inprogress $o_keep_inprogress\
# body $o_records\
#]
dict create \
tag FILEINFO\
-targets $o_targets\
-keep_installrecords $o_keep_installrecords\
-keep_skipped $o_keep_skipped\
-keep_inprogress $o_keep_inprogress\
body $o_records\
]
set record [dict create tag FILEINFO {*}$fields]
body $o_records
}
#retrieve last completed record for the fileset ie exclude SKIPPED,INSTALL-INPROGRESS,DELETE-INPROGRESS,MODIFY-INPROGRESS
@ -199,7 +204,21 @@ namespace eval punkcheck {
} else {
set tsiso_end ""
}
set fields [list\
#set fields [list\
# -tsiso_begin $tsiso_begin\
# -ts_begin $o_ts_begin\
# -tsiso_end $tsiso_end\
# -ts_end $o_ts_end\
# -id $o_id\
# -source $o_rel_sourceroot\
# -targets $o_rel_targetroot\
# -types $o_types\
# -config $o_configdict\
#]
#set record [dict create tag EVENT {*}$fields]
dict create \
tag EVENT\
-tsiso_begin $tsiso_begin\
-ts_begin $o_ts_begin\
-tsiso_end $tsiso_end\
@ -208,10 +227,8 @@ namespace eval punkcheck {
-source $o_rel_sourceroot\
-targets $o_rel_targetroot\
-types $o_types\
-config $o_configdict\
]
-config $o_configdict
set record [dict create tag EVENT {*}$fields]
}
method get_id {} {
return $o_id
@ -1294,7 +1311,7 @@ namespace eval punkcheck {
dict unset config -call-depth-internal
dict unset config -max_depth
dict unset config -subdirlist
dict for {k v} $config {
tcl::dict::for {k v} $config {
if {$v eq "\uFFFF"} {
dict unset config $k
}

2444
src/bootsupport/modules/textblock-0.1.1.tm

File diff suppressed because it is too large Load Diff

2252
src/bootsupport/modules/textutil/wcswidth-35.2.tm

File diff suppressed because it is too large Load Diff

543
src/vendormodules/overtype-1.6.3.tm

File diff suppressed because it is too large Load Diff

3685
src/vendormodules/overtype-1.6.4.tm

File diff suppressed because it is too large Load Diff

3588
src/vendormodules/tcltest-2.5.8.tm

File diff suppressed because it is too large Load Diff

2252
src/vendormodules/textutil/wcswidth-35.2.tm

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save