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. 676
      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. 2446
      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} { proc hex2dec {largeHex} {
#todo - use punk::lib::hex2dec - (scan supports ll so can do larger hex values directly) #todo - use punk::lib::hex2dec - (scan supports ll so can do larger hex values directly)
set res 0 set res 0
set largeHex [string map [list _ ""] $largeHex] set largeHex [string map {_ {}} $largeHex]
if {[string length $largeHex] <=7} { if {[string length $largeHex] <=7} {
#scan can process up to FFFFFFF and does so quickly #scan can process up to FFFFFFF and does so quickly
return [scan $largeHex %x] return [scan $largeHex %x]
@ -392,7 +392,7 @@ namespace eval natsort {
proc get_char_count {str char} { proc get_char_count {str char} {
#faster than lsearch on split for str of a few K #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} { proc build_key {chunk splitchars topdict tagconfig debug} {
@ -856,10 +856,39 @@ namespace eval natsort {
return [csv::join $line {*}$opts] 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} { proc sort {stringlist args} {
#puts stdout "natsort::sort args: $args" #puts stdout "natsort::sort args: $args"
variable debug variable debug
variable sort_flagspecs
if {![llength $stringlist]} return 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 #allow pass through of the check_flags flag -debugargs so it can be set by the caller
set debugargs 0 set debugargs 0
@ -874,49 +903,43 @@ namespace eval natsort {
#-return flagged|defaults doesn't work Review. #-return flagged|defaults doesn't work Review.
#flagfilter global processor/allocator not working 2023-08 #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 opts [check_flags {*}$sort_flagspecs -debugargs $debugargs -values $args]
set winlike [dict get $args -winlike] #we can only shortcircuit input list of single element at this point if there aren't non-default -inputformat or -outputformat transformations
set topchars [dict get $args -topchars] if {[llength $stringlist] == 1} {
set cols [dict get $args -cols] set is_basic 1
set debug [dict get $args -debug] foreach fname [list -inputformat -outputformat] {
set stacktrace [dict get $args -stacktrace] if {[dict get $sort_flagspecs -defaults $fname] ne [dict get $opts $fname]} {
set showsplits [dict get $args -showsplits] set is_basic 0
set splits [dict get $args -splits] break
set sortmethod [dict get $args -sortmethod] }
set opt_collate [dict get $args -collate] }
set opt_inputformat [dict get $args -inputformat] if {$is_basic} {
set opt_inputformatapply [dict get $args -inputformatapply] return $stringlist
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 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} { 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} { if {$debug == 1} {
puts stdout "natsort::sort - try also -debug 2, -debug 3" puts stdout "natsort::sort - try also -debug 2, -debug 3"
} }
@ -1427,24 +1450,27 @@ namespace eval natsort {
return 0 return 0
} }
} }
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 ""}} { proc test_pass_fail_message {pass {additional ""}} {
@ -1709,9 +1735,9 @@ namespace eval natsort {
set debug [dict get $args -debug] set debug [dict get $args -debug]
set collate [dict get $args -collate] set collate [dict get $args -collate]
set db [dict get $args -db] set db [dict get $args -db]
set winlike [dict get $args -winlike] set winlike [dict get $args -winlike]
set topchars [dict get $args -topchars] 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

676
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 # oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::assertion::class { tcl::namespace::eval punk::assertion::class {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::assertion::class}] #[subsection {Namespace punk::assertion::class}]
#[para] class definitions #[para] class definitions
if {[info commands [namespace current]::interface_sample1] eq ""} { if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} {
#*** !doctools #*** !doctools
#[list_begin enumerated] #[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 #keep 2 namespaces for assertActive and assertInactive so there is introspection available via namespace origin
namespace eval punk::assertion::primary { tcl::namespace::eval punk::assertion::primary {
#tcl::namespace::export {[a-z]*}
namespace export * tcl::namespace::export assertActive assertInactive
proc assertActive {expr args} { proc assertActive {expr args} {
set code [catch {uplevel 1 [list expr $expr]} res] set code [catch {uplevel 1 [list expr $expr]} res]
if {$code} { if {$code} {
return -code $code $res return -code $code $res
} }
if {![string is boolean -strict $res]} { if {![tcl::string::is boolean -strict $res]} {
return -code error "invalid boolean expression: $expr" return -code error "invalid boolean expression: $expr"
} }
@ -124,28 +124,40 @@ namespace eval punk::assertion::primary {
upvar ::punk::assertion::CallbackCmd CallbackCmd upvar ::punk::assertion::CallbackCmd CallbackCmd
# Might want to catch this # Might want to catch this
namespace eval :: $CallbackCmd [list $msg] tcl::namespace::eval :: $CallbackCmd [list $msg]
} }
proc assertInactive args {} proc assertInactive args {}
} }
namespace eval punk::assertion::secondary { tcl::namespace::eval punk::assertion::secondary {
namespace export * 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. #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 {} proc assertInactive args {}
} }
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace # Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::assertion { tcl::namespace::eval punk::assertion {
variable CallbackCmd [list return -code error] 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 rename assertActive assert
namespace export * }
tcl::namespace::eval punk::assertion {
tcl::namespace::export *
#variable xyz #variable xyz
#*** !doctools #*** !doctools
@ -177,7 +189,7 @@ namespace eval punk::assertion {
set n [llength $args] set n [llength $args]
if {$n > 1} { if {$n > 1} {
return -code error "wrong # args: should be\ return -code error "wrong # args: should be\
\"[lindex [info level 0] 0] ?command?\"" \"[lindex [tcl::info::level 0] 0] ?command?\""
} }
if {$n} { if {$n} {
set cb [lindex $args 0] set cb [lindex $args 0]
@ -187,41 +199,41 @@ namespace eval punk::assertion {
} }
proc active {{on_off ""}} { proc active {{on_off ""}} {
set nscaller [uplevel 1 [list namespace current]] set nscaller [uplevel 1 [list tcl::namespace::current]]
set which_assert [namespace eval $nscaller {namespace which assert}] set which_assert [tcl::namespace::eval $nscaller {tcl::namespace::which assert}]
#puts "nscaller:'$nscaller'" #puts "nscaller:'$nscaller'"
#puts "which_assert: $which_assert" #puts "which_assert: $which_assert"
if {$on_off eq ""} { if {$on_off eq ""} {
if {$which_assert eq ""} {return 0} 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 which assert: $which_assert"
#puts "ns origin assert: $assertorigin" #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" error "invalid boolean value : $on_off"
} else { } else {
set info_command [namespace eval $nscaller {info commands assert}] set info_command [tcl::namespace::eval $nscaller {tcl::info::commands assert}]
if {$on_off} { if {$on_off} {
#Enable it in calling namespace #Enable it in calling namespace
if {"assert" eq $info_command} { 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) #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]} { if {$which_assert eq [punk::assertion::system::nsjoin ${nscaller} assert]} {
namespace eval $nscaller { tcl::namespace::eval $nscaller {
set assertorigin [namespace origin assert] set assertorigin [tcl::namespace::origin assert]
set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin] set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin]
switch -- $assertorigin_ns { switch -- $assertorigin_ns {
::punk::assertion { ::punk::assertion {
#original import - switch to primary origin #original import - switch to primary origin
rename assert {} rename assert {}
namespace import ::punk::assertion::primary::assertActive tcl::namespace::import ::punk::assertion::primary::assertActive
rename assertActive assert rename assertActive assert
} }
::punk::assertion::primary - ::punk::assertion::secondary { ::punk::assertion::primary - ::punk::assertion::secondary {
#keep using from same origin ns #keep using from same origin ns
rename assert {} rename assert {}
namespace import ${assertorigin_ns}::assertActive tcl::namespace::import ${assertorigin_ns}::assertActive
rename assertActive assert rename assertActive assert
} }
default { default {
@ -232,10 +244,10 @@ namespace eval punk::assertion {
return 1 return 1
} else { } 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 #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 { tcl::namespace::eval $nscaller {
set assertorigin [namespace origin assert] set assertorigin [tcl::namespace::origin assert]
if {[string match ::punk::assertion::* $assertorigin]} { if {[tcl::string::match ::punk::assertion::* $assertorigin]} {
namespace import ::punk::assertion::secondary::assertActive tcl::namespace::import ::punk::assertion::secondary::assertActive
rename assertActive assert rename assertActive assert
} else { } 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" 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 {"assert" eq $info_command} {
if {$which_assert eq [punk::assertion::system::nsjoin ${nscaller} assert]} { if {$which_assert eq [punk::assertion::system::nsjoin ${nscaller} assert]} {
#assert is present in callers NS #assert is present in callers NS
namespace eval $nscaller { tcl::namespace::eval $nscaller {
set assertorigin [namespace origin assert] set assertorigin [tcl::namespace::origin assert]
set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin] set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin]
switch -glob -- $assertorigin_ns { switch -glob -- $assertorigin_ns {
::punk::assertion { ::punk::assertion {
#original import #original import
rename assert {} rename assert {}
namespace import punk::assertion::primary::assertInactive tcl::namespace::import punk::assertion::primary::assertInactive
rename assertInactive assert rename assertInactive assert
} }
::punk::assertion::primary - ::punk::assertion::secondary { ::punk::assertion::primary - ::punk::assertion::secondary {
#keep using from same origin ns #keep using from same origin ns
rename assert {} rename assert {}
namespace import ${assertorigin_ns}::assertInactive tcl::namespace::import ${assertorigin_ns}::assertInactive
rename assertInactive assert rename assertInactive assert
} }
default { default {
@ -278,11 +290,11 @@ namespace eval punk::assertion {
return 0 return 0
} else { } else {
#assert not present in callers NS - first install of secondary (if assert is from punk::assertion::*) #assert not present in callers NS - first install of secondary (if assert is from punk::assertion::*)
namespace eval $nscaller { tcl::namespace::eval $nscaller {
set assertorigin [namespace origin assert] set assertorigin [tcl::namespace::origin assert]
set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin] set assertorigin_ns [punk::assertion::system::nsprefix $assertorigin]
if {[string match ::punk::assertion::* $assertorigin]} { if {[tcl::string::match ::punk::assertion::* $assertorigin]} {
namespace import ::punk::assertion::secondary::assertInactive tcl::namespace::import ::punk::assertion::secondary::assertInactive
rename assertInactive assert rename assertInactive assert
} else { } 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" 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 # Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::assertion::lib { tcl::namespace::eval punk::assertion::lib {
namespace export * tcl::namespace::export *
namespace path [namespace parent] tcl::namespace::path [tcl::namespace::parent]
#*** !doctools #*** !doctools
#[subsection {Namespace punk::assertion::lib}] #[subsection {Namespace punk::assertion::lib}]
#[para] Secondary functions that are part of the API #[para] Secondary functions that are part of the API
@ -337,7 +349,7 @@ namespace eval punk::assertion::lib {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools #*** !doctools
#[section Internal] #[section Internal]
namespace eval punk::assertion::system { tcl::namespace::eval punk::assertion::system {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::assertion::system}] #[subsection {Namespace punk::assertion::system}]
#[para] Internal functions that are not part of the API #[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 #nsprefix/nstail are string functions - they do not concern themselves with what namespaces are present in the system
proc nsprefix {{nspath {}}} { proc nsprefix {{nspath {}}} {
#normalize the common case of :::: #normalize the common case of ::::
set nspath [string map [list :::: ::] $nspath] set nspath [tcl::string::map [list :::: ::] $nspath]
set rawprefix [string range $nspath 0 end-[string length [nstail $nspath]]] set rawprefix [tcl::string::range $nspath 0 end-[tcl::string::length [nstail $nspath]]]
if {$rawprefix eq "::"} { if {$rawprefix eq "::"} {
return $rawprefix return $rawprefix
} else { } else {
if {[string match *:: $rawprefix]} { if {[tcl::string::match *:: $rawprefix]} {
return [string range $rawprefix 0 end-2] return [tcl::string::range $rawprefix 0 end-2]
} else { } else {
return $rawprefix return $rawprefix
} }
#return [string trimright $rawprefix :] #return [tcl::string::trimright $rawprefix :]
} }
} }
#see also punk::ns - keep in sync #see also punk::ns - keep in sync
proc nstail {nspath args} { proc nstail {nspath args} {
#normalize the common case of :::: #normalize the common case of ::::
set nspath [string map [list :::: ::] $nspath] set nspath [tcl::string::map [list :::: ::] $nspath]
set mapped [string map [list :: \u0FFF] $nspath] set mapped [tcl::string::map [list :: \u0FFF] $nspath]
set parts [split $mapped \u0FFF] set parts [split $mapped \u0FFF]
set defaults [list -strict 0] set defaults [list -strict 0]
set opts [dict merge $defaults $args] set opts [tcl::dict::merge $defaults $args]
set strict [dict get $opts -strict] set strict [tcl::dict::get $opts -strict]
if {$strict} { if {$strict} {
foreach p $parts { foreach p $parts {
if {[string match :* $p]} { if {[tcl::string::match :* $p]} {
error "nstail unpaired colon ':' in $nspath" error "nstail unpaired colon ':' in $nspath"
} }
} }
@ -381,7 +393,7 @@ namespace eval punk::assertion::system {
return [lindex $parts end] return [lindex $parts end]
} }
proc nsjoin {prefix name} { proc nsjoin {prefix name} {
if {[string match ::* $name]} { if {[tcl::string::match ::* $name]} {
if {"$prefix" ne ""} { if {"$prefix" ne ""} {
error "nsjoin: won't join non-empty prefix to absolute namespace path '$name'" error "nsjoin: won't join non-empty prefix to absolute namespace path '$name'"
} }
@ -400,7 +412,7 @@ namespace eval punk::assertion::system {
} }
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready ## Ready
package provide punk::assertion [namespace eval punk::assertion { package provide punk::assertion [tcl::namespace::eval punk::assertion {
variable pkg punk::assertion variable pkg punk::assertion
variable version variable version
set version 0.1.0 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 { tcl::namespace::eval punk::cap {
variable pkgcapsdeclared [dict create] variable pkgcapsdeclared [tcl::dict::create]
variable pkgcapsaccepted [dict create] variable pkgcapsaccepted [tcl::dict::create]
variable caps [dict create] variable caps [tcl::dict::create]
namespace eval class { namespace eval class {
if {[info commands [namespace current]::interface_caphandler.registry] eq ""} { if {[tcl::info::commands ::punk::cap::class::interface_caphandler.registry] eq ""} {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::cap::class}] #[subsection {Namespace punk::cap::class}]
#[para] class definitions #[para] class definitions
@ -62,7 +62,7 @@ namespace eval punk::cap {
# [para] [emph {handler_classes}] # [para] [emph {handler_classes}]
# [list_begin enumerated] # [list_begin enumerated]
oo::class create [namespace current]::interface_caphandler.registry { oo::class create ::punk::cap::class::interface_caphandler.registry {
#*** !doctools #*** !doctools
#[enum] CLASS [class interface_caphandler.registry] #[enum] CLASS [class interface_caphandler.registry]
#[list_begin definitions] #[list_begin definitions]
@ -83,7 +83,7 @@ namespace eval punk::cap {
#[list_end] #[list_end]
} }
oo::class create [namespace current]::interface_caphandler.sysapi { oo::class create ::punk::cap::class::interface_caphandler.sysapi {
#*** !doctools #*** !doctools
#[enum] CLASS [class interface_caphandler.sysapi] #[enum] CLASS [class interface_caphandler.sysapi]
#[list_begin definitions] #[list_begin definitions]
@ -103,7 +103,7 @@ namespace eval punk::cap {
# [list_begin enumerated] # [list_begin enumerated]
#Provider classes #Provider classes
oo::class create [namespace current]::interface_capprovider.registration { oo::class create ::punk::cap::class::interface_capprovider.registration {
#*** !doctools #*** !doctools
# [enum] CLASS [class interface_cappprovider.registration] # [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. # [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] # [list_end]
} }
oo::class create [namespace current]::interface_capprovider.provider { oo::class create ::punk::cap::class::interface_capprovider.provider {
#*** !doctools #*** !doctools
# [enum] CLASS [class interface_capprovider.provider] # [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}] # [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 #*** !doctools
#[call class::interface_capprovider.provider [method constructor] [arg providerpkg]] #[call class::interface_capprovider.provider [method constructor] [arg providerpkg]]
variable provider_pkg variable provider_pkg
if {$providerpkg in [list "" "::"]} { if {$providerpkg in {"" "::"}} {
error "interface_capprovider.provider constructor error. Invalid provider '$providerpkg'" error "interface_capprovider.provider constructor error. Invalid provider '$providerpkg'"
} }
if {![namespace exists ::$providerpkg]} { if {![namespace exists ::$providerpkg]} {
@ -165,12 +165,12 @@ namespace eval punk::cap {
} }
set registrationobj ::${providerpkg}::capsystem::capprovider.registration 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" 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 *}} { method register {{capabilityname_glob *}} {
#*** !doctools #*** !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. #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. #we allow registering a capability with an empty handler (capnamespace) - but this means another handler could be registered later.
proc register_capabilityname {capname capnamespace} { proc register_capabilityname {capname capnamespace} {
puts stderr "REGISTER_CAPABILITYNAME $capname $capnamespace" #puts stderr "REGISTER_CAPABILITYNAME $capname $capnamespace"
variable caps variable caps
variable pkgcapsdeclared variable pkgcapsdeclared
variable pkgcapsaccepted variable pkgcapsaccepted
if {$capnamespace ne ""} { if {$capnamespace ne ""} {
#normalize with leading :: in case caller passed in package name rather than fully qualified namespace #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 set capnamespace ::$capnamespace
} }
} }
@ -250,20 +250,21 @@ namespace eval punk::cap {
return 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. #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 tcl::dict::set caps $capname handler $capnamespace
if {![dict exists $caps $capname providers]} { if {![tcl::dict::exists $caps $capname providers]} {
dict set caps $capname providers [list] 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 #some provider(s) were in place before the handler was registered
if {[set capreg [punk::cap::capsystem::get_caphandler_registry $capname]] ne ""} { if {[set capreg [punk::cap::capsystem::get_caphandler_registry $capname]] ne ""} {
foreach pkg $providers { foreach pkg $providers {
set fullcapabilitylist [dict get $pkgcapsdeclared $pkg] set fullcapabilitylist [tcl::dict::get $pkgcapsdeclared $pkg]
foreach capspec $fullcapabilitylist { set capname_capabilitylist [lsearch -all -inline -index 0 $fullcapabilitylist $capname]
foreach capspec $capname_capabilitylist {
lassign $capspec cn capdict lassign $capspec cn capdict
if {$cn ne $capname} { #if {$cn ne $capname} {
continue # continue
} #}
if {[catch {$capreg pkg_register $pkg $capdict $fullcapabilitylist} do_register]} { 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 "punk::cap::register_capabilityname '$capname' '$capnamespace' failed to register provider package '$pkg' - possible error in handler or provider"
puts stderr "error message:" puts stderr "error message:"
@ -271,22 +272,22 @@ namespace eval punk::cap {
set do_register 0 set do_register 0
} }
set list_accepted [dict get $pkgcapsaccepted $pkg] set list_accepted [tcl::dict::get $pkgcapsaccepted $pkg]
if {$do_register} { if {$do_register} {
if {$capspec ni $list_accepted} { if {$capspec ni $list_accepted} {
dict lappend pkgcapsaccepted $pkg $capspec tcl::dict::lappend pkgcapsaccepted $pkg $capspec
} }
} else { } else {
set posn [lsearch $list_accepted $capspec] set posn [lsearch $list_accepted $capspec]
if {$posn >=0} { if {$posn >=0} {
set list_accepted [lreplace $list_accepted $posn $posn] 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 #check if any accepted for this cap and remove from caps as necessary
set count 0 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} { if {[lindex $accepted_capspec 0] eq $capname} {
incr count incr count
} }
@ -295,7 +296,7 @@ namespace eval punk::cap {
set pkgposn [lsearch $providers $pkg] set pkgposn [lsearch $providers $pkg]
if {$pkgposn >= 0} { if {$pkgposn >= 0} {
set updated_providers [lreplace $providers $posn $posn] 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]] # [call [fun capability_exists] [arg capname]]
# Return a boolean indicating if the named capability exists (0|1) # Return a boolean indicating if the named capability exists (0|1)
variable caps variable caps
return [dict exists $caps $capname] return [tcl::dict::exists $caps $capname]
} }
proc capability_has_handler {capname} { proc capability_has_handler {capname} {
#*** !doctools #*** !doctools
# [call [fun capability_has_handler] [arg capname]] # [call [fun capability_has_handler] [arg capname]]
#Return a boolean indicating if the named capability has a handler package installed (0|1) #Return a boolean indicating if the named capability has a handler package installed (0|1)
variable caps 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} { proc capability_get_handler {capname} {
#*** !doctools #*** !doctools
@ -324,8 +325,8 @@ namespace eval punk::cap {
#Return the base namespace of the active handler package for the named capability. #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 :: #[para] The base namespace for a handler will always be the package name, but prefixed with ::
variable caps variable caps
if {[dict exists $caps $capname]} { if {[tcl::dict::exists $caps $capname]} {
return [dict get $caps $capname handler] return [tcl::dict::get $caps $capname handler]
} }
return "" return ""
} }
@ -338,8 +339,8 @@ namespace eval punk::cap {
} }
proc get_providers {capname} { proc get_providers {capname} {
variable caps variable caps
if {[dict exists $caps $capname]} { if {[tcl::dict::exists $caps $capname]} {
return [dict get $caps $capname providers] return [tcl::dict::get $caps $capname providers]
} }
return [list] return [list]
} }
@ -356,26 +357,26 @@ namespace eval punk::cap {
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-nowarnings { -nowarnings {
dict set opts $k $v tcl::dict::set opts $k $v
} }
default { 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]} { if {[tcl::string::match ::* $pkg]} {
set pkg [string range $pkg 2 end] set pkg [tcl::string::range $pkg 2 end]
} }
if {[dict exists $pkgcapsaccepted $pkg]} { if {[tcl::dict::exists $pkgcapsaccepted $pkg]} {
set pkg_already_accepted [dict get $pkgcapsaccepted $pkg] set pkg_already_accepted [tcl::dict::get $pkgcapsaccepted $pkg]
} else { } else {
set pkg_already_accepted [list] set pkg_already_accepted [list]
} }
package require $pkg package require $pkg
set providerapi ::${pkg}::provider 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)" 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] set defined_caps [$providerapi capabilities]
@ -397,13 +398,13 @@ namespace eval punk::cap {
if {[llength $capname] !=1} { 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'" 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" 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 continue
} }
if {[expr {[llength $capdict] %2 != 0}]} { 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'" 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" 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 continue
} }
if {$capspec in $pkg_already_accepted} { if {$capspec in $pkg_already_accepted} {
@ -411,13 +412,13 @@ namespace eval punk::cap {
if {$warnings} { if {$warnings} {
puts stderr "WARNING: register_package pkg $pkg already has capspec marked as accepted: $capspec" 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 continue
} }
if {[dict exists $caps $capname]} { if {[tcl::dict::exists $caps $capname]} {
set cap_pkgs [dict get $caps $capname providers] set cap_pkgs [tcl::dict::get $caps $capname providers]
} else { } else {
dict set caps $capname [dict create handler "" providers [list]] dict set caps $capname [tcl::dict::create handler "" providers [list]]
set cap_pkgs [list] set cap_pkgs [list]
} }
#todo - if there's a caphandler - call it's init/validation callback for the pkg #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 {$do_register} {
if {$pkg ni $cap_pkgs} { if {$pkg ni $cap_pkgs} {
lappend cap_pkgs $pkg 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 #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 #dict lappend pkgcapsdeclared $pkg $capabilitylist
if {[dict exists $pkgcapsdeclared $pkg]} { if {[tcl::dict::exists $pkgcapsdeclared $pkg]} {
#review - untested #review - untested
set mergecapspecs [dict get $pkgcapsdeclared $pkg] set mergecapspecs [tcl::dict::get $pkgcapsdeclared $pkg]
foreach spec $capabilitylist { foreach spec $capabilitylist {
if {$spec ni $mergecapspecs} { if {$spec ni $mergecapspecs} {
lappend mergecapspecs $spec lappend mergecapspecs $spec
} }
} }
dict set pkgcapsdeclared $pkg $mergecapspecs tcl::dict::set pkgcapsdeclared $pkg $mergecapspecs
} else { } else {
dict set pkgcapsdeclared $pkg $capabilitylist tcl::dict::set pkgcapsdeclared $pkg $capabilitylist
} }
set resultdict [list num_capabilities $capabilitylist_count num_accepted $accepted_count] set resultdict [list num_capabilities $capabilitylist_count num_accepted $accepted_count]
if {[llength $errorlist]} { if {[llength $errorlist]} {
dict set resultdict errors $errorlist tcl::dict::set resultdict errors $errorlist
} }
if {[llength $warninglist]} { if {[llength $warninglist]} {
dict set resultdict warnings $warninglist tcl::dict::set resultdict warnings $warninglist
} }
return $resultdict 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 path [dict get $capdict path]
set cname [string map [list . _] $capname] set cname [string map {. _} $capname]
set multivendor_package_whitelist [list punk::mix::templates] set multivendor_package_whitelist [list punk::mix::templates]
@ -85,8 +85,19 @@ namespace eval punk::cap::handlers::templates {
module { module {
set provide_statement [package ifneeded $pkg [package require $pkg]] set provide_statement [package ifneeded $pkg [package require $pkg]]
set tmfile [lindex $provide_statement end] 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]} { 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" 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 return 0
} }
@ -215,7 +226,7 @@ namespace eval punk::cap::handlers::templates {
method pkg_unregister {pkg} { method pkg_unregister {pkg} {
upvar ::punk::cap::handlers::templates::handled_caps hcaps upvar ::punk::cap::handlers::templates::handled_caps hcaps
foreach capname $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 upvar ::punk::cap::handlers::templates::provider_info_$cname my_provider_info
dict unset my_provider_info $pkg dict unset my_provider_info $pkg
#destroy api objects? #destroy api objects?
@ -238,7 +249,7 @@ namespace eval punk::cap::handlers::templates {
constructor {capname} { constructor {capname} {
variable capabilityname variable capabilityname
variable cname variable cname
set cname [string map [list . _] $capname] set cname [string map {. _} $capname]
set capabilityname $capname set capabilityname $capname
} }
method folders {args} { method folders {args} {
@ -635,6 +646,7 @@ namespace eval punk::cap::handlers::templates {
#and a name determining command -command_get_item_name #and a name determining command -command_get_item_name
method _get_itemdict {args} { method _get_itemdict {args} {
set argd [punk::args::get_dict { set argd [punk::args::get_dict {
*proc -name _get_itemdict
*opts -anyopts 0 *opts -anyopts 0
-startdir -default "" -startdir -default ""
-templatefolder_subdir -optional 0 -templatefolder_subdir -optional 0
@ -646,6 +658,7 @@ namespace eval punk::cap::handlers::templates {
} $args] } $args]
set opts [dict get $argd opts] 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 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_startdir [dict get $opts -startdir]
set opt_templatefolder_subdir [dict get $opts -templatefolder_subdir] 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 package require punk::ansi
if {"windows" eq $::tcl_platform(platform)} { #if {"windows" eq $::tcl_platform(platform)} {
#package require zzzload # #package require zzzload
#zzzload::pkg_require twapi # #zzzload::pkg_require twapi
} #}
#see https://learn.microsoft.com/en-us/windows/console/classic-vs-vt #see https://learn.microsoft.com/en-us/windows/console/classic-vs-vt
#https://learn.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session #https://learn.microsoft.com/en-us/windows/console/creating-a-pseudoconsole-session
@ -765,6 +765,7 @@ namespace eval punk::console {
} ;#end namespace eval internal } ;#end namespace eval internal
variable colour_disabled 0 variable colour_disabled 0
#todo - move to punk::config
# https://no-color.org # https://no-color.org
if {[info exists ::env(NO_COLOR)]} { if {[info exists ::env(NO_COLOR)]} {
if {$::env(NO_COLOR) ne ""} { if {$::env(NO_COLOR) ne ""} {
@ -779,7 +780,7 @@ namespace eval punk::console {
#stdout #stdout
variable ansi_wanted variable ansi_wanted
if {$ansi_wanted <= 0} { if {$ansi_wanted <= 0} {
puts -nonewline [punk::ansi::stripansi [::punk::ansi::a?]] puts -nonewline [punk::ansi::stripansiraw [::punk::ansi::a?]]
} else { } else {
tailcall ansi::a? {*}$args 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 [glob -nocomplain -dir $folderpath -types {hidden l} * .*]
#set hlinks {} #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 links [lsort -unique [concat $hlinks $links[unset links]]]
set hfiles [glob -nocomplain -dir $folderpath -types {hidden f} * .*] 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 dirs [glob -nocomplain -dir $folderpath -types d $opt_glob]
set hlinks [glob -nocomplain -dir $folderpath -types {hidden l} $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 hfiles [glob -nocomplain -dir $folderpath -types {hidden f} $opt_glob]
set files [glob -nocomplain -dir $folderpath -types f $opt_glob] set files [glob -nocomplain -dir $folderpath -types f $opt_glob]
} }
#note struct::set difference produces unordered result #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 #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 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 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_times $timed_types
dict set effective_opts -with_sizes $sized_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 #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} { proc range_boundaries {start end chunksizes args} {
lassign [punk::get_leading_opts_and_values {\ set argd [punk::args::get_dict {
-offset 0\ -offset -default 0
} $args] _opts opts _vals remainingargs } $args]
lassign [dict values $argd] opts remainingargs
} }
@ -1650,16 +1650,19 @@ namespace eval punk::fileline::system {
#gets very slow (comparitively) with large resultsets #gets very slow (comparitively) with large resultsets
proc _range_spans_chunk_boundaries_tcl {start end chunksize args} { proc _range_spans_chunk_boundaries_tcl {start end chunksize args} {
if {$chunksize < 1} {error "chunksize must be > 0"} ;#sanitycheck in case called directly if {$chunksize < 1} {error "chunksize must be > 0"} ;#sanitycheck in case called directly
set defaults [dict create\ set opts [dict create\
-offset 0\ -offset 0\
] ]
set known_opts [dict keys $defaults]
foreach {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
error "unknown option '$k'. Known options: $known_opts" -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] 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 # oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::lib::class { tcl::namespace::eval punk::lib::class {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::lib::class}] #[subsection {Namespace punk::lib::class}]
#[para] class definitions #[para] class definitions
if {[info commands [namespace current]::interface_sample1] eq ""} { if {[info commands [tcl::namespace::current]::interface_sample1] eq ""} {
#*** !doctools #*** !doctools
#[list_begin enumerated] #[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 #wiki.tcl-lang.org/page/ensemble+extend
# extend an ensemble-like routine with the routines in some namespace # extend an ensemble-like routine with the routines in some namespace
proc extend {routine extension} { proc extend {routine extension} {
if {![string match ::* $routine]} { if {![string match ::* $routine]} {
set resolved [uplevel 1 [list ::namespace which $routine]] set resolved [uplevel 1 [list ::tcl::namespace::which $routine]]
if {$resolved eq {}} { if {$resolved eq {}} {
error [list {no such routine} $routine] error [list {no such routine} $routine]
} }
set routine $resolved set routine $resolved
} }
set routinens [namespace qualifiers $routine] set routinens [tcl::namespace::qualifiers $routine]
if {$routinens eq {::}} { if {$routinens eq {::}} {
set routinens {} set routinens {}
} }
set routinetail [namespace tail $routine] set routinetail [tcl::namespace::tail $routine]
if {![string match ::* $extension]} { if {![string match ::* $extension]} {
set extension [uplevel 1 [ 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] error [list {no such namespace} $extension]
} }
set extension [namespace eval $extension [ set extension [tcl::namespace::eval $extension [
list [namespace which namespace] current]] list [tcl::namespace::which namespace] current]]
namespace eval $extension [ tcl::namespace::eval $extension [
list [namespace which namespace] export *] list [tcl::namespace::which namespace] export *]
while 1 { while 1 {
set renamed ${routinens}::${routinetail}_[info cmdcount] set renamed ${routinens}::${routinetail}_[info cmdcount]
if {[namespace which $renamed] eq {}} break if {[tcl::namespace::which $renamed] eq {}} break
} }
rename $routine $renamed rename $routine $renamed
namespace eval $extension [ tcl::namespace::eval $extension [
list namespace ensemble create -command $routine -unknown [ list namespace ensemble create -command $routine -unknown [
list apply {{renamed ensemble routine args} { list apply {{renamed ensemble routine args} {
list $renamed $routine list $renamed $routine
@ -147,7 +147,7 @@ namespace eval punk::lib::ensemble {
} }
} }
namespace eval punk::lib::compat { tcl::namespace::eval punk::lib::compat {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::lib::compat}] #[subsection {Namespace punk::lib::compat}]
#[para] compatibility functions for features that may not be available in earlier Tcl versions #[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]. # Bind [string insert] to [::tcl::string::insert].
namespace ensemble configure string -map [dict replace\ tcl::namespace::ensemble configure string -map [tcl::dict::replace\
[namespace ensemble configure string -map]\ [tcl::namespace::ensemble configure string -map]\
insert ::tcl::string::insert] insert ::tcl::string::insert]
} }
#*** !doctools #*** !doctools
@ -327,7 +327,7 @@ namespace eval punk::lib::compat {
# Base namespace # Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::lib { namespace eval punk::lib {
namespace export * tcl::namespace::export *
#variable xyz #variable xyz
#*** !doctools #*** !doctools
@ -335,15 +335,192 @@ namespace eval punk::lib {
#[para] Core API functions for punk::lib #[para] Core API functions for punk::lib
#[list_begin definitions] #[list_begin definitions]
proc range {from to args} { if {[info commands lseq] ne ""} {
if {[info commands lseq] ne ""} { #tcl 8.7+ lseq significantly faster, especially for larger ranges
#tcl 8.7+ lseq significantly faster for larger ranges #support minimal set from to
return [lseq $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} { proc is_list_all_in_list {small large} {
package require struct::list package require struct::list
package require struct::set package require struct::set
@ -356,7 +533,87 @@ namespace eval punk::lib {
return [expr {[llength $i] == 0}] 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 #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} { proc lmapflat_closure {varnames list script} {
set result [list] set result [list]
@ -368,29 +625,29 @@ namespace eval punk::lib {
#capture - use uplevel 1 or namespace eval depending on context #capture - use uplevel 1 or namespace eval depending on context
set capture [uplevel 1 { set capture [uplevel 1 {
apply { varnames { apply { varnames {
set capturevars [dict create] set capturevars [tcl::dict::create]
set capturearrs [dict create] set capturearrs [tcl::dict::create]
foreach fullv $varnames { foreach fullv $varnames {
set v [namespace tail $fullv] set v [tcl::namespace::tail $fullv]
upvar 1 $v var upvar 1 $v var
if {[info exists var]} { if {[info exists var]} {
if {(![array exists var])} { if {(![array exists var])} {
dict set capturevars $v $var tcl::dict::set capturevars $v $var
} else { } else {
dict set capturearrs capturedarray_$v [array get var] tcl::dict::set capturearrs capturedarray_$v [array get var]
} }
} else { } 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 #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] } } [info vars]
} ] } ]
# -- --- --- # -- --- ---
set cvars [dict get $capture vars] set cvars [tcl::dict::get $capture vars]
set carrs [dict get $capture arrs] set carrs [tcl::dict::get $capture arrs]
set apply_script "" set apply_script ""
foreach arrayalias [dict keys $carrs] { foreach arrayalias [tcl::dict::keys $carrs] {
set realname [string range $arrayalias [string first _ $arrayalias]+1 end] set realname [string range $arrayalias [string first _ $arrayalias]+1 end]
append apply_script [string map [list %realname% $realname %arrayalias% $arrayalias] { append apply_script [string map [list %realname% $realname %arrayalias% $arrayalias] {
array set %realname% [set %arrayalias%][unset %arrayalias%] array set %realname% [set %arrayalias%][unset %arrayalias%]
@ -409,9 +666,9 @@ namespace eval punk::lib {
foreach $varnames $list { foreach $varnames $list {
lappend result {*}[apply\ lappend result {*}[apply\
[list\ [list\
[concat $varnames [dict keys $cvars] [dict keys $carrs] ]\ [concat $varnames [tcl::dict::keys $cvars] [tcl::dict::keys $carrs] ]\
$apply_script\ $apply_script\
] {*}[subst $values] {*}[dict values $cvars] {*}[dict values $carrs] ] ] {*}[subst $values] {*}[tcl::dict::values $cvars] {*}[tcl::dict::values $carrs] ]
} }
return $result return $result
} }
@ -447,8 +704,15 @@ namespace eval punk::lib {
return $result return $result
} }
proc lmapflat {varnames list script} { #proc lmapflat {varnames list script} {
concat {*}[uplevel 1 [list lmap $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} { proc dict_getdef {dictValue args} {
@ -456,8 +720,8 @@ namespace eval punk::lib {
error {wrong # args: should be "dict_getdef dictValue ?key ...? key default"} error {wrong # args: should be "dict_getdef dictValue ?key ...? key default"}
} }
set keys [lrange $args -1 end-1] set keys [lrange $args -1 end-1]
if {[dict exists $dictValue {*}$keys]} { if {[tcl::dict::exists $dictValue {*}$keys]} {
return [dict get $dictValue {*}$keys] return [tcl::dict::get $dictValue {*}$keys]
} else { } else {
return [lindex $args end] return [lindex $args end]
} }
@ -475,6 +739,23 @@ namespace eval punk::lib {
# return "ok" # 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} { proc lindex_resolve {list index} {
#*** !doctools #*** !doctools
@ -492,7 +773,7 @@ namespace eval punk::lib {
if {![llength $list]} { if {![llength $list]} {
return -1 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]} { if {[string is integer -strict $index]} {
#can match +i -i #can match +i -i
if {$index < 0} { if {$index < 0} {
@ -566,7 +847,7 @@ namespace eval punk::lib {
} else { } 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 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 #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} { if {[llength $argopts]%2 !=0} {
error "[namespace current]::hex2dec arguments prior to list_largeHex must be option/value pairs - received '$argopts'" 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\ -validate 1\
-empty_as_hex "INVALID set -empty_as_hex to a hex string e.g FF if empty values should be replaced"\ -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 { 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_validate [tcl::dict::get $opts -validate]
set opt_empty [dict get $opts -empty_as_hex] 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]}] 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} { if {[llength $argopts]%2 !=0} {
error "[namespace current]::dec2hex arguments prior to list_decimals must be option/value pairs - received '$argopts'" 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\ -width 1\
-case upper\ -case upper\
-empty_as_decimal "INVALID set -empty_as_decimal to a number if empty values should be replaced"\ -empty_as_decimal "INVALID set -empty_as_decimal to a number if empty values should be replaced"\
] ]
set known_opts [dict keys $defaults] set known_opts [tcl::dict::keys $defaults]
set fullopts [dict create] set fullopts [tcl::dict::create]
foreach {k v} $argopts { 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_width [tcl::dict::get $opts -width]
set opt_case [dict get $opts -case] set opt_case [tcl::dict::get $opts -case]
set opt_empty [dict get $opts -empty_as_decimal] set opt_empty [tcl::dict::get $opts -empty_as_decimal]
# -- --- --- --- # -- --- --- ---
@ -933,35 +1214,35 @@ namespace eval punk::lib {
proc sieve n { proc sieve n {
set primes [list] set primes [list]
if {$n < 2} {return $primes} if {$n < 2} {return $primes}
set nums [dict create] set nums [tcl::dict::create]
for {set i 2} {$i <= $n} {incr i} { for {set i 2} {$i <= $n} {incr i} {
dict set nums $i "" tcl::dict::set nums $i ""
} }
set next 2 set next 2
set limit [expr {sqrt($n)}] set limit [expr {sqrt($n)}]
while {$next <= $limit} { 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 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 { proc sieve2 n {
set primes [list] set primes [list]
if {$n < 2} {return $primes} if {$n < 2} {return $primes}
set nums [dict create] set nums [tcl::dict::create]
for {set i 2} {$i <= $n} {incr i} { for {set i 2} {$i <= $n} {incr i} {
dict set nums $i "" tcl::dict::set nums $i ""
} }
set next 2 set next 2
set limit [expr {sqrt($n)}] set limit [expr {sqrt($n)}]
while {$next <= $limit} { 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 lappend primes $next
#dict for {next -} $nums break #dict for {next -} $nums break
set next [lindex $nums 0] set next [lindex $nums 0]
} }
return [concat $primes [dict keys $nums]] return [concat $primes [tcl::dict::keys $nums]]
} }
proc hasglobs {str} { 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. #[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 #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} { proc askuser {question} {
@ -1044,7 +1325,7 @@ namespace eval punk::lib {
set answer [gets stdin] set answer [gets stdin]
} }
} finally { } finally {
fconfigure stdin -blocking [dict get $stdin_state -blocking] fconfigure stdin -blocking [tcl::dict::get $stdin_state -blocking]
} }
return $answer return $answer
} }
@ -1162,13 +1443,13 @@ namespace eval punk::lib {
} }
proc list_as_lines2 {args} { 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? #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 -joinchar -default \n
*values -min 1 -max 1 *values -min 1 -max 1
} $args]] opts values } $args]] opts values
puts "opts:$opts" puts "opts:$opts"
puts "values:$values" 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} { proc lines_as_list {args} {
@ -1189,7 +1470,7 @@ namespace eval punk::lib {
} else { } else {
set opts [lrange $args 0 end-1] 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] set bposn [lsearch $opts -block]
if {$bposn < 0} { if {$bposn < 0} {
lappend opts -block {} 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 #-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 #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) #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 *opts -any 1
-block -default {} -block -default {}
} $args]] opts valuedict } $args]] opts valuedict
tailcall linelist {*}$opts {*}[dict values $valuedict] tailcall linelist {*}$opts {*}[tcl::dict::values $valuedict]
} }
# important for pipeline & match_assign # 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 text [string map [list \r\n \n] $text] ;#review - option?
set arglist [lrange $args 0 end-1] set arglist [lrange $args 0 end-1]
set opts [dict create\ set opts [tcl::dict::create\
-block {trimhead1 trimtail1}\ -block {trimhead1 trimtail1}\
-line {}\ -line {}\
-commandprefix ""\ -commandprefix ""\
@ -1232,7 +1513,7 @@ namespace eval punk::lib {
foreach {o v} $arglist { foreach {o v} $arglist {
switch -- $o { switch -- $o {
-block - -line - -commandprefix - -ansiresets - -ansireplays { -block - -line - -commandprefix - -ansiresets - -ansireplays {
dict set opts $o $v tcl::dict::set opts $o $v
} }
default { default {
error "linelist: Unrecognized option '$o' usage:$usage" 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]} { if {[llength $opt_block]} {
foreach bo $opt_block { foreach bo $opt_block {
switch -- $bo { 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_left 0
set tl_right 0 set tl_right 0
set tl_both 0 set tl_both 0
@ -1299,11 +1580,11 @@ namespace eval punk::lib {
set tl_both 1 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_ansireplays} {
if {$opt_ansiresets eq "auto"} { if {$opt_ansiresets eq "auto"} {
set opt_ansiresets 1 set opt_ansiresets 1
@ -1414,7 +1695,11 @@ namespace eval punk::lib {
set replaycodes $RST ;#todo - default? set replaycodes $RST ;#todo - default?
set transformed [list] set transformed [list]
#shortcircuit common case of no ansi #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} { if {$opt_ansiresets} {
foreach ln $linelist { foreach ln $linelist {
lappend transformed $RST$ln$RST 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) #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} { proc show_jump_tables {args} {
set data [tcl::unsupported::disassemble proc $procname] #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 result ""
set in_jt 0 set in_jt 0
foreach ln [split $data \n] { foreach ln [split $data \n] {
@ -1626,6 +1932,12 @@ namespace eval punk::lib {
return $result 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 #*** !doctools
#[list_end] [comment {--- end definitions namespace punk::lib ---}] #[list_end] [comment {--- end definitions namespace punk::lib ---}]
} }
@ -1639,7 +1951,7 @@ namespace eval punk::lib {
#todo - way to generate 'internal' docs separately? #todo - way to generate 'internal' docs separately?
#*** !doctools #*** !doctools
#[section Internal] #[section Internal]
namespace eval punk::lib::system { tcl::namespace::eval punk::lib::system {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::lib::system}] #[subsection {Namespace punk::lib::system}]
#[para] Internal functions that are not part of the API #[para] Internal functions that are not part of the API
@ -1664,6 +1976,51 @@ namespace eval punk::lib::system {
return false 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} { proc mostFactorsBelow {n} {
##*** !doctools ##*** !doctools
@ -1888,7 +2245,7 @@ namespace eval punk::lib::system {
} }
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready ## Ready
package provide punk::lib [namespace eval punk::lib { package provide punk::lib [tcl::namespace::eval punk::lib {
variable pkg punk::lib variable pkg punk::lib
variable version variable version
set version 0.1.1 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
package require punk::cap::handlers::templates ;#handler for templates cap
punk::cap::register_capabilityname punk.templates ::punk::cap::handlers::templates tcl::namespace::eval punk::mix {
proc init {} {
package require punk::mix::templates ;#registers as provider pkg for 'punk.templates' capability with punk::cap package require punk::cap::handlers::templates ;#handler for templates cap
if {[catch {punk::mix::templates::provider register *} errM]} { punk::cap::register_capabilityname punk.templates ::punk::cap::handlers::templates ;#time taken should generally be sub 200us
puts stderr "punk::mix failure during punk::mix::templates::provider register *"
puts stderr $errM package require punk::mix::templates ;#registers as provider pkg for 'punk.templates' capability with punk::cap
puts stderr "-----" set t [time {
puts stderr $::errorInfo 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::base
package require punk::mix::cli package require punk::mix::cli
namespace eval punk::mix { package provide punk::mix [tcl::namespace::eval punk::mix {
}
package provide punk::mix [namespace eval punk::mix {
variable version variable version
set version 0.2 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} { proc module_subpath {modulename} {
set modulename [string trim $modulename :] set modulename [string trim $modulename :]
set nsq [namespace qualifiers $modulename] set nsq [namespace qualifiers $modulename]
return [string map [list :: /] $nsq] return [string map {:: /} $nsq]
} }
proc get_build_workdir {path} { 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 #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 {} { 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?) #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? #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])} { 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 {[string length $project_base]} {
if {[file exists $project_base/src] && [string tolower [pwd]] ne [string tolower $project_base/src]} { if {[file exists $project_base/src] && [string tolower [pwd]] ne [string tolower $project_base/src]} {
puts stderr "Try cd to $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 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} { if {[string first : $testname] >=0} {
error "$opt_errorprefix '$modulename' can only contain paired colons" error "$opt_errorprefix '$modulename' can only contain paired colons"
} }
@ -366,13 +367,13 @@ namespace eval punk::mix::cli {
if {"project" in $repotypes} { if {"project" in $repotypes} {
#punk project #punk project
if {![catch {package require textblock; package require patternpunk}]} { 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 append result \n
} }
} }
set timeline [exec fossil timeline -n 5 -t ci] 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 append result $timeline
if {$opt_v} { if {$opt_v} {
set repostate [punk::repo::workingdir_state $repopath -repopaths $repopaths -repotypes fossil] 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 #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] set allfiles [lib::layout_all_files $layout]
return [join $allfiles \n] return [join $allfiles \n]
} }
@ -77,6 +82,13 @@ namespace eval punk::mix::commandset::layout {
} }
proc _default {args} { 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] set tdict_low_to_high [as_dict {*}$args]
#convert to screen order - with higher priority at the top #convert to screen order - with higher priority at the top
set tdict [dict create] 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 eval punk::mix::commandset::loadedlib {
namespace export * namespace export *
#search automatically wrapped in * * - can contain inner * ? globs #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 catch {package require frobznodule666} ;#ensure pkg system has loaded/searched for everything
if {[catch {package require natsort}]} { if {[catch {package require natsort}]} {
set has_natsort 0 set has_natsort 0
} else { } else {
set has_natsort 1 set has_natsort 1
} }
if {[regexp {[?*]} $searchstring]} { set packages [package names]
#caller has specified specific glob pattern - use it set matches [list]
#todo - respect supplied case only if uppers present? require another flag? foreach search $searchstrings {
set matches [lsearch -all -inline -nocase [package names] $searchstring] if {[regexp {[?*]} $search]} {
} else { #caller has specified specific glob pattern - use it
#make it easy to search for anything #todo - respect supplied case only if uppers present? require another flag?
set matches [lsearch -all -inline -nocase [package names] "*$searchstring*"] 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 matchinfo [list]
set highlight_ansi [a+ web-limegreen underline]
set RST [a]
foreach m $matches { foreach m $matches {
set versions [package versions $m] 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} { if {$has_natsort} {
set versions [natsort::sort $versions] set versions [natsort::sort $versions]
} else { } else {
set versions [lsort $versions] 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] 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} { proc loaded.search {searchstring} {
set search_result [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 [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] set loadinfo_lines [split $loadinfo \n]
if {[catch {llength $loadinfo}]} { if {[catch {llength $loadinfo}]} {
set loadinfo_is_listshaped 0 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(?) #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 libfound $lib_diversion_name
set loadinfo [package ifneeded $libfound $ver] 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] set loadinfo_lines [split $loadinfo \n]
if {[catch {llength $loadinfo}]} { if {[catch {llength $loadinfo}]} {
set loadinfo_is_listshaped 0 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 tablewidth [expr {$widest(name) + 1 + $widest(pathtype) + 1 + $widest(name)}]
set table "" set table ""
append table [string repeat - $tablewidth] \n 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 append table [string repeat - $tablewidth] \n
foreach n $names pt $pathtypes p $paths { 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 #return all module templates with repeated ones suffixed with .2 .3 etc
proc templates_dict {args} { 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 package require punk::cap
if {[punk::cap::capability_has_handler punk.templates]} { if {[punk::cap::capability_has_handler punk.templates]} {
set template_folder_dict [punk::cap::call_handler punk.templates get_itemdict_moduletemplates {*}$args] 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" 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 year [clock format [clock seconds] -format %Y]
set defaults [list\ set moduletypes [punk::mix::cli::lib::module_types]
-project \uFFFF\ # use \uFFFD because unicode replacement char should consistently render as 1 wide
-version \uFFFF\ set argspecs [subst {
-license <unspecified>\ -project -default \uFFFD
-template punk.module\ -version -default \uFFFD
-type \uFFFF\ -license -default <unspecified>
-force 0\ -template -default punk.module
-quiet 0\ -type -default \uFFFD -choices {$moduletypes}
] -force -default 0 -type boolean
set opts [dict merge $defaults $args] -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 #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) #-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 # we need this value before looking at the named argument
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_version_supplied [dict get $opts -version] 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" set opt_version "0.1.0"
} else { } else {
set opt_version $opt_version_supplied set opt_version $opt_version_supplied
@ -178,7 +194,7 @@ namespace eval punk::mix::commandset::module {
} else { } else {
set vmsg "from -version option: $opt_version_supplied" 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} { if {$vcompare_is_mversion_bigger != 0} {
#is bigger or smaller #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" 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] 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 set opt_type [lindex [punk::mix::cli::lib::module_types] 0] ;#default to plain
} }
if {$opt_type ni [punk::mix::cli::lib::module_types]} { 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 tablewidth [expr {$widest(name) + 1 + $widest(pathtype) + $widest(path)}]
set table "" set table ""
append table [string repeat - $tablewidth] \n 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 append table [string repeat - $tablewidth] \n
foreach n $names pt $pathtypes p $paths { 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 { oo::objdefine provider {
method register {{capabilityname_glob *}} { method register {{capabilityname_glob *}} {
#puts registering punk::mix::templates $capabilityname #puts registering punk::mix::templates $capabilityname
next next $capabilityname_glob
} }
method capabilities {} { method capabilities {} {
next 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 { foreach {relpath module} $bootsupport_modules {
set module [string trim $module :] 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] set srclocation [file join $projectroot $relpath $module_subpath]
#puts stdout "$relpath $module $module_subpath $srclocation" #puts stdout "$relpath $module $module_subpath $srclocation"
set pkgmatches [glob -nocomplain -dir $srclocation -tail [namespace tail $module]-*] set pkgmatches [glob -nocomplain -dir $srclocation -tail [namespace tail $module]-*]
@ -617,7 +617,7 @@ if {[file exists $mapfile]} {
fconfigure $fdmap -translation binary fconfigure $fdmap -translation binary
set mapdata [read $fdmap] set mapdata [read $fdmap]
close $fdmap close $fdmap
set mapdata [string map [list \r\n \n] $mapdata] set mapdata [string map {\r\n \n} $mapdata]
set missing [list] set missing [list]
foreach ln [split $mapdata \n] { foreach ln [split $mapdata \n] {
set ln [string trim $ln] 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::lib
package require punk::args 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_current "::"
variable ns_re_cache [dict create] ;#cache regular expressions used in globmatchns variable ns_re_cache [dict create] ;#cache regular expressions used in globmatchns
namespace export nsjoin nsprefix nstail nsparts nseval nsimport_noclobber corp 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] set has_globchars [regexp {[*?]} $ns_or_glob]
if {$is_absolute} { if {$is_absolute} {
if {!$has_globchars} { if {!$has_globchars} {
if {![namespace exists $ns_or_glob]} { if {![tcl::namespace::exists $ns_or_glob]} {
error "cannot change to namespace $ns_or_glob" error "cannot change to namespace $ns_or_glob"
} }
set ns_current $ns_or_glob set ns_current $ns_or_glob
@ -71,7 +71,7 @@ namespace eval punk::ns {
} else { } else {
if {!$has_globchars} { if {!$has_globchars} {
set nsnext [nsjoin $ns_current $ns_or_glob] 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" error "cannot change to namespace $ns_or_glob"
} }
set ns_current $nsnext set ns_current $nsnext
@ -86,7 +86,7 @@ namespace eval punk::ns {
set ns_display "\n$ns_queried" set ns_display "\n$ns_queried"
if {$ns_current eq $ns_queried} { if {$ns_current eq $ns_queried} {
if {$ns_current in [info commands $ns_current] } { 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} { if {[llength $ensemble_info] > 0} {
#this namespace happens to match ensemble command. #this namespace happens to match ensemble command.
#todo - keep cache of encountered ensembles from commands.. and examine namespace in the configure info. #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 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} { if {$ns_exists} {
error "Namespace $nspath already exists" error "Namespace $nspath already exists"
} }
#namespace eval [nsprefix $nspath] [list namespace eval [nstail $nspath] {}] #tcl::namespace::eval [nsprefix $nspath] [list tcl::namespace::eval [nstail $nspath] {}]
nseval [nsprefix $nspath] [list ::namespace eval [nstail $nspath] {}] nseval [nsprefix $nspath] [list ::tcl::namespace::eval [nstail $nspath] {}]
n/ $nspath n/ $nspath
} }
@ -157,7 +157,7 @@ namespace eval punk::ns {
} }
#recursive nseval - for introspection of weird namespace trees #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} { proc nseval_script {location} {
set parts [nsparts $location] set parts [nsparts $location]
if {[lindex $parts 0] eq ""} { if {[lindex $parts 0] eq ""} {
@ -171,7 +171,7 @@ namespace eval punk::ns {
set i 0 set i 0
set tails [lrepeat [llength $parts] ""] set tails [lrepeat [llength $parts] ""]
foreach ns $parts { foreach ns $parts {
set cmdlist [list ::namespace eval $ns] set cmdlist [list ::tcl::namespace::eval $ns]
set t "" set t ""
if {$i > 0} { if {$i > 0} {
append body " <lb>" append body " <lb>"
@ -194,7 +194,7 @@ namespace eval punk::ns {
set scr {[::list ::eval [::uplevel <i> {::set script}]]} set scr {[::list ::eval [::uplevel <i> {::set script}]]}
set up [expr {$i - 1}] 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] set body [string map [list <script> $scr] $body]
return $body return $body
@ -203,7 +203,7 @@ namespace eval punk::ns {
if {![string match ::* $fqns]} { if {![string match ::* $fqns]} {
error "nseval only accepts a fully qualified namespace" 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::pipecmds::nseval_$loc
set cmd ::punk_dynamic::ns::eval-$loc set cmd ::punk_dynamic::ns::eval-$loc
if {$cmd ni [info commands $cmd]} { if {$cmd ni [info commands $cmd]} {
@ -221,7 +221,7 @@ namespace eval punk::ns {
set tail [nstail $fqns] set tail [nstail $fqns]
#puts ">>> parent $parent tail $tail" #puts ">>> parent $parent tail $tail"
#set nslist [nseval $parent [list ::namespace children $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] return [lsort $nslist]
} }
@ -281,7 +281,7 @@ namespace eval punk::ns {
# #
proc nsprefix {{nspath ""}} { proc nsprefix {{nspath ""}} {
#normalize the common case of :::: #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]]] set rawprefix [string range $nspath 0 end-[string length [nstail $nspath]]]
if {$rawprefix eq "::"} { if {$rawprefix eq "::"} {
return $rawprefix 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. #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} { proc nstail {nspath args} {
#normalize the common case of :::: #normalize the common case of ::::
set nspath [string map [list :::: ::] $nspath] set nspath [string map {:::: ::} $nspath]
set mapped [string map [list :: \u0FFF] $nspath] set mapped [string map {:: \u0FFF} $nspath]
set parts [split $mapped \u0FFF] set parts [split $mapped \u0FFF]
set defaults [list -strict 0] 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 #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) #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 #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 #NOTE tcl allows creating ambiguous namespaces. e.g ::punk:::etc:::blah
# is this :: punk :etc :blah or :: 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. #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 :/ #This is important to support leading colon commands such as :/
# ie ::punk:::jjj:::etc -> :: punk :jjj :etc # ie ::punk:::jjj:::etc -> :: punk :jjj :etc
proc nsparts {nspath} { proc nsparts {nspath} {
set nspath [string map [list :::: ::] $nspath] set nspath [string map {:::: ::} $nspath]
set mapped [string map [list :: \u0FFF] $nspath] set mapped [string map {:: \u0FFF} $nspath]
set parts [split $mapped \u0FFF] set parts [split $mapped \u0FFF]
if {[lindex $parts end] eq ""} { if {[lindex $parts end] eq ""} {
@ -387,7 +387,8 @@ namespace eval punk::ns {
} elseif {$seg eq "**"} { } elseif {$seg eq "**"} {
lappend pats {.*} lappend pats {.*}
} else { } else {
set seg [string map [list . {[.]}] $seg] #set seg [string map [list . {[.]}] $seg]
set seg [string map {. [.]} $seg]
if {[regexp {[*?]} $seg]} { if {[regexp {[*?]} $seg]} {
set pat [string map [list ** {.*} * {[^:]*} ? {[^:]}] $seg] set pat [string map [list ** {.*} * {[^:]*} ? {[^:]}] $seg]
lappend pats "$pat" lappend pats "$pat"
@ -469,14 +470,14 @@ namespace eval punk::ns {
set base $location set base $location
set tailparts $subnslist set tailparts $subnslist
} }
if {![namespace exists $base]} { if {![tcl::namespace::exists $base]} {
return [list] return [list]
} }
#set parent [nsprefix $ns_absolute] #set parent [nsprefix $ns_absolute]
#set tail [nstail $ns_absolute] #set tail [nstail $ns_absolute]
#set allchildren [lsort [nseval $base [list ::namespace children]]] #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 allchildren: $allchildren"
#puts "->base:$base tailparts:$tailparts childcount: [llength $allchildren]" #puts "->base:$base tailparts:$tailparts childcount: [llength $allchildren]"
@ -994,7 +995,19 @@ namespace eval punk::ns {
} }
#info cmdtype available in 8.7+ #info cmdtype available in 8.7+
#safe interps also seem to have it disabled for some reason
proc cmdtype {cmd} { 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 ""} { if {[info commands ::tcl::info::cmdtype] ne ""} {
tailcall info cmdtype $cmd tailcall info cmdtype $cmd
} }
@ -1072,8 +1085,8 @@ namespace eval punk::ns {
#JMN #JMN
set location $ch set location $ch
set exportpatterns [namespace eval $location {::namespace export}] set exportpatterns [tcl::namespace::eval $location {::namespace export}]
set nspathlist [namespace eval $location {::namespace path}] set nspathlist [tcl::namespace::eval $location {::namespace path}]
set nspathdict [dict create] set nspathdict [dict create]
if {$nspathcommands} { if {$nspathcommands} {
foreach pathns $nspathlist { foreach pathns $nspathlist {
@ -1092,7 +1105,7 @@ namespace eval punk::ns {
foreach p $exportpatterns { foreach p $exportpatterns {
if {[regexp {[*?]} $p]} { if {[regexp {[*?]} $p]} {
#lappend matched {*}[nseval $location [list ::info commands [nsjoin ${location} $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 { foreach m $matched {
lappend allexported [nstail $m] lappend allexported [nstail $m]
} }
@ -1101,8 +1114,8 @@ namespace eval punk::ns {
} }
} }
set allexported [lsort -unique $allexported] 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) #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 [namespace eval $location {::info procs}] set allprocs [tcl::namespace::eval $location {::info procs}]
#set allprocs [nseval $location {::info procs}] #set allprocs [nseval $location {::info procs}]
set childtails [lmap v $allchildren {nstail $v}] set childtails [lmap v $allchildren {nstail $v}]
set allaliases [list] set allaliases [list]
@ -1120,7 +1133,7 @@ namespace eval punk::ns {
set interp_aliases [interp aliases ""] set interp_aliases [interp aliases ""]
#use aliases glob - because aliases can be present with or without leading :: #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 #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 raw_aliases [nseval $location [list ::aliases $glob]] ;#'aliases $glob' must be passed as list, not separate args to namespace eval.
set aliases [list] set aliases [list]
foreach a $raw_aliases { foreach a $raw_aliases {
@ -1363,8 +1376,8 @@ namespace eval punk::ns {
} }
::set all_ns_commands [::info commands [::punk::ns::nsjoin $base $what]] ::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 #important not to call tcl::namespace::eval (or punk::ns::nseval) on non-existant base - or it will be created
::if {![::namespace exists $base]} { ::if {![::tcl::namespace::exists $base]} {
::continue ::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 #this was to support weird namespaces with leading/trailing colons - not an important usecase for the cost
::set matchedcommands [::pipeswitch { ::set matchedcommands [::pipeswitch {
::pipecase \ ::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] #lappend commandlist {*}[@@ok/result= $matchedcommands]
#need to pull result from matchedcommands dict #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]] ::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 #important not to call tcl::namespace::eval (or punk::ns::nseval) on non-existant base - or it will be created
::if {![::namespace exists $base]} { ::if {![::tcl::namespace::exists $base]} {
::continue ::continue
} }
::set all_ns_tails [::lmap v $all_ns_commands {::punk::ns::nstail $v}] ::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 #maintenance: similar in punk::winrun
@ -1701,7 +1714,7 @@ namespace eval punk::ns {
} }
default { default {
if {[string match ::* $pkg_or_existing_ns]} { 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]] set ver [package require [string range $pkg_or_existing_ns 2 end]]
} else { } else {
set ver "" set ver ""
@ -1713,7 +1726,7 @@ namespace eval punk::ns {
} }
} }
} }
if {[namespace exists $ns]} { if {[tcl::namespace::exists $ns]} {
if {[llength $cmdargs]} { if {[llength $cmdargs]} {
set binding {} set binding {}
#if {[info level] == 1} { #if {[info level] == 1} {
@ -1724,10 +1737,10 @@ namespace eval punk::ns {
#} #}
#set vars [uplevel 1 {*}$get_vars] #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 #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 { apply { varnames {
while {"prev_args[incr n]" in $varnames} {} while {"prev_args[incr n]" in $varnames} {}
set capturevars [dict create] set capturevars [dict create]
@ -1799,8 +1812,8 @@ namespace eval punk::ns {
lassign [dict values [punk::args::get_dict $argspecs $args]] opts values lassign [dict values [punk::args::get_dict $argspecs $args]] opts values
set sourcepattern [dict get $values sourcepattern] set sourcepattern [dict get $values sourcepattern]
set source_ns [namespace qualifiers $sourcepattern] set source_ns [tcl::namespace::qualifiers $sourcepattern]
if {![namespace exists $source_ns]} { if {![tcl::namespace::exists $source_ns]} {
error "nsimport_noclobber error namespace $source_ns not found" error "nsimport_noclobber error namespace $source_ns not found"
} }
set target_ns [dict get $opts -targetnamespace] set target_ns [dict get $opts -targetnamespace]
@ -1811,9 +1824,9 @@ namespace eval punk::ns {
set target_ns [punk::nsjoin $nscaller $target_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_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] set a_exported_tails [list]
foreach epattern $a_export_patterns { foreach epattern $a_export_patterns {
set matches [lsearch -all -inline $a_tails $epattern] set matches [lsearch -all -inline $a_tails $epattern]
@ -1825,7 +1838,7 @@ namespace eval punk::ns {
} }
set imported_commands [list] set imported_commands [list]
foreach e $a_exported_tails { 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 "" set cmd ""
if {![catch {namespace import <a>::<func>}]} { if {![catch {namespace import <a>::<func>}]} {
set cmd <func> set cmd <func>
@ -1890,7 +1903,7 @@ namespace eval punk::ns {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready ## Ready
package provide punk::ns [namespace eval punk::ns { package provide punk::ns [tcl::namespace::eval punk::ns {
variable version variable version
set version 0.1.0 set version 0.1.0
}] }]

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

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

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

@ -131,7 +131,8 @@ namespace eval punk::path {
** {lappend pats {.*}} ** {lappend pats {.*}}
default { default {
set seg [string map [list {^ {\^} $ {\$} [} {\[} ( {\(} \{ \\\{ \\ {\\}] $seg] ;#treat regex characters in the input as literals 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]} { if {[regexp {[*?]} $seg]} {
set pat [string map [list ** {.*} * {[^/]*} ? {[^/]}] $seg] set pat [string map [list ** {.*} * {[^/]*} ? {[^/]}] $seg]
lappend pats "$pat" 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] list of path patterns to exclude - may include * and ** path segments e.g /usr/**
#[para]no natsorting - so order is dependent on filesystem #[para]no natsorting - so order is dependent on filesystem
lassign [punk::get_leading_opts_and_values { set argd [punk::args::get_dict {
-directory "\uFFFF" -directory -default "\uFFFF"
-call-depth-internal 0 -call-depth-internal -default 0 -type integer
-antiglob_paths {} -antiglob_paths -default {}
} $args] _o opts _v tailglobs *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 opt_antiglob_paths [dict get $opts -antiglob_paths]
set CALLDEPTH [dict get $opts -call-depth-internal] 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]} { if {[catch {exec {*}$fossilcmd all ls} repolines]} {
error "fossil_get_configdb cannot find repositories" error "fossil_get_configdb cannot find repositories"
} else { } else {
set repolines [string map [list \r\n \n] $repolines] set repolines [string map {\r\n \n} $repolines]
set repolist [split $repolines \n] set repolist [split $repolines \n]
set dbcmd "fossil_get_configdb_tempdb" set dbcmd "fossil_get_configdb_tempdb"
foreach repodb $repolist { foreach repodb $repolist {
@ -1383,12 +1383,12 @@ namespace eval punk::repo {
return [lindex [split $content \x1A] 0] return [lindex [split $content \x1A] 0]
} }
proc grep {pattern data} { 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] return [lsearch -all -inline -glob [split $data \n] $pattern]
} }
proc rgrep {pattern data} { 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] 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. #\\servername\share etc or \\?\UNC\servername\share etc.
proc is_unc_path {path} { proc is_unc_path {path} {
set strcopy_path [punk::objclone $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} { if {[string first "//" $strcopy_path] == 0} {
#check for "Dos device path" syntax #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) #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"} { if {[string range $strcopy_path 4 6] eq "UNC"} {
return 1 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) #(can exist on server shares and on NTFS - but standard apps can't access without dos device syntax)
proc is_dos_device_path {path} { proc is_dos_device_path {path} {
set strcopy_path [punk::objclone $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 range $strcopy_path 0 3] in [list "//?/" "//./"]} { if {[string range $strcopy_path 0 3] in {//?/ //./}} {
return 1 return 1
} else { } else {
return 0 return 0

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

@ -1,5 +1,5 @@
# -*- tcl -*- # -*- 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. # 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. # 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 {} { 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\ -targets $o_targets\
-keep_installrecords $o_keep_installrecords\ -keep_installrecords $o_keep_installrecords\
-keep_skipped $o_keep_skipped\ -keep_skipped $o_keep_skipped\
-keep_inprogress $o_keep_inprogress\ -keep_inprogress $o_keep_inprogress\
body $o_records\ body $o_records
]
set record [dict create tag FILEINFO {*}$fields]
} }
#retrieve last completed record for the fileset ie exclude SKIPPED,INSTALL-INPROGRESS,DELETE-INPROGRESS,MODIFY-INPROGRESS #retrieve last completed record for the fileset ie exclude SKIPPED,INSTALL-INPROGRESS,DELETE-INPROGRESS,MODIFY-INPROGRESS
@ -199,7 +204,21 @@ namespace eval punkcheck {
} else { } else {
set tsiso_end "" 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\ -tsiso_begin $tsiso_begin\
-ts_begin $o_ts_begin\ -ts_begin $o_ts_begin\
-tsiso_end $tsiso_end\ -tsiso_end $tsiso_end\
@ -208,10 +227,8 @@ namespace eval punkcheck {
-source $o_rel_sourceroot\ -source $o_rel_sourceroot\
-targets $o_rel_targetroot\ -targets $o_rel_targetroot\
-types $o_types\ -types $o_types\
-config $o_configdict\ -config $o_configdict
]
set record [dict create tag EVENT {*}$fields]
} }
method get_id {} { method get_id {} {
return $o_id return $o_id
@ -1294,7 +1311,7 @@ namespace eval punkcheck {
dict unset config -call-depth-internal dict unset config -call-depth-internal
dict unset config -max_depth dict unset config -max_depth
dict unset config -subdirlist dict unset config -subdirlist
dict for {k v} $config { tcl::dict::for {k v} $config {
if {$v eq "\uFFFF"} { if {$v eq "\uFFFF"} {
dict unset config $k dict unset config $k
} }

2446
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