Browse Source

punk::args fixes, auto_execok override

master
Julian Noble 2 months ago
parent
commit
1f68b9aa62
  1. 10
      src/bootsupport/modules/commandstack-0.3.tm
  2. 309
      src/bootsupport/modules/overtype-1.6.5.tm
  3. 242
      src/bootsupport/modules/punk-0.1.tm
  4. 1
      src/bootsupport/modules/punk/aliascore-0.1.0.tm
  5. 2
      src/bootsupport/modules/punk/ansi-0.1.1.tm
  6. 1930
      src/bootsupport/modules/punk/args-0.1.0.tm
  7. 4
      src/bootsupport/modules/punk/char-0.1.0.tm
  8. 2
      src/bootsupport/modules/punk/console-0.1.1.tm
  9. 2
      src/bootsupport/modules/punk/fileline-0.1.0.tm
  10. 2
      src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm
  11. 2
      src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  12. 4
      src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  13. 122
      src/bootsupport/modules/punk/ns-0.1.0.tm
  14. 2
      src/bootsupport/modules/punk/path-0.1.0.tm
  15. 39
      src/bootsupport/modules/punk/repo-0.1.1.tm
  16. 2
      src/bootsupport/modules/textblock-0.1.2.tm
  17. 8567
      src/bootsupport/modules/textblock-0.1.3.tm
  18. 4
      src/modules/argparsingtest-999999.0a1.0.tm
  19. 3
      src/modules/patternpunk-1.1.tm
  20. 2
      src/modules/poshinfo-999999.0a1.0.tm
  21. 242
      src/modules/punk-0.1.tm
  22. 1
      src/modules/punk/aliascore-999999.0a1.0.tm
  23. 2
      src/modules/punk/ansi-999999.0a1.0.tm
  24. 1930
      src/modules/punk/args-999999.0a1.0.tm
  25. 100
      src/modules/punk/args/tclcore-999999.0a1.0.tm
  26. 8
      src/modules/punk/blockletter-999999.0a1.0.tm
  27. 4
      src/modules/punk/char-999999.0a1.0.tm
  28. 2
      src/modules/punk/console-999999.0a1.0.tm
  29. 2
      src/modules/punk/fileline-999999.0a1.0.tm
  30. 2
      src/modules/punk/mix/commandset/loadedlib-999999.0a1.0.tm
  31. 2
      src/modules/punk/mix/commandset/module-999999.0a1.0.tm
  32. 4
      src/modules/punk/nav/fs-999999.0a1.0.tm
  33. 122
      src/modules/punk/ns-999999.0a1.0.tm
  34. 2
      src/modules/punk/path-999999.0a1.0.tm
  35. 2
      src/modules/punk/repl-0.1.tm
  36. 39
      src/modules/punk/repo-999999.0a1.0.tm
  37. 8
      src/modules/punk/safe-999999.0a1.0.tm
  38. 2
      src/modules/punk/sixel-999999.0a1.0.tm
  39. 376
      src/modules/punk/winshell-999999.0a1.0.tm
  40. 3
      src/modules/punk/winshell-buildversion.txt
  41. 93
      src/modules/textblock-999999.0a1.0.tm
  42. 2
      src/modules/textblock-buildversion.txt
  43. 10
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/commandstack-0.3.tm
  44. 309
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.6.5.tm
  45. 242
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk-0.1.tm
  46. 1
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/aliascore-0.1.0.tm
  47. 2
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm
  48. 1930
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args-0.1.0.tm
  49. 4
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/char-0.1.0.tm
  50. 2
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/console-0.1.1.tm
  51. 2
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/fileline-0.1.0.tm
  52. 2
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm
  53. 2
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  54. 4
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  55. 122
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ns-0.1.0.tm
  56. 2
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm
  57. 39
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm
  58. 2
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.2.tm
  59. 8567
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.3.tm
  60. 10
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/commandstack-0.3.tm
  61. 309
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.6.5.tm
  62. 242
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk-0.1.tm
  63. 1
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/aliascore-0.1.0.tm
  64. 2
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm
  65. 1930
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args-0.1.0.tm
  66. 4
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/char-0.1.0.tm
  67. 2
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/console-0.1.1.tm
  68. 2
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/fileline-0.1.0.tm
  69. 2
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm
  70. 2
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  71. 4
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  72. 122
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ns-0.1.0.tm
  73. 2
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm
  74. 39
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm
  75. 2
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.2.tm
  76. 8567
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.3.tm
  77. 10
      src/vendormodules/commandstack-0.3.tm
  78. 309
      src/vendormodules/overtype-1.6.5.tm
  79. 4
      src/vfs/_vfscommon.vfs/modules/argparsingtest-0.1.0.tm
  80. 10
      src/vfs/_vfscommon.vfs/modules/commandstack-0.3.tm
  81. 309
      src/vfs/_vfscommon.vfs/modules/overtype-1.6.5.tm
  82. 3
      src/vfs/_vfscommon.vfs/modules/patternpunk-1.1.tm
  83. 2
      src/vfs/_vfscommon.vfs/modules/poshinfo-0.1.0.tm
  84. 242
      src/vfs/_vfscommon.vfs/modules/punk-0.1.tm
  85. 1
      src/vfs/_vfscommon.vfs/modules/punk/aliascore-0.1.0.tm
  86. 2
      src/vfs/_vfscommon.vfs/modules/punk/ansi-0.1.1.tm
  87. 1930
      src/vfs/_vfscommon.vfs/modules/punk/args-0.1.0.tm
  88. 100
      src/vfs/_vfscommon.vfs/modules/punk/args/tclcore-0.1.0.tm
  89. 8
      src/vfs/_vfscommon.vfs/modules/punk/blockletter-0.1.0.tm
  90. 4
      src/vfs/_vfscommon.vfs/modules/punk/char-0.1.0.tm
  91. 2
      src/vfs/_vfscommon.vfs/modules/punk/console-0.1.1.tm
  92. 2
      src/vfs/_vfscommon.vfs/modules/punk/fileline-0.1.0.tm
  93. 2
      src/vfs/_vfscommon.vfs/modules/punk/mix/commandset/loadedlib-0.1.0.tm
  94. 2
      src/vfs/_vfscommon.vfs/modules/punk/mix/commandset/module-0.1.0.tm
  95. 4
      src/vfs/_vfscommon.vfs/modules/punk/nav/fs-0.1.0.tm
  96. 122
      src/vfs/_vfscommon.vfs/modules/punk/ns-0.1.0.tm
  97. 2
      src/vfs/_vfscommon.vfs/modules/punk/path-0.1.0.tm
  98. 2
      src/vfs/_vfscommon.vfs/modules/punk/repl-0.1.tm
  99. 39
      src/vfs/_vfscommon.vfs/modules/punk/repo-0.1.1.tm
  100. 8
      src/vfs/_vfscommon.vfs/modules/punk/safe-0.1.0.tm
  101. Some files were not shown because too many files have changed in this diff Show More

10
src/bootsupport/modules/commandstack-0.3.tm

@ -211,6 +211,7 @@ namespace eval commandstack {
set new_code [string trim $procbody]
if {$current_code eq $new_code} {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command with same procbody - Aborting rename."
puts stderr [show_stack $command]
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command - but appears to be with new code - proceeding."
puts stdout "----------"
@ -223,6 +224,7 @@ namespace eval commandstack {
}
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command, but is not immediate predecessor - proceeding anyway... (untested)"
puts stderr
set next_target ::commandstack::renamed_commands::${mungedcommand}-${munged_next_implementor}-$mungedrenamer-$tokenid
set do_rename 1
}
@ -374,13 +376,13 @@ namespace eval commandstack {
proc show_stack {{commandname_glob *}} {
variable all_stacks
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
if {[package provide punk::lib] ne ""} {
return [punk::lib::pdict -channel none all_stacks $commandname_glob/@*/@*.@*]
} else {
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
set result ""
set matchedkeys [dict keys $all_stacks $commandname_glob]
#don't try to calculate widest on empty list

309
src/bootsupport/modules/overtype-1.6.5.tm

@ -449,7 +449,7 @@ tcl::namespace::eval overtype {
4 {
set inputchunks [list]
foreach ln [split $overblock \n] {
lappend inputchunks [string cat $ln \n]
lappend inputchunks $ln\n
}
if {[llength $inputchunks]} {
lset inputchunks end [tcl::string::range [lindex $inputchunks end] 0 end-1]
@ -499,9 +499,9 @@ tcl::namespace::eval overtype {
#set overtext [tcl::string::cat [lindex $replay_codes_overlay $overidx] $overtext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set overtext $replay_codes_overlay$overtext
if {[tcl::dict::exists $replay_codes_underlay $row]} {
set undertext [tcl::string::cat [tcl::dict::get $replay_codes_underlay $row] $undertext]
set undertext [tcl::dict::get $replay_codes_underlay $row]$undertext
}
#review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary -
#but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l
@ -1365,8 +1365,8 @@ tcl::namespace::eval overtype {
set udiff [expr {$renderwidth - $ulen}]
set undertext "$undertext[string repeat { } $udiff]"
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
#review - right-to-left langs should elide on left! - extra option required
@ -1518,8 +1518,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1545,7 +1545,7 @@ tcl::namespace::eval overtype {
}
}
if {$show_ellipsis} {
set ellipsis [tcl::string::cat $replay_codes $opt_ellipsistext]
set ellipsis $replay_codes$opt_ellipsistext
#todo - overflow on left if allign = right??
set rendered [overtype::right $rendered $ellipsis]
}
@ -1701,8 +1701,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1769,6 +1769,9 @@ tcl::namespace::eval overtype {
return [join $outputlines \n]
}
variable optimise_ptruns 10 ;# can be set to zero to disable the ptruns branches
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# renderline written from a left-right line orientation perspective as a first-shot at getting something useful.
# ultimately right-to-left, top-to-bottom and bottom-to-top are probably needed.
@ -1802,6 +1805,7 @@ tcl::namespace::eval overtype {
#[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation.
#puts stderr "renderline '$args'"
variable optimise_ptruns
if {[llength $args] < 2} {
error {usage: ?-info 0|1? ?-startcolumn <int>? ?-cursor_column <int>? ?-cursor_row <int>|""? ?-transparent [0|1|<regexp>]? ?-expand_right [1|0]? undertext overtext}
@ -1973,58 +1977,107 @@ tcl::namespace::eval overtype {
foreach {pt code} $undermap {
#pt = plain text
#append pt_underchars $pt
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
if {$pt ne ""} {
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set hex [format %x [scan $p1 %c]] ;#punk::char::char_hex
set re [tcl::string::cat {^[} \\U$hex {]+$}]
set is_ptrun [regexp $re $pt]
}
if {$is_ptrun} {
#switch -- $p1 {
# " " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
# a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
# z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
# set width 1
# }
# default {
# if {$p1 eq "\u0000"} {
# #use null as empty cell representation - review
# #use of this will probably collide with some application at some point
# #consider an option to set the empty cell character
# set width 1
# } else {
# set width [grapheme_width_cached $p1] ;# when zero???
# }
# }
#}
set width [grapheme_width_cached $p1] ;# when zero???
set ptlen [string length $pt]
if {$width <= 1} {
#review - 0 and 1?
incr i_u $ptlen
lappend understacks {*}[lrepeat $ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $ptlen $u_gx_stack]
lappend undercols {*}[lrepeat $ptlen $p1]
} else {
incr i_u $ptlen ;#2nd col empty str - so same as above
set 2ptlen [expr {$ptlen * 2}]
lappend understacks {*}[lrepeat $2ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $2ptlen $u_gx_stack]
set l [concat {*}[lrepeat $ptlen [list $p1 ""]]
lappend undercols {*}$l
unset l
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme]
set grapheme $gvis
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
#zero width still acts as 1 below??? review what should happen
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme] ;#can only use with graphemes that have a single replacement char..
set grapheme $gvis
set width 1
}
}
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
#underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2168,23 +2221,31 @@ tcl::namespace::eval overtype {
# -- --- --- --- --- --- --- ---
####
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left of the right number of columns.
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left containing the right number of columns.
#this will be processed as transparent - and handle doublewidth underlay characters appropriately
set startpad_overlay [string repeat " " [expr {$opt_colstart -1}]]
append startpad_overlay $overdata ;#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpad_overlay ne ""} {
if {[punk::ansi::ta::detect $startpad_overlay]} {
set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
set startpadding [string repeat " " [expr {$opt_colstart -1}]]
#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpadding ne "" || $overdata ne ""} {
if {[punk::ansi::ta::detect $overdata]} {
set overmap [punk::ansi::ta::split_codes_single $startpadding$overdata]
} else {
#single plaintext part
set overmap [list $startpad_overlay]
set overmap [list $startpadding$overdata]
}
} else {
set overmap [list]
}
#set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
####
#todo - detect plain ascii no-ansi input line (aside from leading ansi reset)
#will that allow some optimisations?
#todo - detect repeated transparent char in overlay
#regexp {^(.)\1+$} ;#backtracking regexp - relatively slow.
# - try set c [string index $data 0]; regexp [string map [list %c% $c] {^[%c%]+$}] $data
#we should be able to optimize to pass through the underlay??
#???
set colcursor $opt_colstart
#TODO - make a little virtual column object
@ -2206,41 +2267,78 @@ tcl::namespace::eval overtype {
#experiment
set overlay_grapheme_control_stacks [list]
foreach {pt code} $overmap {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
if {$pt ne ""} {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+$}]
set is_ptrun [regexp $re $pt]
#leading only? we would have to check for graphemes at the trailing boundary?
#set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+}]
#set is_ptrun [regexp -indices $re $pt runrange]
#if {$is_ptrun && 1} {
#}
}
if {$is_ptrun} {
#review - in theory a run over a certain length won't be part of some grapheme combo (graphemes can be long e.g 44?, but not as runs(?))
#could be edge cases for runs at line end? (should be ok as we include trailing \n in our data)
set len [string length $pt]
set g_element [list g $p1]
#lappend overstacks {*}[lrepeat $len $o_codestack]
#lappend overstacks_gx {*}[lrepeat $len $o_gxstack]
#incr i_o $len
#lappend overlay_grapheme_control_list {*}[lrepeat $len [list g $p1]]
#lappend overlay_grapheme_control_stacks {*}[lrepeat $len $o_codestack]
set pi 0
incr i_o $len
while {$pi < $len} {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
lappend overlay_grapheme_control_list $g_element
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr pi
}
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2324,6 +2422,7 @@ tcl::namespace::eval overtype {
set o_codestack [list $temp_cursor_saved]
lappend overlay_grapheme_control_list [list other $code]
} else {
#review
if {[punk::ansi::codetype::is_gx_open $code]} {
set o_gxstack [list "gx0_on"]
lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets
@ -2837,7 +2936,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 3 end]]
}
7CSI - 7OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
set codenorm $leadernorm[tcl::string::range $code 2 end]
}
7DCS {
#ESC P
@ -2849,7 +2949,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
}
7ESC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
set codenorm $leadernorm[tcl::string::range $code 1 end]
}
8CSI - 8OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
@ -2886,7 +2987,12 @@ tcl::namespace::eval overtype {
A {
#Row move - up
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
set num $param
#todo
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row -$num
@ -2904,9 +3010,12 @@ tcl::namespace::eval overtype {
B {
#CUD - Cursor Down
#Row move - down
set num $param
lassign [split $param {;}] num modifierkey
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move down
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row $num
@ -2924,7 +3033,10 @@ tcl::namespace::eval overtype {
#todo - consider right-to-left cursor mode (e.g Hebrew).. some day.
#cursor forward
#right-arrow/move forward
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
#todo - retrict to moving 1 position past datalen? restrict to column width?
@ -3028,7 +3140,10 @@ tcl::namespace::eval overtype {
#puts stdout "<-back"
#cursor back
#left-arrow/move-back when ltr mode
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
set version 2
@ -4518,7 +4633,7 @@ tcl::namespace::eval overtype::priv {
if {$existing eq "\0"} {
lset o $i $c
} else {
lset o $i [string cat $existing $c]
lset o $i $existing$c
}
}
#is actually addgrapheme?

242
src/bootsupport/modules/punk-0.1.tm

@ -12,6 +12,242 @@ namespace eval punk {
#lazyload twapi ?
catch {package require vfs} ;#attempt load now so we can use faster 'package provide' to test existence later
variable can_exec_windowsapp
set can_exec_windowsapp unknown ;#don't spend a potential X00ms testing until needed
variable windowsappdir
set windowsappdir ""
variable cmdexedir
set cmdexedir ""
proc rehash {{refresh 0}} {
global auto_execs
if {!$refresh} {
unset -nocomplain auto_execs
} else {
set names [array names auto_execs]
unset -nocomplain auto_execs
foreach nm $names {
auto_execok_windows $nm
}
}
return
}
proc ::punk::auto_execok_original name [info body ::auto_execok]
variable better_autoexec
#set better_autoexec 0 ;#use this var via better_autoexec only
#proc ::punk::auto_execok_windows name {
# ::punk::auto_execok_original $name
#}
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
set has_commandstack [expr {![catch {package require commandstack}]}]
if {![interp issafe] && $has_commandstack && $::tcl_platform(platform) eq "windows"} {
#still a caching version of auto_execok - but with proper(fixed) search order
#set b [info body ::auto_execok]
#proc ::auto_execok_original name $b
proc better_autoexec {{onoff ""}} {
variable better_autoexec
if {$onoff eq ""} {
return $better_autoexec
}
if {![string is boolean -strict $onoff]} {
error "better_autoexec argument 'onoff' must be a boolean, received: $onoff"
}
if {$onoff && ($onoff != $better_autoexec)} {
puts "Turning on better_autoexec - search PATH first then extension"
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
punk::rehash
} elseif {!$onoff && ($onoff != $better_autoexec)} {
puts "Turning off better_autoexec - search extension then PATH"
set better_autoexec 0
proc ::punk::auto_execok_windows name {
::punk::auto_execok_original $name
}
punk::rehash
} else {
puts "no change"
}
}
#better_autoexec $better_autoexec ;#init to default
proc auto_execok_better name {
global auto_execs env tcl_platform
if {[info exists auto_execs($name)]} {
return $auto_execs($name)
}
#puts stdout "[a+ red]...[a]"
set auto_execs($name) ""
set shellBuiltins [list assoc cls copy date del dir echo erase exit ftype \
md mkdir mklink move rd ren rename rmdir start time type ver vol]
if {[info exists env(PATHEXT)]} {
# Add an initial ; to have the {} extension check first.
set execExtensions [split ";$env(PATHEXT)" ";"]
} else {
set execExtensions [list {} .com .exe .bat .cmd]
}
if {[string tolower $name] in $shellBuiltins} {
# When this is command.com for some reason on Win2K, Tcl won't
# exec it unless the case is right, which this corrects. COMSPEC
# may not point to a real file, so do the check.
set cmd $env(COMSPEC)
if {[file exists $cmd]} {
set cmd [file attributes $cmd -shortname]
}
return [set auto_execs($name) [list $cmd /c $name]]
}
if {[llength [file split $name]] != 1} {
foreach ext $execExtensions {
set file ${name}${ext}
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
return ""
}
#change1
#set path "[file dirname [info nameofexecutable]];.;"
set path "[file dirname [info nameofexecutable]];"
if {[info exists env(SystemRoot)]} {
set windir $env(SystemRoot)
} elseif {[info exists env(WINDIR)]} {
set windir $env(WINDIR)
}
if {[info exists windir]} {
append path "$windir/system32;$windir/system;$windir;"
}
foreach var {PATH Path path} {
if {[info exists env($var)]} {
append path ";$env($var)"
}
}
#change2
set lookfor [lmap ext $execExtensions {string cat ${name} ${ext}}]
foreach dir [split $path {;}] {
#set dir [file normalize $dir]
# Skip already checked directories
if {[info exists checked($dir)] || ($dir eq "")} {
continue
}
set checked($dir) {}
foreach match [glob -nocomplain -dir $dir -tail {*}$lookfor] {
set file [file join $dir $match]
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
}
#foreach ext $execExtensions {
#unset -nocomplain checked
#foreach dir [split $path {;}] {
# # Skip already checked directories
# if {[info exists checked($dir)] || ($dir eq "")} {
# continue
# }
# set checked($dir) {}
# set file [file join $dir ${name}${ext}]
# if {[file exists $file] && ![file isdirectory $file]} {
# return [set auto_execs($name) [list $file]]
# }
#}
#}
return ""
}
#review - what if punk package reloaded - but ::auto_execs has updated path for winget.exe?
#what if we create another interp and use the same ::auto_execs? The appdir won't be detected.
#TODO - see if there is a proper windows way to determine where the 'reparse point' apps are installed
#winget is installed on all modern windows and is an example of the problem this addresses
#we target apps with same location
#the main purpose of this override is to support windows app executables (installed as 'reparse points')
#for Tcl versions prior to the 2025-01 fix by APN https://core.tcl-lang.org/tcl/tktview/4f0b5767ac
#versions prior to this will use cmd.exe to resolve the links
set stackrecord [commandstack::rename_command -renamer ::punk auto_execok name {
#set windowsappdir "%appdir%"
upvar ::punk::can_exec_windowsapp can_exec_windowsapp
upvar ::punk::windowsappdir windowsappdir
upvar ::punk::cmdexedir cmdexedir
if {$windowsappdir eq ""} {
#we are targeting the winget location under the presumption this is where microsoft store apps are stored as 'reparse points'
#Tcl (2025) can't exec when given a path to these 0KB files
#This path is probably something like C:/Users/username/AppData/Local/Microsoft/WindowsApps
if {!([info exists ::env(LOCALAPPDATA)] &&
[file exists [set testapp [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]]])} {
#should be unlikely to get here - unless LOCALAPPDATA missing
set windowsappdir [file dirname [lindex [::punk::auto_execok_windows winget.exe] 0]]
puts stderr "(resolved winget by search)"
} else {
set windowsappdir [file dirname $testapp]
}
}
#set default_auto [$COMMANDSTACKNEXT $name]
set default_auto [::punk::auto_execok_windows $name]
#if {$name ni {cmd cmd.exe}} {
# unset -nocomplain ::auto_execs
#}
if {$default_auto eq ""} {
return
}
set namedir [file dirname [lindex $default_auto 0]]
if {$namedir eq $windowsappdir} {
if {$can_exec_windowsapp eq "unknown"} {
if {[catch {exec [file join $windowsappdir winget.exe] --version}]} {
set can_exec_windowsapp 0
} else {
set can_exec_windowsapp 1
}
}
if {$can_exec_windowsapp} {
return [file join $windowsappdir $name]
}
if {$cmdexedir eq ""} {
#cmd.exe very unlikely to move
set cmdexedir [file dirname [lindex [::punk::auto_execok_windows cmd.exe] 0]]
#auto_reset never seems to exist as a command - because auto_reset deletes all commands in the ::auto_index
#anyway.. it has other side effects (affects auto_load)
}
return "[file join $cmdexedir cmd.exe] /c $name"
}
return $default_auto
}]
}
}
@ -5321,8 +5557,8 @@ namespace eval punk {
}
return -options $opts $msg
} else {
dict incr opts -level
return -options $opts $msg
dict incr opts -level
return -options $opts $msg
}
}
}
@ -7152,7 +7388,7 @@ namespace eval punk {
dict filter $result value {?*}
}
punk::args::definition {
punk::args::define {
@id -id ::punk::inspect
@cmd -name punk::inspect -help\
"Function to display values - used pimarily in a punk pipeline.

1
src/bootsupport/modules/punk/aliascore-0.1.0.tm

@ -115,6 +115,7 @@ tcl::namespace::eval punk::aliascore {
pdict ::punk::lib::pdict\
plist {::punk::lib::pdict -roottype list}\
showlist {::punk::lib::showdict -roottype list}\
rehash ::punk::rehash\
showdict ::punk::lib::showdict\
ansistrip ::punk::ansi::ansistrip\
stripansi ::punk::ansi::ansistrip\

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

@ -5568,6 +5568,7 @@ tcl::namespace::eval punk::ansi::class {
}
#does not affect object state
#REVIEW - icu or equiv required
method DoCount {plaintext} {
#- combiners/diacritics just map them away here - but for consistency we need to combine unicode grapheme clusters too.
#todo - joiners 200d? zwnbsp
@ -5672,6 +5673,7 @@ tcl::namespace::eval punk::ansi::class {
method renderbuf {} {
#get the underlying renderobj - if any
#return $o_renderout ;#also class_ansistring
if {$o_renderer eq ""} {error "renderbuf error: no active renderer"}
return [$o_renderer renderbuf]
}
method render {{maxgraphemes ""}} {

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

File diff suppressed because it is too large Load Diff

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

@ -1246,6 +1246,10 @@ tcl::namespace::eval punk::char {
return [charset_dict "Box Drawing"]
}
proc char_hex {char} {
return [format %08x [scan $char %c]]
}
proc char_info_hex {hex args} {
set hex [tcl::string::map [list _ ""] $hex]
if {[tcl::string::is xdigit -strict $hex]} {

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

@ -1186,7 +1186,7 @@ namespace eval punk::console {
#todo - change -inoutchannels to -terminalobject with prebuilt default
punk::args::definition {
punk::args::define {
@id -id ::punk::console::cell_size
-inoutchannels -default {stdin stdout} -type list
@values -min 0 -max 1

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

@ -1251,7 +1251,7 @@ namespace eval punk::fileline {
#[para] Core API functions for punk::fileline
#[list_begin definitions]
punk::args::definition {
punk::args::define {
@id -id ::punk::fileline::get_textinfo
@cmd -name punk::fileline::get_textinfo -help\
"return: textinfo object instance"

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

@ -26,7 +26,7 @@ package require punk::lib
namespace eval punk::mix::commandset::loadedlib {
namespace export *
#search automatically wrapped in * * - can contain inner * ? globs
punk::args::definition {
punk::args::define {
@id -id ::punk::mix::commandset::loadedlib::search
@cmd -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}

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

@ -141,7 +141,7 @@ namespace eval punk::mix::commandset::module {
set moduletypes [punk::mix::cli::lib::module_types]
punk::args::definition [subst {
punk::args::define [subst {
@id -id ::punk::mix::commandset::module::new
@cmd -name "punk::mix::commandset::module::new" -help\
"Create a new module file in the appropriate folder within src/modules.

4
src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -636,7 +636,7 @@ tcl::namespace::eval punk::nav::fs {
# c:/repo/jn/punk/../../blah
#dirfiles assumes we don't have glob chars in the filenames or paths - dirfiles_dict can be called directly with explicit -tailglob in the rare case that assumption doesn't hold
# dirfiles will test last segment (tail) of supplied searchspecs for fileness vs folderness (when no globchars present in tail) so that it can pass the appropriate flags downstream
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles
-stripbase -default 1 -type boolean
-formatsizes -default 1 -type boolean -help "Format file size numbers for clarity"
@ -992,7 +992,7 @@ tcl::namespace::eval punk::nav::fs {
return [dict merge $listing $updated]
}
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles_dict_as_lines
-stripbase -default 0 -type boolean
-formatsizes -default 1 -type boolean

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

@ -1893,7 +1893,31 @@ tcl::namespace::eval punk::ns {
}
} |data@@ok/result> {lmap v $data {punk::ns::nstail $v}} |> lsort |> {join $data \n} <ns/0|
proc ensemble_subcommands {origin} {
punk::args::define {
@id -id ::punk::ns::ensemble_subcommands
@cmd -name punk::ns::ensemble_subcommands -help\
"Returns a dictionary keyed on subcommand with each value pointing
to the implementation command.
This is not guaranteed to be complete - e.g for ensembles which use
the namespace ensemble 'unknown' mechanism to implement subcommands.
The subcommand information is gathered from entries in the '-map' as
well as those exported from the namespace in '-namespace' if the
'-subcommands' list has been configured for the ensemble.
"
-return -default dict -choices {show dict} -choicelabels {
show "display the result in 'showdict' format"
}
@values -min 1 -max 1
origin -help\
"Name of ensemble command for which subcommand info is gathered."
}
proc ensemble_subcommands {args} {
set argd [punk::args::get_by_id ::punk::ns::ensemble_subcommands $args]
set opts [dict get $argd opts]
set origin [dict get $argd values origin]
set ensembleinfo [namespace ensemble configure $origin]
set prefixes [dict get $ensembleinfo -prefixes]
set map [dict get $ensembleinfo -map]
@ -1936,12 +1960,16 @@ tcl::namespace::eval punk::ns {
}
}
}
return $subcommand_dict
if {[dict get $opts -return] eq "dict"} {
return $subcommand_dict
} else {
return [punk::lib::showdict $subcommand_dict]
}
}
#todo - -cache or -refresh to configure whether we introspect ensembles/objects each time?
# - as this is interactive generally introspection should be ok at the top level
# but if we need to go down multiple levels of subcommands generating/testing prefixes - could be an issue ??
punk::args::definition {
punk::args::define -dynamic 0 {
@id -id ::punk::ns::arginfo
@cmd -name punk::ns::arginfo -help\
"Show usage info for a command.
@ -1965,6 +1993,10 @@ tcl::namespace::eval punk::ns {
exit the interp etc)
"
-return -type string -default table -choices {string table tableobject}
} {${[punk::args::get_spec ::punk::args::arg_error -scheme]}} {
-- -type none -help\
"End of options marker
Use this if the command to view begins with a -"
@ -1977,6 +2009,13 @@ tcl::namespace::eval punk::ns {
}
proc arginfo {args} {
lassign [dict values [punk::args::get_by_id ::punk::ns::arginfo $args]] leaders opts values received
#review - setting this afterwards is an architecture smell - we should be able to override the default in the dynamic part
#todo - enable retrieving by id just the record_opts part - so we can treat as a dict directly, as well as easily apply it as a different flag name.
if {![dict exists $received -scheme]} {
dict set opts -scheme info
}
set querycommand [dict get $values commandpath]
set queryargs [dict get $values subcommand]
punk::args::update_definitions ;#ensure any packages that register PUNKARGS have been loaded
@ -2035,9 +2074,11 @@ tcl::namespace::eval punk::ns {
} else {
#namespace as relative to current doesn't seem to exist
#Tcl would also attempt to resolve as global
set numvals [expr {[llength $queryargs]+1}]
#puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
#set numvals [expr {[llength $queryargs]+1}]
##puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $querycommand {*}$queryargs]]
#set origin $querycommand
#set resolved $querycommand
@ -2068,9 +2109,10 @@ tcl::namespace::eval punk::ns {
#(possible curried arguments)
#review - curried arguments could be for ensembles!
set targetword $word1
set numvals [expr {[llength $queryargs]+1}]
#set numvals [expr {[llength $queryargs]+1}]
#puts "ALIAS THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
}
@ -2115,11 +2157,11 @@ tcl::namespace::eval punk::ns {
set nextqueryargs [list] ;#build a list of prefix-resolved queryargs
set queryargs_untested $queryargs
foreach q $queryargs {
if {[llength [dict get $def leader_names]]} {
set subitems [dict get $def leader_names]
if {[llength [dict get $def LEADER_NAMES]]} {
set subitems [dict get $def LEADER_NAMES]
if {[llength $subitems]} {
set next [lindex $subitems 0]
set arginfo [dict get $def arg_info $next]
set arginfo [dict get $def ARG_INFO $next]
set allchoices [list]
set choices [punk::args::system::Dict_getdef $arginfo -choices {}]
@ -2140,8 +2182,11 @@ tcl::namespace::eval punk::ns {
lpop queryargs_untested 0
if {$resolved_q ne $q} {
#we have our first difference - recurse with new query args
set numvals [expr {[llength $queryargs]+1}]
return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
#set numvals [expr {[llength $queryargs]+1}]
#return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
return [ punk::ns::arginfo {*}$opts $querycommand {*}$nextqueryargs {*}$queryargs_untested]
}
#check if subcommands so far have a custom args def
set currentid [list $querycommand {*}$nextqueryargs]
@ -2188,7 +2233,7 @@ tcl::namespace::eval punk::ns {
new {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} new"
@cmd -name "${$origin} new" -help\
"create object with specified command name.
@ -2200,22 +2245,22 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin new"]
}
create {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} create"
@cmd -name "${$origin} create" -help\
"create object with specified command name.
@ -2229,29 +2274,29 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin create"]
}
destroy {
#review - generally no doc
# but we may want notes about a specific destructor
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(audodef)${$origin} destroy"
@cmd -name "destroy" -help\
"delete object, calling destructor if any.
destroy accepts no arguments."
@values -min 0 -max 0
}]
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin destroy"]
}
default {
@ -2301,7 +2346,7 @@ tcl::namespace::eval punk::ns {
#assert - if we pre
set autoid "(autodef)$location $c1"
set arglist [lindex $def 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@cmd -name "${$location} ${$c1}" -help\
"(autogenerated)
@ -2314,13 +2359,13 @@ tcl::namespace::eval punk::ns {
1 {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
}
2 {
append argspec \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
append argdef \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
}
default {
error "punk::ns::arginfo unexpected argument signature '$arglist'\ndef:$def\nimplementaions:$implementations"
@ -2328,7 +2373,7 @@ tcl::namespace::eval punk::ns {
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
} else {
return "unable to resolve $origin method $c1"
@ -2378,14 +2423,14 @@ tcl::namespace::eval punk::ns {
set vline [list method -choices $public_methods -choicelabels $choicelabeldict -choiceprefix 0] ;#methods must be specified in full always? - review
#puts stderr "--->$vline"
set idauto "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$idauto}
@cmd -name "Object: ${$origin}" -help\
"Instance of class: ${$class} (info autogenerated)"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $idauto]
}
privateObject {
@ -2457,7 +2502,8 @@ tcl::namespace::eval punk::ns {
set match [tcl::prefix::match $subcommands [lindex $queryargs 0]]
if {$match in $subcommands} {
set subcmd [dict get $subcommand_dict $match]
return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
#return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
return [arginfo {*}$opts {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
}
}
@ -2491,15 +2537,15 @@ tcl::namespace::eval punk::ns {
set vline [list subcommand -choices $subcommands -choiceprefix $prefixes -choicelabels $choicelabeldict]
set autoid "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$autoid}
@cmd -help\
"(autogenerated)
ensemble: ${$origin}"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
}
@ -2918,7 +2964,7 @@ tcl::namespace::eval punk::ns {
}
interp alias "" use "" punk::ns::pkguse
punk::args::definition {
punk::args::define {
@id -id ::punk::ns::nsimport_noclobber
@cmd -name punk::ns::nsimport_noclobber -help\
"Import exported commands from a namespace into either the current namespace,

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

@ -644,7 +644,7 @@ namespace eval punk::path {
return $ismatch
}
punk::args::definition {
punk::args::define {
@id -id ::punk::path::treefilenames
-directory -type directory -help\
"folder in which to begin recursive scan for files."

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

@ -65,6 +65,22 @@ namespace eval punk::repo {
variable PUNKARGS
variable PUNKARGS_aliases
variable cached_command_paths
set cached_command_paths [dict create]
#anticipating possible removal of buggy caching from auto_execok
#mentioned in: https://core.tcl-lang.org/tcl/tktview/4dc35e0c0c
#this would leave the application to decide what it wants to cache in that regard.
proc Cached_auto_execok {name} {
return [auto_execok $name]
#variable cached_command_paths
#if {[dict exists $cached_command_paths $name]} {
# return [dict get $cached_command_paths $name]
#}
#set resolved [auto_execok $name]
#dict set cached_command_paths $name $resolved
#return $resolved
}
proc get_fossil_usage {} {
set allcmds [runout -n fossil help -a]
set mainhelp [runout -n fossil help]
@ -197,7 +213,7 @@ namespace eval punk::repo {
#emit warning whether or not multiple fossil repos
puts stdout [dict get $repostate warnings]
}
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog ne ""} {
{*}$fossil_prog {*}$args
} else {
@ -222,7 +238,10 @@ namespace eval punk::repo {
#uppercase FOSSIL to bypass fossil as alias to fossil_proxy
#only necessary on unix?
#Windows filesystem case insensitive so any non-lowercase fossil version goes out to get an ::auto_execs entry anyway
proc establish_FOSSIL {args} {
#review
if {![info exists ::auto_execs(FOSSIL)]} {
set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp
}
@ -499,7 +518,7 @@ namespace eval punk::repo {
#For this reason we will store 'unchanged' records for both git and fossil so that the combined dict should represent all files in the revision
if {$rt eq "fossil"} {
dict set resultdict repotype fossil
set fossil_cmd [auto_execok fossil]
set fossil_cmd [Cached_auto_execok fossil]
if {$fossil_cmd eq ""} {
error "workingdir_state error: fossil executable doesn't seem to be available"
}
@ -598,7 +617,7 @@ namespace eval punk::repo {
break
} elseif {$rt eq "git"} {
dict set resultdict repotype git
set git_cmd [auto_execok git]
set git_cmd [Cached_auto_execok git]
# -uno = suppress ? lines.
# -b = show ranch and tracking info
#our basic parsing/grepping assumes --porcelain=2
@ -988,7 +1007,7 @@ namespace eval punk::repo {
}
proc fossil_get_repository_file {{path {}}} {
if {$path eq {}} { set path [pwd] }
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set fossilinfo [::exec {*}$fossilcmd info]
@ -1073,7 +1092,7 @@ namespace eval punk::repo {
set startdir $opt_parentfolder
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog eq ""} {
puts stderr "Fossil not found. Please install fossil"
return
@ -1319,7 +1338,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1332,7 +1351,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1343,7 +1362,7 @@ namespace eval punk::repo {
proc fossil_revision {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd info]
@ -1357,7 +1376,7 @@ namespace eval punk::repo {
proc fossil_remote {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd remote ls]
@ -1423,7 +1442,7 @@ namespace eval punk::repo {
set original_cwd [pwd]
#attempt2 - let fossil do it for us - hopefully based on current folder
if {$path eq {}} {set path [pwd]}
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {![llength $fossilcmd]} {
set fossil_ok 0
} else {

2
src/bootsupport/modules/textblock-0.1.2.tm

@ -8367,7 +8367,7 @@ tcl::namespace::eval textblock {
foreach tline $tlines {
if {[tcl::string::first $FSUB $tline] >= 0} {
set content_line [lindex $clines $contentindex]
if {[tcl::string::first $R $content_line] == 0} {
if {[tcl::string::first $R [string range $content_line 0 10]] == 0} {
set content_line [tcl::string::range $content_line $rlen end]
}
#make sure to replay opt_ansibase to the right of the replacement

8567
src/bootsupport/modules/textblock-0.1.3.tm

File diff suppressed because it is too large Load Diff

4
src/modules/argparsingtest-999999.0a1.0.tm

@ -296,7 +296,7 @@ namespace eval argparsingtest {
return [tcl::dict::get $argd opts]
}
punk::args::definition {
punk::args::define {
@id -id ::test1_punkargs_by_id
@cmd -name argtest4 -help "test of punk::args::get_dict comparative performance"
@opts -anyopts 0
@ -318,7 +318,7 @@ namespace eval argparsingtest {
return [tcl::dict::get $argd opts]
}
punk::args::definition {
punk::args::define {
@id -id ::argparsingtest::test1_punkargs2
@cmd -name argtest4 -help "test of punk::args::get_dict comparative performance"
@opts -anyopts 0

3
src/modules/patternpunk-1.1.tm

@ -111,7 +111,8 @@ proc TCL {args} {
return $version
}
punk::args::definition {
punk::args::define {
#Review
@id -id ">punk . poses"
@cmd -name ">punk . poses" -help "Show or list the poses for the Punk mascot"
-censored -default 1 -type boolean -help "Set true to include mild toilet humour poses"

2
src/modules/poshinfo-999999.0a1.0.tm

@ -198,7 +198,7 @@ tcl::namespace::eval poshinfo {
error "unimplemented"
}
punk::args::definition {
punk::args::define {
@id -id ::poshinfo::themes
@cmd -name poshinfo::themes
-format -default all -multiple 1 -choices {all yaml json}\

242
src/modules/punk-0.1.tm

@ -12,6 +12,242 @@ namespace eval punk {
#lazyload twapi ?
catch {package require vfs} ;#attempt load now so we can use faster 'package provide' to test existence later
variable can_exec_windowsapp
set can_exec_windowsapp unknown ;#don't spend a potential X00ms testing until needed
variable windowsappdir
set windowsappdir ""
variable cmdexedir
set cmdexedir ""
proc rehash {{refresh 0}} {
global auto_execs
if {!$refresh} {
unset -nocomplain auto_execs
} else {
set names [array names auto_execs]
unset -nocomplain auto_execs
foreach nm $names {
auto_execok_windows $nm
}
}
return
}
proc ::punk::auto_execok_original name [info body ::auto_execok]
variable better_autoexec
#set better_autoexec 0 ;#use this var via better_autoexec only
#proc ::punk::auto_execok_windows name {
# ::punk::auto_execok_original $name
#}
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
set has_commandstack [expr {![catch {package require commandstack}]}]
if {![interp issafe] && $has_commandstack && $::tcl_platform(platform) eq "windows"} {
#still a caching version of auto_execok - but with proper(fixed) search order
#set b [info body ::auto_execok]
#proc ::auto_execok_original name $b
proc better_autoexec {{onoff ""}} {
variable better_autoexec
if {$onoff eq ""} {
return $better_autoexec
}
if {![string is boolean -strict $onoff]} {
error "better_autoexec argument 'onoff' must be a boolean, received: $onoff"
}
if {$onoff && ($onoff != $better_autoexec)} {
puts "Turning on better_autoexec - search PATH first then extension"
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
punk::rehash
} elseif {!$onoff && ($onoff != $better_autoexec)} {
puts "Turning off better_autoexec - search extension then PATH"
set better_autoexec 0
proc ::punk::auto_execok_windows name {
::punk::auto_execok_original $name
}
punk::rehash
} else {
puts "no change"
}
}
#better_autoexec $better_autoexec ;#init to default
proc auto_execok_better name {
global auto_execs env tcl_platform
if {[info exists auto_execs($name)]} {
return $auto_execs($name)
}
#puts stdout "[a+ red]...[a]"
set auto_execs($name) ""
set shellBuiltins [list assoc cls copy date del dir echo erase exit ftype \
md mkdir mklink move rd ren rename rmdir start time type ver vol]
if {[info exists env(PATHEXT)]} {
# Add an initial ; to have the {} extension check first.
set execExtensions [split ";$env(PATHEXT)" ";"]
} else {
set execExtensions [list {} .com .exe .bat .cmd]
}
if {[string tolower $name] in $shellBuiltins} {
# When this is command.com for some reason on Win2K, Tcl won't
# exec it unless the case is right, which this corrects. COMSPEC
# may not point to a real file, so do the check.
set cmd $env(COMSPEC)
if {[file exists $cmd]} {
set cmd [file attributes $cmd -shortname]
}
return [set auto_execs($name) [list $cmd /c $name]]
}
if {[llength [file split $name]] != 1} {
foreach ext $execExtensions {
set file ${name}${ext}
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
return ""
}
#change1
#set path "[file dirname [info nameofexecutable]];.;"
set path "[file dirname [info nameofexecutable]];"
if {[info exists env(SystemRoot)]} {
set windir $env(SystemRoot)
} elseif {[info exists env(WINDIR)]} {
set windir $env(WINDIR)
}
if {[info exists windir]} {
append path "$windir/system32;$windir/system;$windir;"
}
foreach var {PATH Path path} {
if {[info exists env($var)]} {
append path ";$env($var)"
}
}
#change2
set lookfor [lmap ext $execExtensions {string cat ${name} ${ext}}]
foreach dir [split $path {;}] {
#set dir [file normalize $dir]
# Skip already checked directories
if {[info exists checked($dir)] || ($dir eq "")} {
continue
}
set checked($dir) {}
foreach match [glob -nocomplain -dir $dir -tail {*}$lookfor] {
set file [file join $dir $match]
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
}
#foreach ext $execExtensions {
#unset -nocomplain checked
#foreach dir [split $path {;}] {
# # Skip already checked directories
# if {[info exists checked($dir)] || ($dir eq "")} {
# continue
# }
# set checked($dir) {}
# set file [file join $dir ${name}${ext}]
# if {[file exists $file] && ![file isdirectory $file]} {
# return [set auto_execs($name) [list $file]]
# }
#}
#}
return ""
}
#review - what if punk package reloaded - but ::auto_execs has updated path for winget.exe?
#what if we create another interp and use the same ::auto_execs? The appdir won't be detected.
#TODO - see if there is a proper windows way to determine where the 'reparse point' apps are installed
#winget is installed on all modern windows and is an example of the problem this addresses
#we target apps with same location
#the main purpose of this override is to support windows app executables (installed as 'reparse points')
#for Tcl versions prior to the 2025-01 fix by APN https://core.tcl-lang.org/tcl/tktview/4f0b5767ac
#versions prior to this will use cmd.exe to resolve the links
set stackrecord [commandstack::rename_command -renamer ::punk auto_execok name {
#set windowsappdir "%appdir%"
upvar ::punk::can_exec_windowsapp can_exec_windowsapp
upvar ::punk::windowsappdir windowsappdir
upvar ::punk::cmdexedir cmdexedir
if {$windowsappdir eq ""} {
#we are targeting the winget location under the presumption this is where microsoft store apps are stored as 'reparse points'
#Tcl (2025) can't exec when given a path to these 0KB files
#This path is probably something like C:/Users/username/AppData/Local/Microsoft/WindowsApps
if {!([info exists ::env(LOCALAPPDATA)] &&
[file exists [set testapp [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]]])} {
#should be unlikely to get here - unless LOCALAPPDATA missing
set windowsappdir [file dirname [lindex [::punk::auto_execok_windows winget.exe] 0]]
puts stderr "(resolved winget by search)"
} else {
set windowsappdir [file dirname $testapp]
}
}
#set default_auto [$COMMANDSTACKNEXT $name]
set default_auto [::punk::auto_execok_windows $name]
#if {$name ni {cmd cmd.exe}} {
# unset -nocomplain ::auto_execs
#}
if {$default_auto eq ""} {
return
}
set namedir [file dirname [lindex $default_auto 0]]
if {$namedir eq $windowsappdir} {
if {$can_exec_windowsapp eq "unknown"} {
if {[catch {exec [file join $windowsappdir winget.exe] --version}]} {
set can_exec_windowsapp 0
} else {
set can_exec_windowsapp 1
}
}
if {$can_exec_windowsapp} {
return [file join $windowsappdir $name]
}
if {$cmdexedir eq ""} {
#cmd.exe very unlikely to move
set cmdexedir [file dirname [lindex [::punk::auto_execok_windows cmd.exe] 0]]
#auto_reset never seems to exist as a command - because auto_reset deletes all commands in the ::auto_index
#anyway.. it has other side effects (affects auto_load)
}
return "[file join $cmdexedir cmd.exe] /c $name"
}
return $default_auto
}]
}
}
@ -5321,8 +5557,8 @@ namespace eval punk {
}
return -options $opts $msg
} else {
dict incr opts -level
return -options $opts $msg
dict incr opts -level
return -options $opts $msg
}
}
}
@ -7152,7 +7388,7 @@ namespace eval punk {
dict filter $result value {?*}
}
punk::args::definition {
punk::args::define {
@id -id ::punk::inspect
@cmd -name punk::inspect -help\
"Function to display values - used pimarily in a punk pipeline.

1
src/modules/punk/aliascore-999999.0a1.0.tm

@ -115,6 +115,7 @@ tcl::namespace::eval punk::aliascore {
pdict ::punk::lib::pdict\
plist {::punk::lib::pdict -roottype list}\
showlist {::punk::lib::showdict -roottype list}\
rehash ::punk::rehash\
showdict ::punk::lib::showdict\
ansistrip ::punk::ansi::ansistrip\
stripansi ::punk::ansi::ansistrip\

2
src/modules/punk/ansi-999999.0a1.0.tm

@ -5568,6 +5568,7 @@ tcl::namespace::eval punk::ansi::class {
}
#does not affect object state
#REVIEW - icu or equiv required
method DoCount {plaintext} {
#- combiners/diacritics just map them away here - but for consistency we need to combine unicode grapheme clusters too.
#todo - joiners 200d? zwnbsp
@ -5672,6 +5673,7 @@ tcl::namespace::eval punk::ansi::class {
method renderbuf {} {
#get the underlying renderobj - if any
#return $o_renderout ;#also class_ansistring
if {$o_renderer eq ""} {error "renderbuf error: no active renderer"}
return [$o_renderer renderbuf]
}
method render {{maxgraphemes ""}} {

1930
src/modules/punk/args-999999.0a1.0.tm

File diff suppressed because it is too large Load Diff

100
src/modules/punk/args/tclcore-999999.0a1.0.tm

@ -208,7 +208,7 @@ tcl::namespace::eval punk::args::tclcore {
#todo - make generic - take command and known_groups_dict
proc info_subcommands {} {
package require punk::ns
set subdict [punk::ns::ensemble_subcommands info]
set subdict [punk::ns::ensemble_subcommands -return dict info]
set allsubs [dict keys $subdict]
dict set groups "system" {hostname library nameofexecutable patchlevel script sharedlibextension tclversion}
dict set groups "{proc introspection}" {args body default}
@ -234,8 +234,58 @@ tcl::namespace::eval punk::args::tclcore {
}
append argdef " \}" \n
#todo -choicelabels
#detect subcommand further info available e.g if oo or ensemble or punk::args id exists..
#consider a different mechanism to add a label on rhs of same line as choice (for (i) marker)
return $argdef
}
lappend PUNKARGS [list -dynamic 1 {
#test of @form
@id -id ::AFTER
@cmd -name "Builtin: after" -help\
"Execute a command after a time delay."
# ---------- shared elements -------------
@ref -id common_script_help -help\
"script argument to be concatenated in the same fashion as the concat command"
# ---------- shared elements -------------
@form -form {delay} -synopsis "after ms"
@form -form {schedule_ms} -synopsis "after ms ?script...?"
#@values -form {*} #note "classify next argument as a value not a leader"
ms -form {*} -type int
@values -form {delay} -min 1 -max 1
@values -form {schedule_ms} -min 2
script -form {schedule_ms} -multiple 1 -optional 1 ref-help common_script_help
@form -form {cancelid} -synopsis "after cancel id"
@values
cancel -choices {cancel}
id
@form -form {cancelscript} -synopsis "after cancel script ?script...?"
@values -min 2
cancel -choices {cancel}
script -multiple 1 -optional 0 ref-help common_script_help
@form -form {schedule_idle} -synopsis "after idle script ?script...?"
@values -min 1
idle -choices {idle}
script -multiple 1 -optional 1 ref-help common_script_help
@form -form {info} -synopsis "after info ?id?"
info -choices {info}
id -optional 1
} "@doc -name Manpage: -url [manpage_tcl after]" ]
lappend PUNKARGS [list -dynamic 1 {
@id -id ::info
@cmd -name "Builtin: info" -help\
@ -290,11 +340,11 @@ tcl::namespace::eval punk::args::tclcore {
characters are used. When decoding, upper and lower characters are accepted."
} "@doc -name Manpage: -url [manpage_tcl binary]" ]
lappend PUNKARGS [list {
@id -id "::tcl::binary::encode::hex"
@default -id (default)::tcl::binary::*::hex
@cmd -name "binary encode hex"
@values -min 1 -max 1
data -type string
@id -id "::tcl::binary::encode::hex"
@default -id (default)::tcl::binary::*::hex
@cmd -name "binary encode hex"
@values -min 1 -max 1
data -type string
} ]
lappend PUNKARGS [list {
@id -id "::tcl::binary::decode::hex"
@ -534,7 +584,7 @@ tcl::namespace::eval punk::args::tclcore {
value -type any -optional 1 -multiple 1
} "@doc -name Manpage: -url [manpage_tcl lappend]"]
punk::args::definition {
punk::args::define {
@id -id ::ledit
@cmd -name "builtin: ledit" -help\
"Replace elements of a list stored in variable
@ -547,7 +597,7 @@ tcl::namespace::eval punk::args::tclcore {
value -type any -optional 1 -multiple 1
} "@doc -name Manpage: -url [manpage_tcl ledit]"
punk::args::definition {
punk::args::define {
@id -id ::lpop
@cmd -name "builtin: lpop" -help\
"Get and remove an element in a list
@ -567,7 +617,7 @@ tcl::namespace::eval punk::args::tclcore {
in sublists, similar to lindex and lset."
} "@doc -name Manpage: -url [manpage_tcl lpop]"
punk::args::definition {
punk::args::define {
@id -id ::lrange
@cmd -name "builtin: lrange" -help\
"return one or more adjacent elements from a list.
@ -587,23 +637,23 @@ tcl::namespace::eval punk::args::tclcore {
} "@doc -name Manpage: -url [manpage_tcl lrange]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::cat
@cmd -name "builtin: tcl::string::cat" -help\
"Concatente the given strings just like placing them directly next to each other and
"Concatenate the given strings just like placing them directly next to each other and
return the resulting compound string. If no strings are present, the result is an
empty string.
This primitive is occasionally handier than juxtaposition of strings when mixed quoting
is wanted, or when the aim is to return the result of a concatentation without resorting
to return -level 0, and is more efficient than building a list of arguments and using
join with an empty join string."
@form -synopsis "string cat ?string...?"
@values -min 0 -max -1
string -type string -optional 1 -multiple 1
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::compare
@cmd -name "builtin: tcl::string::compare" -help\
@ -623,7 +673,7 @@ tcl::namespace::eval punk::args::tclcore {
string2 -type string
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::equal
@cmd -name "builtin: tcl::string::equal" -help\
@ -642,7 +692,7 @@ tcl::namespace::eval punk::args::tclcore {
string2 -type string
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::first
@cmd -name "builtin: tcl::string::first" -help\
"Search haystackString for a sequence of characters that exactly match the characters
@ -658,7 +708,7 @@ tcl::namespace::eval punk::args::tclcore {
"integer or simple expression."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::insert
@cmd -name "builtin: tcl::string::insert" -help\
"Returns a copy of string with insertString inserted at the index'th character.
@ -679,7 +729,7 @@ tcl::namespace::eval punk::args::tclcore {
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::last
@cmd -name "builtin: tcl::string::last" -help\
"Search haystackString for a sequence of characters that exactly match the characters
@ -695,7 +745,7 @@ tcl::namespace::eval punk::args::tclcore {
"integer or simple expression."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::repeat
@cmd -name "builtin: tcl::string::repeat" -help\
"Returns a string consisting of string concatenated with itself count times."
@ -705,7 +755,7 @@ tcl::namespace::eval punk::args::tclcore {
"If count is 0, the empty string will be returned."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::replace
@cmd -name "builtin: tcl::string::replace" -help\
"Removes a range of consecutive characters from string, starting with the character whose
@ -725,7 +775,7 @@ tcl::namespace::eval punk::args::tclcore {
"If newstring is specified, then it is placed in the removed character range."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::totitle
@cmd -name "builtin: tcl::string::totitle" -help\
"Returns a value equal to string except that the first character in string is converted to
@ -740,7 +790,7 @@ tcl::namespace::eval punk::args::tclcore {
"If last is specified, it refers to the char index in the string to stop at (inclusive)."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::wordend
@cmd -name "builtin: tcl::string::wordend" -help\
"Returns the index of the character just after the last one in the word containing
@ -756,7 +806,7 @@ tcl::namespace::eval punk::args::tclcore {
e.g M+N"
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::wordstart
@cmd -name "builtin: tcl::string::wordstart" -help\
"Returns the index of the first character in the word containing
@ -773,7 +823,7 @@ tcl::namespace::eval punk::args::tclcore {
e.g M+N"
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition [punk::lib::tstr -return string {
punk::args::define [punk::lib::tstr -return string {
@id -id ::tcl::string::is
@cmd -name "builtin: tcl::string::is" -help\
"Returns 1 if string is a valid member of the specified character class, otherwise returns 0.
@ -932,7 +982,7 @@ tcl::namespace::eval punk::args::tclcore {
string -type string -optional 0
}] "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::zlib
@cmd -name "builtin: ::zlib" -help\
"zlib - compression and decompression operations
@ -960,7 +1010,7 @@ tcl::namespace::eval punk::args::tclcore {
}
} "@doc -name Manpage: -url [manpage_tcl zlib]"
punk::args::definition {
punk::args::define {
@id -id "::zlib adler32"
@cmd -name "builtin: ::zlib adler32" -help\
"Compute a checksum of binary string ${$I}string${$NI} using the Adler32

8
src/modules/punk/blockletter-999999.0a1.0.tm

@ -119,7 +119,7 @@ tcl::namespace::eval punk::blockletter {
set logo_letter_colours [list Web-red Web-green Web-royalblue Web-purple Web-orange]
set logo_letter_colours [list Red Green Blue Purple Yellow]
punk::args::definition [tstr -return string {
punk::args::define [tstr -return string {
@id -id ::punk::blockletter::logo
-frametype -default {${$default_frametype}}
-outlinecolour -default "web-white"
@ -218,7 +218,7 @@ tcl::namespace::eval punk::blockletter {
append out [textblock::join_basic -- $left $centre $right]
}
punk::args::definition [tstr -return string {
punk::args::define [tstr -return string {
@id -id ::punk::blockletter::text
-bgcolour -default "Web-red"
-bordercolour -default "web-white"
@ -280,7 +280,9 @@ tcl::namespace::eval punk::blockletter::lib {
#}
punk::args::definition [tstr -return string {
#use tstr when resolving params as a one-off at definition time
#versus slower -dynamic 1 if defaults/choices etc need to reflect the current state of the system.
punk::args::define [tstr -return string {
@id -id ::punk::blockletter::block
-height -default 2
-width -default 4

4
src/modules/punk/char-999999.0a1.0.tm

@ -1246,6 +1246,10 @@ tcl::namespace::eval punk::char {
return [charset_dict "Box Drawing"]
}
proc char_hex {char} {
return [format %08x [scan $char %c]]
}
proc char_info_hex {hex args} {
set hex [tcl::string::map [list _ ""] $hex]
if {[tcl::string::is xdigit -strict $hex]} {

2
src/modules/punk/console-999999.0a1.0.tm

@ -1186,7 +1186,7 @@ namespace eval punk::console {
#todo - change -inoutchannels to -terminalobject with prebuilt default
punk::args::definition {
punk::args::define {
@id -id ::punk::console::cell_size
-inoutchannels -default {stdin stdout} -type list
@values -min 0 -max 1

2
src/modules/punk/fileline-999999.0a1.0.tm

@ -1251,7 +1251,7 @@ namespace eval punk::fileline {
#[para] Core API functions for punk::fileline
#[list_begin definitions]
punk::args::definition {
punk::args::define {
@id -id ::punk::fileline::get_textinfo
@cmd -name punk::fileline::get_textinfo -help\
"return: textinfo object instance"

2
src/modules/punk/mix/commandset/loadedlib-999999.0a1.0.tm

@ -26,7 +26,7 @@ package require punk::lib
namespace eval punk::mix::commandset::loadedlib {
namespace export *
#search automatically wrapped in * * - can contain inner * ? globs
punk::args::definition {
punk::args::define {
@id -id ::punk::mix::commandset::loadedlib::search
@cmd -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}

2
src/modules/punk/mix/commandset/module-999999.0a1.0.tm

@ -141,7 +141,7 @@ namespace eval punk::mix::commandset::module {
set moduletypes [punk::mix::cli::lib::module_types]
punk::args::definition [subst {
punk::args::define [subst {
@id -id ::punk::mix::commandset::module::new
@cmd -name "punk::mix::commandset::module::new" -help\
"Create a new module file in the appropriate folder within src/modules.

4
src/modules/punk/nav/fs-999999.0a1.0.tm

@ -636,7 +636,7 @@ tcl::namespace::eval punk::nav::fs {
# c:/repo/jn/punk/../../blah
#dirfiles assumes we don't have glob chars in the filenames or paths - dirfiles_dict can be called directly with explicit -tailglob in the rare case that assumption doesn't hold
# dirfiles will test last segment (tail) of supplied searchspecs for fileness vs folderness (when no globchars present in tail) so that it can pass the appropriate flags downstream
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles
-stripbase -default 1 -type boolean
-formatsizes -default 1 -type boolean -help "Format file size numbers for clarity"
@ -992,7 +992,7 @@ tcl::namespace::eval punk::nav::fs {
return [dict merge $listing $updated]
}
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles_dict_as_lines
-stripbase -default 0 -type boolean
-formatsizes -default 1 -type boolean

122
src/modules/punk/ns-999999.0a1.0.tm

@ -1893,7 +1893,31 @@ tcl::namespace::eval punk::ns {
}
} |data@@ok/result> {lmap v $data {punk::ns::nstail $v}} |> lsort |> {join $data \n} <ns/0|
proc ensemble_subcommands {origin} {
punk::args::define {
@id -id ::punk::ns::ensemble_subcommands
@cmd -name punk::ns::ensemble_subcommands -help\
"Returns a dictionary keyed on subcommand with each value pointing
to the implementation command.
This is not guaranteed to be complete - e.g for ensembles which use
the namespace ensemble 'unknown' mechanism to implement subcommands.
The subcommand information is gathered from entries in the '-map' as
well as those exported from the namespace in '-namespace' if the
'-subcommands' list has been configured for the ensemble.
"
-return -default dict -choices {show dict} -choicelabels {
show "display the result in 'showdict' format"
}
@values -min 1 -max 1
origin -help\
"Name of ensemble command for which subcommand info is gathered."
}
proc ensemble_subcommands {args} {
set argd [punk::args::get_by_id ::punk::ns::ensemble_subcommands $args]
set opts [dict get $argd opts]
set origin [dict get $argd values origin]
set ensembleinfo [namespace ensemble configure $origin]
set prefixes [dict get $ensembleinfo -prefixes]
set map [dict get $ensembleinfo -map]
@ -1936,12 +1960,16 @@ tcl::namespace::eval punk::ns {
}
}
}
return $subcommand_dict
if {[dict get $opts -return] eq "dict"} {
return $subcommand_dict
} else {
return [punk::lib::showdict $subcommand_dict]
}
}
#todo - -cache or -refresh to configure whether we introspect ensembles/objects each time?
# - as this is interactive generally introspection should be ok at the top level
# but if we need to go down multiple levels of subcommands generating/testing prefixes - could be an issue ??
punk::args::definition {
punk::args::define -dynamic 0 {
@id -id ::punk::ns::arginfo
@cmd -name punk::ns::arginfo -help\
"Show usage info for a command.
@ -1965,6 +1993,10 @@ tcl::namespace::eval punk::ns {
exit the interp etc)
"
-return -type string -default table -choices {string table tableobject}
} {${[punk::args::get_spec ::punk::args::arg_error -scheme]}} {
-- -type none -help\
"End of options marker
Use this if the command to view begins with a -"
@ -1977,6 +2009,13 @@ tcl::namespace::eval punk::ns {
}
proc arginfo {args} {
lassign [dict values [punk::args::get_by_id ::punk::ns::arginfo $args]] leaders opts values received
#review - setting this afterwards is an architecture smell - we should be able to override the default in the dynamic part
#todo - enable retrieving by id just the record_opts part - so we can treat as a dict directly, as well as easily apply it as a different flag name.
if {![dict exists $received -scheme]} {
dict set opts -scheme info
}
set querycommand [dict get $values commandpath]
set queryargs [dict get $values subcommand]
punk::args::update_definitions ;#ensure any packages that register PUNKARGS have been loaded
@ -2035,9 +2074,11 @@ tcl::namespace::eval punk::ns {
} else {
#namespace as relative to current doesn't seem to exist
#Tcl would also attempt to resolve as global
set numvals [expr {[llength $queryargs]+1}]
#puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
#set numvals [expr {[llength $queryargs]+1}]
##puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $querycommand {*}$queryargs]]
#set origin $querycommand
#set resolved $querycommand
@ -2068,9 +2109,10 @@ tcl::namespace::eval punk::ns {
#(possible curried arguments)
#review - curried arguments could be for ensembles!
set targetword $word1
set numvals [expr {[llength $queryargs]+1}]
#set numvals [expr {[llength $queryargs]+1}]
#puts "ALIAS THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
}
@ -2115,11 +2157,11 @@ tcl::namespace::eval punk::ns {
set nextqueryargs [list] ;#build a list of prefix-resolved queryargs
set queryargs_untested $queryargs
foreach q $queryargs {
if {[llength [dict get $def leader_names]]} {
set subitems [dict get $def leader_names]
if {[llength [dict get $def LEADER_NAMES]]} {
set subitems [dict get $def LEADER_NAMES]
if {[llength $subitems]} {
set next [lindex $subitems 0]
set arginfo [dict get $def arg_info $next]
set arginfo [dict get $def ARG_INFO $next]
set allchoices [list]
set choices [punk::args::system::Dict_getdef $arginfo -choices {}]
@ -2140,8 +2182,11 @@ tcl::namespace::eval punk::ns {
lpop queryargs_untested 0
if {$resolved_q ne $q} {
#we have our first difference - recurse with new query args
set numvals [expr {[llength $queryargs]+1}]
return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
#set numvals [expr {[llength $queryargs]+1}]
#return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
return [ punk::ns::arginfo {*}$opts $querycommand {*}$nextqueryargs {*}$queryargs_untested]
}
#check if subcommands so far have a custom args def
set currentid [list $querycommand {*}$nextqueryargs]
@ -2188,7 +2233,7 @@ tcl::namespace::eval punk::ns {
new {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} new"
@cmd -name "${$origin} new" -help\
"create object with specified command name.
@ -2200,22 +2245,22 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin new"]
}
create {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} create"
@cmd -name "${$origin} create" -help\
"create object with specified command name.
@ -2229,29 +2274,29 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin create"]
}
destroy {
#review - generally no doc
# but we may want notes about a specific destructor
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(audodef)${$origin} destroy"
@cmd -name "destroy" -help\
"delete object, calling destructor if any.
destroy accepts no arguments."
@values -min 0 -max 0
}]
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin destroy"]
}
default {
@ -2301,7 +2346,7 @@ tcl::namespace::eval punk::ns {
#assert - if we pre
set autoid "(autodef)$location $c1"
set arglist [lindex $def 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@cmd -name "${$location} ${$c1}" -help\
"(autogenerated)
@ -2314,13 +2359,13 @@ tcl::namespace::eval punk::ns {
1 {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
}
2 {
append argspec \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
append argdef \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
}
default {
error "punk::ns::arginfo unexpected argument signature '$arglist'\ndef:$def\nimplementaions:$implementations"
@ -2328,7 +2373,7 @@ tcl::namespace::eval punk::ns {
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
} else {
return "unable to resolve $origin method $c1"
@ -2378,14 +2423,14 @@ tcl::namespace::eval punk::ns {
set vline [list method -choices $public_methods -choicelabels $choicelabeldict -choiceprefix 0] ;#methods must be specified in full always? - review
#puts stderr "--->$vline"
set idauto "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$idauto}
@cmd -name "Object: ${$origin}" -help\
"Instance of class: ${$class} (info autogenerated)"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $idauto]
}
privateObject {
@ -2457,7 +2502,8 @@ tcl::namespace::eval punk::ns {
set match [tcl::prefix::match $subcommands [lindex $queryargs 0]]
if {$match in $subcommands} {
set subcmd [dict get $subcommand_dict $match]
return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
#return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
return [arginfo {*}$opts {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
}
}
@ -2491,15 +2537,15 @@ tcl::namespace::eval punk::ns {
set vline [list subcommand -choices $subcommands -choiceprefix $prefixes -choicelabels $choicelabeldict]
set autoid "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$autoid}
@cmd -help\
"(autogenerated)
ensemble: ${$origin}"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
}
@ -2918,7 +2964,7 @@ tcl::namespace::eval punk::ns {
}
interp alias "" use "" punk::ns::pkguse
punk::args::definition {
punk::args::define {
@id -id ::punk::ns::nsimport_noclobber
@cmd -name punk::ns::nsimport_noclobber -help\
"Import exported commands from a namespace into either the current namespace,

2
src/modules/punk/path-999999.0a1.0.tm

@ -644,7 +644,7 @@ namespace eval punk::path {
return $ismatch
}
punk::args::definition {
punk::args::define {
@id -id ::punk::path::treefilenames
-directory -type directory -help\
"folder in which to begin recursive scan for files."

2
src/modules/punk/repl-0.1.tm

@ -1580,7 +1580,7 @@ proc punk::repl::console_debugview {editbuf consolewidth args} {
set spacepatch [textblock::block $debug_width $patch_height " "]
puts -nonewline [punk::ansi::cursor_off]
#use non cursorsave versions - cursor save/restore will interfere with any concurrent ansi rendering that uses save/restore - because save/restore is a single item, not a stack.
set debug_offset [[expr {$consolewidth - $debug_width - $opt_rightmargin}]]
set debug_offset [expr {$consolewidth - $debug_width - $opt_rightmargin}]
set row_clear [expr {$opt_row -2}]
punk::console::move_emitblock_return $row_clear $debug_offset $spacepatch
punk::console::move_emitblock_return $opt_row $debug_offset $info

39
src/modules/punk/repo-999999.0a1.0.tm

@ -65,6 +65,22 @@ namespace eval punk::repo {
variable PUNKARGS
variable PUNKARGS_aliases
variable cached_command_paths
set cached_command_paths [dict create]
#anticipating possible removal of buggy caching from auto_execok
#mentioned in: https://core.tcl-lang.org/tcl/tktview/4dc35e0c0c
#this would leave the application to decide what it wants to cache in that regard.
proc Cached_auto_execok {name} {
return [auto_execok $name]
#variable cached_command_paths
#if {[dict exists $cached_command_paths $name]} {
# return [dict get $cached_command_paths $name]
#}
#set resolved [auto_execok $name]
#dict set cached_command_paths $name $resolved
#return $resolved
}
proc get_fossil_usage {} {
set allcmds [runout -n fossil help -a]
set mainhelp [runout -n fossil help]
@ -197,7 +213,7 @@ namespace eval punk::repo {
#emit warning whether or not multiple fossil repos
puts stdout [dict get $repostate warnings]
}
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog ne ""} {
{*}$fossil_prog {*}$args
} else {
@ -222,7 +238,10 @@ namespace eval punk::repo {
#uppercase FOSSIL to bypass fossil as alias to fossil_proxy
#only necessary on unix?
#Windows filesystem case insensitive so any non-lowercase fossil version goes out to get an ::auto_execs entry anyway
proc establish_FOSSIL {args} {
#review
if {![info exists ::auto_execs(FOSSIL)]} {
set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp
}
@ -499,7 +518,7 @@ namespace eval punk::repo {
#For this reason we will store 'unchanged' records for both git and fossil so that the combined dict should represent all files in the revision
if {$rt eq "fossil"} {
dict set resultdict repotype fossil
set fossil_cmd [auto_execok fossil]
set fossil_cmd [Cached_auto_execok fossil]
if {$fossil_cmd eq ""} {
error "workingdir_state error: fossil executable doesn't seem to be available"
}
@ -598,7 +617,7 @@ namespace eval punk::repo {
break
} elseif {$rt eq "git"} {
dict set resultdict repotype git
set git_cmd [auto_execok git]
set git_cmd [Cached_auto_execok git]
# -uno = suppress ? lines.
# -b = show ranch and tracking info
#our basic parsing/grepping assumes --porcelain=2
@ -988,7 +1007,7 @@ namespace eval punk::repo {
}
proc fossil_get_repository_file {{path {}}} {
if {$path eq {}} { set path [pwd] }
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set fossilinfo [::exec {*}$fossilcmd info]
@ -1073,7 +1092,7 @@ namespace eval punk::repo {
set startdir $opt_parentfolder
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog eq ""} {
puts stderr "Fossil not found. Please install fossil"
return
@ -1319,7 +1338,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1332,7 +1351,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1343,7 +1362,7 @@ namespace eval punk::repo {
proc fossil_revision {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd info]
@ -1357,7 +1376,7 @@ namespace eval punk::repo {
proc fossil_remote {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd remote ls]
@ -1423,7 +1442,7 @@ namespace eval punk::repo {
set original_cwd [pwd]
#attempt2 - let fossil do it for us - hopefully based on current folder
if {$path eq {}} {set path [pwd]}
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {![llength $fossilcmd]} {
set fossil_ok 0
} else {

8
src/modules/punk/safe-999999.0a1.0.tm

@ -458,7 +458,7 @@ tcl::namespace::eval punk::safe {
# If we have exactly 2 arguments the semantic is a "configure get"
lassign $args child arg
set spec_dict [punk::args::definition [punk::args::get_spec punk::safe::interpIC]]
set spec_dict [punk::args::define [punk::args::get_spec punk::safe::interpIC]]
set opt_names [dict get $spec_dict opt_names]
CheckInterp $child
@ -761,7 +761,7 @@ tcl::namespace::eval punk::safe::system {
append OPTS \n {-autoPath -type list -default {} -help\
"::auto_path for the child"}
}
punk::args::definition $OPTS
punk::args::define $OPTS
set optlines [punk::args::get_spec punk::safe::OPTS -*]
set INTERPCREATE {
@ -775,7 +775,7 @@ tcl::namespace::eval punk::safe::system {
}
append INTERPCREATE \n $optlines
append INTERPCREATE \n {@values -max 0}
punk::args::definition $INTERPCREATE
punk::args::define $INTERPCREATE
set INTERPIC {
@ -786,7 +786,7 @@ tcl::namespace::eval punk::safe::system {
}
append INTERPIC \n $optlines
append INTERPIC \n {@values -max 0}
punk::args::definition $INTERPIC
punk::args::define $INTERPIC
####

2
src/modules/punk/sixel-999999.0a1.0.tm

@ -141,7 +141,7 @@ tcl::namespace::eval punk::sixel {
#non-sixel characters ignored (? review)
#we will for now consume all to final ST
#TODO - sixel row/col info is dependent on terminal - pass in -terminalobject or -inoutchannels (for use with punk::console::cell_size)
punk::args::definition {
punk::args::define {
@id -id ::punk::sixel::get_info
@cmd -name punk::sixel::get_info -help\
"return a dict of information about the supplied sixelstring"

376
src/modules/punk/winshell-999999.0a1.0.tm

@ -0,0 +1,376 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'dev make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.3.tm
#
# 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.
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# (C) 2025
#
# @@ Meta Begin
# Application punk::winshell 999999.0a1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin shellspy_module_punk::winshell 0 999999.0a1.0]
#[copyright "2025"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
#[require punk::winshell]
#[keywords module]
#[description]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of punk::winshell
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by punk::winshell
#[list_begin itemized]
package require Tcl 8.6-
#*** !doctools
#[item] [package {Tcl 8.6}]
# #package require frobz
# #*** !doctools
# #[item] [package {frobz}]
#*** !doctools
#[list_end]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section API]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#tcl::namespace::eval punk::winshell::class {
#*** !doctools
#[subsection {Namespace punk::winshell::class}]
#[para] class definitions
#if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} {
#*** !doctools
#[list_begin enumerated]
# oo::class create interface_sample1 {
# #*** !doctools
# #[enum] CLASS [class interface_sample1]
# #[list_begin definitions]
# method test {arg1} {
# #*** !doctools
# #[call class::interface_sample1 [method test] [arg arg1]]
# #[para] test method
# puts "test: $arg1"
# }
# #*** !doctools
# #[list_end] [comment {-- end definitions interface_sample1}]
# }
#*** !doctools
#[list_end] [comment {--- end class enumeration ---}]
#}
#}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::winshell {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
#variable xyz
#*** !doctools
#[subsection {Namespace punk::winshell}]
#[para] Core API functions for punk::winshell
#[list_begin definitions]
#The windows api we need here is createPseudoConsole et al.
variable autoshellid 0
variable shellinfo [dict create]
#test of exec and named pipes.
#we don't get a console
proc cmdexec {{id ""}} {
variable autoshellid
variable shellinfo
package require twapi
set pipebase {\\.\pipe\punkwinshell}
if {$id eq ""} {
incr autoshellid
set shellid $autoshellid
} else {
set shellid $id
}
set pipename_stdin $pipebase$shellid-stdin
set pipename_stdout $pipebase$shellid-stdout
set pipename_stderr $pipebase$shellid-stderr
set h_stdin [twapi::namedpipe_server $pipename_stdin] ;#handle for child process redirection
set p_stdin [twapi::namedpipe_client $pipename_stdin] ;#this end
set h_stdout [twapi::namedpipe_server $pipename_stdout] ;#handle for child process redirection
set p_stdout [twapi::namedpipe_client $pipename_stdout] ;#this end
chan configure $p_stdout -blocking 0
set h_stderr [twapi::namedpipe_server $pipename_stderr] ;#handle for child process redirection
set p_stderr [twapi::namedpipe_client $pipename_stderr] ;#this end
chan configure $p_stderr -blocking 0
set pid [exec cmd.exe /k >@$h_stdout 2>@$h_stderr <@$h_stdin &]
dict set shellinfo $shellid id $shellid
dict set shellinfo $shellid pid $pid
dict set shellinfo $shellid stdin $p_stdin
dict set shellinfo $shellid stdout $p_stdout
dict set shellinfo $shellid stderr $p_stderr
return [dict get $shellinfo $shellid]
}
#test with twapi create_process
proc cmdcreate {{id ""}} {
variable autoshellid
variable shellinfo
package require twapi
set pipebase {\\.\pipe\punkwinshell}
if {$id eq ""} {
incr autoshellid
set shellid $autoshellid
} else {
set shellid $id
}
#Method 1) - using windows named pipes
set pipename_stdin $pipebase$shellid-stdin
set pipename_stdout $pipebase$shellid-stdout
set pipename_stderr $pipebase$shellid-stderr
#set h_stdin [twapi::namedpipe_server $pipename_stdin] ;#handle for child process redirection - child to read
#set p_stdin [twapi::namedpipe_client $pipename_stdin] ;#this end for writing
#set h_stdout [twapi::namedpipe_server $pipename_stdout] ;#handle for child process redirection - child to write
#set p_stdout [twapi::namedpipe_client $pipename_stdout] ;#this end for reading
#set h_stderr [twapi::namedpipe_server $pipename_stderr] ;#handle for child process redirection - child to write
#set p_stderr [twapi::namedpipe_client $pipename_stderr] ;#this end for reading
#test
set p_stdout [twapi::namedpipe_server $pipename_stdout] ;#handle for child process redirection - child to write
set p_stdin ""
set p_stderr ""
chan configure $p_stdout -blocking 0
#Method 2) - using tcl's 'chan pipe' which creates OS level channels
#chan pipe returns rd wr channels in that order
#lassign [chan pipe] h_stdin p_stdin
#lassign [chan pipe] p_stdout h_stdout
#lassign [chan pipe] p_stderr h_stderr
#chan configure $p_stdout -blocking 0
#chan configure $p_stderr -blocking 0
#set cmd {C:\Users\sleek\scoop\apps\windows-terminal\current\WindowsTerminal.exe} ;#doesn't work?
#set cmd "[auto_execok cmd.exe] /k"
#set cmd "[auto_execok powershell] -nop"
#set cmd "[auto_execok tclsh]"
set cmd "[auto_execok tclsh90]"
set flagdict [dict create\
-cmdline "$cmd"\
-newconsole 1\
-inherithandles 0\
-background blue\
-title "punk::winshell $shellid"
]
#dict set flagdict -stdchannels [list $h_stdin $h_stdout $h_stderr]
set program ""
lassign [twapi::create_process $program {*}$flagdict] pid tid
puts stdout "launched with pid:$pid tid:$tid"
#set pid [exec cmd.exe /k >@$h_stdout 2>@$h_stderr <@$h_stdin &]
dict set shellinfo $shellid id $shellid
dict set shellinfo $shellid pid $pid
dict set shellinfo $shellid type "create_process"
dict set shellinfo $shellid stdin $p_stdin
dict set shellinfo $shellid stdout $p_stdout
dict set shellinfo $shellid stderr $p_stderr
return [dict get $shellinfo $shellid]
}
proc cmdexit {shellid} {
variable shellinfo
set info [dict get $shellinfo $shellid]
switch -- [dict get $info type] {
"create_process" {
set exitresult [twapi::end_process [dict get $info pid]]
}
"exec" {
puts stderr "todo.."
puts stderr "manually kill exec process [dict get $info pid]"
set exitresult 0
}
}
return [dict create exitresult $exitresult]
}
proc cmdkill {shellid} {
variable shellinfo
set info [dict get $shellinfo $shellid]
set pid [dict get $info pid]
set killcmd [list taskkill /PID $pid]
if {[catch {
exec {*}$killcmd
} errMsg]} {
puts stderr "$killcmd returned an error:"
puts stderr $errMsg
#if {!$forcekill} {
# puts stderr "(try 'kill -9 $pid' ??)"
#}
#review - *no running instance* works with windows taskkill - "*No such process*" works with kill -9 on FreeBSD and linux - other platforms?
if {![string match "*no running instance*" $errMsg] && ![string match "*No such process*" $errMsg]} {
lappend failed_kits [list kit $targetkit reason "could not kill running process for $targetkit (using '$killcmd')"]
continue
} else {
puts stderr "
}
} else {
puts stderr "$killcmd ran without error"
incr count_killed
}
}
proc cmdinfo {{id ""}} {
variable autoshellid
variable shellinfo
if {$id eq ""} {
#last created
set shellid $autoshellid
} else {
set shellid $id
}
set info [dict get $shellinfo $shellid]
set pid [dict get $info pid]
set statusresult [tcl::process status $pid]
dict set info status $statusresult
set cmdline [twapi::get_process_commandline $pid]
dict set info cmdline $cmdline
return [showdict $info]
}
#quick n dirty - status of last (or identified) winshell
proc cmdstat {{id ""}} {
variable autoshellid
variable shellinfo
if {$id eq ""} {
#last created
set shellid $autoshellid
} else {
set shellid $id
}
set pid [dict get $shellinfo $shellid pid]
set statusresult [tcl::process status $pid]
return [dict create id $shellid status $statusresult]
}
#proc sample1 {p1 n args} {
# #*** !doctools
# #[call [fun sample1] [arg p1] [arg n] [opt {option value...}]]
# #[para]Description of sample1
# #[para] Arguments:
# # [list_begin arguments]
# # [arg_def tring p1] A description of string argument p1.
# # [arg_def integer n] A description of integer argument n.
# # [list_end]
# return "ok"
#}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::winshell ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::winshell::lib {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
tcl::namespace::path [tcl::namespace::parent]
#*** !doctools
#[subsection {Namespace punk::winshell::lib}]
#[para] Secondary functions that are part of the API
#[list_begin definitions]
#proc utility1 {p1 args} {
# #*** !doctools
# #[call lib::[fun utility1] [arg p1] [opt {?option value...?}]]
# #[para]Description of utility1
# return 1
#}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::winshell::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
#tcl::namespace::eval punk::winshell::system {
#*** !doctools
#[subsection {Namespace punk::winshell::system}]
#[para] Internal functions that are not part of the API
#}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::winshell [tcl::namespace::eval punk::winshell {
variable pkg punk::winshell
variable version
set version 999999.0a1.0
}]
return
#*** !doctools
#[manpage_end]

3
src/modules/punk/winshell-buildversion.txt

@ -0,0 +1,3 @@
0.1.0
#First line must be a semantic version number
#all other lines are ignored.

93
src/modules/textblock-999999.0a1.0.tm

@ -4102,7 +4102,7 @@ tcl::namespace::eval textblock {
return $t
}
punk::args::definition {
punk::args::define {
@id -id ::textblock::periodic
@cmd -name textblock::periodic -help "A rudimentary periodic table
This is primarily a test of textblock::class::table"
@ -4299,6 +4299,9 @@ tcl::namespace::eval textblock {
set base ""
set out ""
if {$newprefix eq ""} {
if {![punk::ansi::ta::detect $block]} {
return $block
}
foreach ln [split $block \n] {
set parts [punk::ansi::ta::split_codes $ln]
if {[lindex $parts 0] eq ""} {
@ -4325,6 +4328,12 @@ tcl::namespace::eval textblock {
return [string range $out 0 end-1]
} else {
set base $newprefix
if {![punk::ansi::ta::detect $block]} {
foreach ln [split $block \n] {
append out $base $ln \n
}
return $out
}
foreach ln [split $block \n] {
set parts [punk::ansi::ta::split_codes $ln]
set code_idx 1
@ -4351,7 +4360,7 @@ tcl::namespace::eval textblock {
}
set FRAMETYPES [textblock::frametypes]
punk::args::definition [punk::lib::tstr -return string {
punk::args::define [punk::lib::tstr -return string {
@id -id ::textblock::list_as_table
@cmd -name "textblock::list_as_table" -help\
"Display a list in a bordered table
@ -4594,10 +4603,47 @@ tcl::namespace::eval textblock {
return [::join $mtrx \n]
}
}
proc testblock {size {colour ""}} {
if {$size <1 || $size > 15} {
error "textblock::testblock only sizes between 1 and 15 inclusive supported"
}
punk::args::define {
@id -id ::textblock::testblock
@cmd -name textblock::testblock -help\
"Create a block of characters size
columns wide and size rows tall.
(which on a terminal will show as a
vertically oriented rectangle due to
cells being taller than their width)
The characters used are
123456789ABCDEF
"
-size -type integer\
-default 15\
-optional 1\
-range {1 15}
-direction -default horizontal\
-choices {horizontal vertical}\
-help\
"When rainbow is in the colour list,
this also affects the direction of
colour changes"
@values -min 0 -max 2
colour -type list -default {} -optional 1 -help\
"List of Ansi colour names
e.g. testblock 10 {white Red}
produces a block of character 10x10
with white text on red bacground
The additional pseudo-color 'rainbow'
is available.
"
}
proc testblock {args} {
set argd [punk::args::get_by_id ::textblock::testblock $args]
set colour [dict get $argd values colour]
set size [dict get $argd opts -size]
set rainbow_list [list]
lappend rainbow_list {30 47} ;#black White
lappend rainbow_list {31 46} ;#red Cyan
@ -4616,17 +4662,18 @@ tcl::namespace::eval textblock {
lappend rainbow_list cyan
lappend rainbow_list {white Red}
set rainbow_direction "horizontal"
set vpos [lsearch $colour vertical]
if {$vpos >= 0} {
set rainbow_direction vertical
set colour [lremove $colour $vpos]
}
set hpos [lsearch $colour horizontal]
if {$hpos >=0} {
#horizontal is the default and superfluous but allowed for symmetry
set colour [lremove $colour $hpos]
}
#set rainbow_direction "horizontal"
#set vpos [lsearch $colour vertical]
#if {$vpos >= 0} {
# set rainbow_direction vertical
# set colour [lremove $colour $vpos]
#}
#set hpos [lsearch $colour horizontal]
#if {$hpos >=0} {
# #horizontal is the default and superfluous but allowed for symmetry
# set colour [lremove $colour $hpos]
#}
set direction [dict get $argd opts -direction]
@ -4637,7 +4684,7 @@ tcl::namespace::eval textblock {
} else {
set RST [a]
}
if {"rainbow" in $colour && $rainbow_direction eq "vertical"} {
if {"rainbow" in $colour && $direction eq "vertical"} {
#column first - colour change each column
set c [::join $charsubset \n]
@ -5431,7 +5478,7 @@ tcl::namespace::eval textblock {
}
punk::args::definition {
punk::args::define {
@id -id ::textblock::join_basic
@cmd -name textblock::join_basic -help\
"Join blocks of text line by line but don't add padding on each line to enforce uniform width.
@ -7452,7 +7499,7 @@ tcl::namespace::eval textblock {
variable frame_cache
set frame_cache [tcl::dict::create]
punk::args::definition {
punk::args::define {
@id -id ::textblock::frame_cache
@cmd -name textblock::frame_cache -help\
"Display or clear the frame cache."
@ -7536,7 +7583,7 @@ tcl::namespace::eval textblock {
# ${[textblock::frame_samples]}
#todo punk::args alias for centre center etc?
punk::args::definition -dynamic 1 {
punk::args::define -dynamic 1 {
@id -id ::textblock::frame
@cmd -name "textblock::frame"\
-help "Frame a block of text with a border."
@ -8367,7 +8414,7 @@ tcl::namespace::eval textblock {
foreach tline $tlines {
if {[tcl::string::first $FSUB $tline] >= 0} {
set content_line [lindex $clines $contentindex]
if {[tcl::string::first $R $content_line] == 0} {
if {[tcl::string::first $R [string range $content_line 0 10]] == 0} {
set content_line [tcl::string::range $content_line $rlen end]
}
#make sure to replay opt_ansibase to the right of the replacement
@ -8390,7 +8437,7 @@ tcl::namespace::eval textblock {
return $fs
}
}
punk::args::definition {
punk::args::define {
@id -id ::textblock::gcross
-max_cross_size -default 0 -type integer -help "Largest size cross to use to make up the block
Only cross sizes that divide the size of the overall block will be used.

2
src/modules/textblock-buildversion.txt

@ -1,3 +1,3 @@
0.1.2
0.1.3
#First line must be a semantic version number
#all other lines are ignored.

10
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/commandstack-0.3.tm

@ -211,6 +211,7 @@ namespace eval commandstack {
set new_code [string trim $procbody]
if {$current_code eq $new_code} {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command with same procbody - Aborting rename."
puts stderr [show_stack $command]
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command - but appears to be with new code - proceeding."
puts stdout "----------"
@ -223,6 +224,7 @@ namespace eval commandstack {
}
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command, but is not immediate predecessor - proceeding anyway... (untested)"
puts stderr
set next_target ::commandstack::renamed_commands::${mungedcommand}-${munged_next_implementor}-$mungedrenamer-$tokenid
set do_rename 1
}
@ -374,13 +376,13 @@ namespace eval commandstack {
proc show_stack {{commandname_glob *}} {
variable all_stacks
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
if {[package provide punk::lib] ne ""} {
return [punk::lib::pdict -channel none all_stacks $commandname_glob/@*/@*.@*]
} else {
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
set result ""
set matchedkeys [dict keys $all_stacks $commandname_glob]
#don't try to calculate widest on empty list

309
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.6.5.tm

@ -449,7 +449,7 @@ tcl::namespace::eval overtype {
4 {
set inputchunks [list]
foreach ln [split $overblock \n] {
lappend inputchunks [string cat $ln \n]
lappend inputchunks $ln\n
}
if {[llength $inputchunks]} {
lset inputchunks end [tcl::string::range [lindex $inputchunks end] 0 end-1]
@ -499,9 +499,9 @@ tcl::namespace::eval overtype {
#set overtext [tcl::string::cat [lindex $replay_codes_overlay $overidx] $overtext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set overtext $replay_codes_overlay$overtext
if {[tcl::dict::exists $replay_codes_underlay $row]} {
set undertext [tcl::string::cat [tcl::dict::get $replay_codes_underlay $row] $undertext]
set undertext [tcl::dict::get $replay_codes_underlay $row]$undertext
}
#review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary -
#but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l
@ -1365,8 +1365,8 @@ tcl::namespace::eval overtype {
set udiff [expr {$renderwidth - $ulen}]
set undertext "$undertext[string repeat { } $udiff]"
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
#review - right-to-left langs should elide on left! - extra option required
@ -1518,8 +1518,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1545,7 +1545,7 @@ tcl::namespace::eval overtype {
}
}
if {$show_ellipsis} {
set ellipsis [tcl::string::cat $replay_codes $opt_ellipsistext]
set ellipsis $replay_codes$opt_ellipsistext
#todo - overflow on left if allign = right??
set rendered [overtype::right $rendered $ellipsis]
}
@ -1701,8 +1701,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1769,6 +1769,9 @@ tcl::namespace::eval overtype {
return [join $outputlines \n]
}
variable optimise_ptruns 10 ;# can be set to zero to disable the ptruns branches
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# renderline written from a left-right line orientation perspective as a first-shot at getting something useful.
# ultimately right-to-left, top-to-bottom and bottom-to-top are probably needed.
@ -1802,6 +1805,7 @@ tcl::namespace::eval overtype {
#[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation.
#puts stderr "renderline '$args'"
variable optimise_ptruns
if {[llength $args] < 2} {
error {usage: ?-info 0|1? ?-startcolumn <int>? ?-cursor_column <int>? ?-cursor_row <int>|""? ?-transparent [0|1|<regexp>]? ?-expand_right [1|0]? undertext overtext}
@ -1973,58 +1977,107 @@ tcl::namespace::eval overtype {
foreach {pt code} $undermap {
#pt = plain text
#append pt_underchars $pt
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
if {$pt ne ""} {
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set hex [format %x [scan $p1 %c]] ;#punk::char::char_hex
set re [tcl::string::cat {^[} \\U$hex {]+$}]
set is_ptrun [regexp $re $pt]
}
if {$is_ptrun} {
#switch -- $p1 {
# " " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
# a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
# z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
# set width 1
# }
# default {
# if {$p1 eq "\u0000"} {
# #use null as empty cell representation - review
# #use of this will probably collide with some application at some point
# #consider an option to set the empty cell character
# set width 1
# } else {
# set width [grapheme_width_cached $p1] ;# when zero???
# }
# }
#}
set width [grapheme_width_cached $p1] ;# when zero???
set ptlen [string length $pt]
if {$width <= 1} {
#review - 0 and 1?
incr i_u $ptlen
lappend understacks {*}[lrepeat $ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $ptlen $u_gx_stack]
lappend undercols {*}[lrepeat $ptlen $p1]
} else {
incr i_u $ptlen ;#2nd col empty str - so same as above
set 2ptlen [expr {$ptlen * 2}]
lappend understacks {*}[lrepeat $2ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $2ptlen $u_gx_stack]
set l [concat {*}[lrepeat $ptlen [list $p1 ""]]
lappend undercols {*}$l
unset l
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme]
set grapheme $gvis
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
#zero width still acts as 1 below??? review what should happen
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme] ;#can only use with graphemes that have a single replacement char..
set grapheme $gvis
set width 1
}
}
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
#underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2168,23 +2221,31 @@ tcl::namespace::eval overtype {
# -- --- --- --- --- --- --- ---
####
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left of the right number of columns.
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left containing the right number of columns.
#this will be processed as transparent - and handle doublewidth underlay characters appropriately
set startpad_overlay [string repeat " " [expr {$opt_colstart -1}]]
append startpad_overlay $overdata ;#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpad_overlay ne ""} {
if {[punk::ansi::ta::detect $startpad_overlay]} {
set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
set startpadding [string repeat " " [expr {$opt_colstart -1}]]
#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpadding ne "" || $overdata ne ""} {
if {[punk::ansi::ta::detect $overdata]} {
set overmap [punk::ansi::ta::split_codes_single $startpadding$overdata]
} else {
#single plaintext part
set overmap [list $startpad_overlay]
set overmap [list $startpadding$overdata]
}
} else {
set overmap [list]
}
#set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
####
#todo - detect plain ascii no-ansi input line (aside from leading ansi reset)
#will that allow some optimisations?
#todo - detect repeated transparent char in overlay
#regexp {^(.)\1+$} ;#backtracking regexp - relatively slow.
# - try set c [string index $data 0]; regexp [string map [list %c% $c] {^[%c%]+$}] $data
#we should be able to optimize to pass through the underlay??
#???
set colcursor $opt_colstart
#TODO - make a little virtual column object
@ -2206,41 +2267,78 @@ tcl::namespace::eval overtype {
#experiment
set overlay_grapheme_control_stacks [list]
foreach {pt code} $overmap {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
if {$pt ne ""} {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+$}]
set is_ptrun [regexp $re $pt]
#leading only? we would have to check for graphemes at the trailing boundary?
#set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+}]
#set is_ptrun [regexp -indices $re $pt runrange]
#if {$is_ptrun && 1} {
#}
}
if {$is_ptrun} {
#review - in theory a run over a certain length won't be part of some grapheme combo (graphemes can be long e.g 44?, but not as runs(?))
#could be edge cases for runs at line end? (should be ok as we include trailing \n in our data)
set len [string length $pt]
set g_element [list g $p1]
#lappend overstacks {*}[lrepeat $len $o_codestack]
#lappend overstacks_gx {*}[lrepeat $len $o_gxstack]
#incr i_o $len
#lappend overlay_grapheme_control_list {*}[lrepeat $len [list g $p1]]
#lappend overlay_grapheme_control_stacks {*}[lrepeat $len $o_codestack]
set pi 0
incr i_o $len
while {$pi < $len} {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
lappend overlay_grapheme_control_list $g_element
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr pi
}
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2324,6 +2422,7 @@ tcl::namespace::eval overtype {
set o_codestack [list $temp_cursor_saved]
lappend overlay_grapheme_control_list [list other $code]
} else {
#review
if {[punk::ansi::codetype::is_gx_open $code]} {
set o_gxstack [list "gx0_on"]
lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets
@ -2837,7 +2936,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 3 end]]
}
7CSI - 7OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
set codenorm $leadernorm[tcl::string::range $code 2 end]
}
7DCS {
#ESC P
@ -2849,7 +2949,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
}
7ESC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
set codenorm $leadernorm[tcl::string::range $code 1 end]
}
8CSI - 8OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
@ -2886,7 +2987,12 @@ tcl::namespace::eval overtype {
A {
#Row move - up
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
set num $param
#todo
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row -$num
@ -2904,9 +3010,12 @@ tcl::namespace::eval overtype {
B {
#CUD - Cursor Down
#Row move - down
set num $param
lassign [split $param {;}] num modifierkey
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move down
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row $num
@ -2924,7 +3033,10 @@ tcl::namespace::eval overtype {
#todo - consider right-to-left cursor mode (e.g Hebrew).. some day.
#cursor forward
#right-arrow/move forward
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
#todo - retrict to moving 1 position past datalen? restrict to column width?
@ -3028,7 +3140,10 @@ tcl::namespace::eval overtype {
#puts stdout "<-back"
#cursor back
#left-arrow/move-back when ltr mode
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
set version 2
@ -4518,7 +4633,7 @@ tcl::namespace::eval overtype::priv {
if {$existing eq "\0"} {
lset o $i $c
} else {
lset o $i [string cat $existing $c]
lset o $i $existing$c
}
}
#is actually addgrapheme?

242
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk-0.1.tm

@ -12,6 +12,242 @@ namespace eval punk {
#lazyload twapi ?
catch {package require vfs} ;#attempt load now so we can use faster 'package provide' to test existence later
variable can_exec_windowsapp
set can_exec_windowsapp unknown ;#don't spend a potential X00ms testing until needed
variable windowsappdir
set windowsappdir ""
variable cmdexedir
set cmdexedir ""
proc rehash {{refresh 0}} {
global auto_execs
if {!$refresh} {
unset -nocomplain auto_execs
} else {
set names [array names auto_execs]
unset -nocomplain auto_execs
foreach nm $names {
auto_execok_windows $nm
}
}
return
}
proc ::punk::auto_execok_original name [info body ::auto_execok]
variable better_autoexec
#set better_autoexec 0 ;#use this var via better_autoexec only
#proc ::punk::auto_execok_windows name {
# ::punk::auto_execok_original $name
#}
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
set has_commandstack [expr {![catch {package require commandstack}]}]
if {![interp issafe] && $has_commandstack && $::tcl_platform(platform) eq "windows"} {
#still a caching version of auto_execok - but with proper(fixed) search order
#set b [info body ::auto_execok]
#proc ::auto_execok_original name $b
proc better_autoexec {{onoff ""}} {
variable better_autoexec
if {$onoff eq ""} {
return $better_autoexec
}
if {![string is boolean -strict $onoff]} {
error "better_autoexec argument 'onoff' must be a boolean, received: $onoff"
}
if {$onoff && ($onoff != $better_autoexec)} {
puts "Turning on better_autoexec - search PATH first then extension"
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
punk::rehash
} elseif {!$onoff && ($onoff != $better_autoexec)} {
puts "Turning off better_autoexec - search extension then PATH"
set better_autoexec 0
proc ::punk::auto_execok_windows name {
::punk::auto_execok_original $name
}
punk::rehash
} else {
puts "no change"
}
}
#better_autoexec $better_autoexec ;#init to default
proc auto_execok_better name {
global auto_execs env tcl_platform
if {[info exists auto_execs($name)]} {
return $auto_execs($name)
}
#puts stdout "[a+ red]...[a]"
set auto_execs($name) ""
set shellBuiltins [list assoc cls copy date del dir echo erase exit ftype \
md mkdir mklink move rd ren rename rmdir start time type ver vol]
if {[info exists env(PATHEXT)]} {
# Add an initial ; to have the {} extension check first.
set execExtensions [split ";$env(PATHEXT)" ";"]
} else {
set execExtensions [list {} .com .exe .bat .cmd]
}
if {[string tolower $name] in $shellBuiltins} {
# When this is command.com for some reason on Win2K, Tcl won't
# exec it unless the case is right, which this corrects. COMSPEC
# may not point to a real file, so do the check.
set cmd $env(COMSPEC)
if {[file exists $cmd]} {
set cmd [file attributes $cmd -shortname]
}
return [set auto_execs($name) [list $cmd /c $name]]
}
if {[llength [file split $name]] != 1} {
foreach ext $execExtensions {
set file ${name}${ext}
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
return ""
}
#change1
#set path "[file dirname [info nameofexecutable]];.;"
set path "[file dirname [info nameofexecutable]];"
if {[info exists env(SystemRoot)]} {
set windir $env(SystemRoot)
} elseif {[info exists env(WINDIR)]} {
set windir $env(WINDIR)
}
if {[info exists windir]} {
append path "$windir/system32;$windir/system;$windir;"
}
foreach var {PATH Path path} {
if {[info exists env($var)]} {
append path ";$env($var)"
}
}
#change2
set lookfor [lmap ext $execExtensions {string cat ${name} ${ext}}]
foreach dir [split $path {;}] {
#set dir [file normalize $dir]
# Skip already checked directories
if {[info exists checked($dir)] || ($dir eq "")} {
continue
}
set checked($dir) {}
foreach match [glob -nocomplain -dir $dir -tail {*}$lookfor] {
set file [file join $dir $match]
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
}
#foreach ext $execExtensions {
#unset -nocomplain checked
#foreach dir [split $path {;}] {
# # Skip already checked directories
# if {[info exists checked($dir)] || ($dir eq "")} {
# continue
# }
# set checked($dir) {}
# set file [file join $dir ${name}${ext}]
# if {[file exists $file] && ![file isdirectory $file]} {
# return [set auto_execs($name) [list $file]]
# }
#}
#}
return ""
}
#review - what if punk package reloaded - but ::auto_execs has updated path for winget.exe?
#what if we create another interp and use the same ::auto_execs? The appdir won't be detected.
#TODO - see if there is a proper windows way to determine where the 'reparse point' apps are installed
#winget is installed on all modern windows and is an example of the problem this addresses
#we target apps with same location
#the main purpose of this override is to support windows app executables (installed as 'reparse points')
#for Tcl versions prior to the 2025-01 fix by APN https://core.tcl-lang.org/tcl/tktview/4f0b5767ac
#versions prior to this will use cmd.exe to resolve the links
set stackrecord [commandstack::rename_command -renamer ::punk auto_execok name {
#set windowsappdir "%appdir%"
upvar ::punk::can_exec_windowsapp can_exec_windowsapp
upvar ::punk::windowsappdir windowsappdir
upvar ::punk::cmdexedir cmdexedir
if {$windowsappdir eq ""} {
#we are targeting the winget location under the presumption this is where microsoft store apps are stored as 'reparse points'
#Tcl (2025) can't exec when given a path to these 0KB files
#This path is probably something like C:/Users/username/AppData/Local/Microsoft/WindowsApps
if {!([info exists ::env(LOCALAPPDATA)] &&
[file exists [set testapp [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]]])} {
#should be unlikely to get here - unless LOCALAPPDATA missing
set windowsappdir [file dirname [lindex [::punk::auto_execok_windows winget.exe] 0]]
puts stderr "(resolved winget by search)"
} else {
set windowsappdir [file dirname $testapp]
}
}
#set default_auto [$COMMANDSTACKNEXT $name]
set default_auto [::punk::auto_execok_windows $name]
#if {$name ni {cmd cmd.exe}} {
# unset -nocomplain ::auto_execs
#}
if {$default_auto eq ""} {
return
}
set namedir [file dirname [lindex $default_auto 0]]
if {$namedir eq $windowsappdir} {
if {$can_exec_windowsapp eq "unknown"} {
if {[catch {exec [file join $windowsappdir winget.exe] --version}]} {
set can_exec_windowsapp 0
} else {
set can_exec_windowsapp 1
}
}
if {$can_exec_windowsapp} {
return [file join $windowsappdir $name]
}
if {$cmdexedir eq ""} {
#cmd.exe very unlikely to move
set cmdexedir [file dirname [lindex [::punk::auto_execok_windows cmd.exe] 0]]
#auto_reset never seems to exist as a command - because auto_reset deletes all commands in the ::auto_index
#anyway.. it has other side effects (affects auto_load)
}
return "[file join $cmdexedir cmd.exe] /c $name"
}
return $default_auto
}]
}
}
@ -5321,8 +5557,8 @@ namespace eval punk {
}
return -options $opts $msg
} else {
dict incr opts -level
return -options $opts $msg
dict incr opts -level
return -options $opts $msg
}
}
}
@ -7152,7 +7388,7 @@ namespace eval punk {
dict filter $result value {?*}
}
punk::args::definition {
punk::args::define {
@id -id ::punk::inspect
@cmd -name punk::inspect -help\
"Function to display values - used pimarily in a punk pipeline.

1
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/aliascore-0.1.0.tm

@ -115,6 +115,7 @@ tcl::namespace::eval punk::aliascore {
pdict ::punk::lib::pdict\
plist {::punk::lib::pdict -roottype list}\
showlist {::punk::lib::showdict -roottype list}\
rehash ::punk::rehash\
showdict ::punk::lib::showdict\
ansistrip ::punk::ansi::ansistrip\
stripansi ::punk::ansi::ansistrip\

2
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm

@ -5568,6 +5568,7 @@ tcl::namespace::eval punk::ansi::class {
}
#does not affect object state
#REVIEW - icu or equiv required
method DoCount {plaintext} {
#- combiners/diacritics just map them away here - but for consistency we need to combine unicode grapheme clusters too.
#todo - joiners 200d? zwnbsp
@ -5672,6 +5673,7 @@ tcl::namespace::eval punk::ansi::class {
method renderbuf {} {
#get the underlying renderobj - if any
#return $o_renderout ;#also class_ansistring
if {$o_renderer eq ""} {error "renderbuf error: no active renderer"}
return [$o_renderer renderbuf]
}
method render {{maxgraphemes ""}} {

1930
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args-0.1.0.tm

File diff suppressed because it is too large Load Diff

4
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/char-0.1.0.tm

@ -1246,6 +1246,10 @@ tcl::namespace::eval punk::char {
return [charset_dict "Box Drawing"]
}
proc char_hex {char} {
return [format %08x [scan $char %c]]
}
proc char_info_hex {hex args} {
set hex [tcl::string::map [list _ ""] $hex]
if {[tcl::string::is xdigit -strict $hex]} {

2
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/console-0.1.1.tm

@ -1186,7 +1186,7 @@ namespace eval punk::console {
#todo - change -inoutchannels to -terminalobject with prebuilt default
punk::args::definition {
punk::args::define {
@id -id ::punk::console::cell_size
-inoutchannels -default {stdin stdout} -type list
@values -min 0 -max 1

2
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/fileline-0.1.0.tm

@ -1251,7 +1251,7 @@ namespace eval punk::fileline {
#[para] Core API functions for punk::fileline
#[list_begin definitions]
punk::args::definition {
punk::args::define {
@id -id ::punk::fileline::get_textinfo
@cmd -name punk::fileline::get_textinfo -help\
"return: textinfo object instance"

2
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm

@ -26,7 +26,7 @@ package require punk::lib
namespace eval punk::mix::commandset::loadedlib {
namespace export *
#search automatically wrapped in * * - can contain inner * ? globs
punk::args::definition {
punk::args::define {
@id -id ::punk::mix::commandset::loadedlib::search
@cmd -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}

2
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm

@ -141,7 +141,7 @@ namespace eval punk::mix::commandset::module {
set moduletypes [punk::mix::cli::lib::module_types]
punk::args::definition [subst {
punk::args::define [subst {
@id -id ::punk::mix::commandset::module::new
@cmd -name "punk::mix::commandset::module::new" -help\
"Create a new module file in the appropriate folder within src/modules.

4
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -636,7 +636,7 @@ tcl::namespace::eval punk::nav::fs {
# c:/repo/jn/punk/../../blah
#dirfiles assumes we don't have glob chars in the filenames or paths - dirfiles_dict can be called directly with explicit -tailglob in the rare case that assumption doesn't hold
# dirfiles will test last segment (tail) of supplied searchspecs for fileness vs folderness (when no globchars present in tail) so that it can pass the appropriate flags downstream
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles
-stripbase -default 1 -type boolean
-formatsizes -default 1 -type boolean -help "Format file size numbers for clarity"
@ -992,7 +992,7 @@ tcl::namespace::eval punk::nav::fs {
return [dict merge $listing $updated]
}
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles_dict_as_lines
-stripbase -default 0 -type boolean
-formatsizes -default 1 -type boolean

122
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ns-0.1.0.tm

@ -1893,7 +1893,31 @@ tcl::namespace::eval punk::ns {
}
} |data@@ok/result> {lmap v $data {punk::ns::nstail $v}} |> lsort |> {join $data \n} <ns/0|
proc ensemble_subcommands {origin} {
punk::args::define {
@id -id ::punk::ns::ensemble_subcommands
@cmd -name punk::ns::ensemble_subcommands -help\
"Returns a dictionary keyed on subcommand with each value pointing
to the implementation command.
This is not guaranteed to be complete - e.g for ensembles which use
the namespace ensemble 'unknown' mechanism to implement subcommands.
The subcommand information is gathered from entries in the '-map' as
well as those exported from the namespace in '-namespace' if the
'-subcommands' list has been configured for the ensemble.
"
-return -default dict -choices {show dict} -choicelabels {
show "display the result in 'showdict' format"
}
@values -min 1 -max 1
origin -help\
"Name of ensemble command for which subcommand info is gathered."
}
proc ensemble_subcommands {args} {
set argd [punk::args::get_by_id ::punk::ns::ensemble_subcommands $args]
set opts [dict get $argd opts]
set origin [dict get $argd values origin]
set ensembleinfo [namespace ensemble configure $origin]
set prefixes [dict get $ensembleinfo -prefixes]
set map [dict get $ensembleinfo -map]
@ -1936,12 +1960,16 @@ tcl::namespace::eval punk::ns {
}
}
}
return $subcommand_dict
if {[dict get $opts -return] eq "dict"} {
return $subcommand_dict
} else {
return [punk::lib::showdict $subcommand_dict]
}
}
#todo - -cache or -refresh to configure whether we introspect ensembles/objects each time?
# - as this is interactive generally introspection should be ok at the top level
# but if we need to go down multiple levels of subcommands generating/testing prefixes - could be an issue ??
punk::args::definition {
punk::args::define -dynamic 0 {
@id -id ::punk::ns::arginfo
@cmd -name punk::ns::arginfo -help\
"Show usage info for a command.
@ -1965,6 +1993,10 @@ tcl::namespace::eval punk::ns {
exit the interp etc)
"
-return -type string -default table -choices {string table tableobject}
} {${[punk::args::get_spec ::punk::args::arg_error -scheme]}} {
-- -type none -help\
"End of options marker
Use this if the command to view begins with a -"
@ -1977,6 +2009,13 @@ tcl::namespace::eval punk::ns {
}
proc arginfo {args} {
lassign [dict values [punk::args::get_by_id ::punk::ns::arginfo $args]] leaders opts values received
#review - setting this afterwards is an architecture smell - we should be able to override the default in the dynamic part
#todo - enable retrieving by id just the record_opts part - so we can treat as a dict directly, as well as easily apply it as a different flag name.
if {![dict exists $received -scheme]} {
dict set opts -scheme info
}
set querycommand [dict get $values commandpath]
set queryargs [dict get $values subcommand]
punk::args::update_definitions ;#ensure any packages that register PUNKARGS have been loaded
@ -2035,9 +2074,11 @@ tcl::namespace::eval punk::ns {
} else {
#namespace as relative to current doesn't seem to exist
#Tcl would also attempt to resolve as global
set numvals [expr {[llength $queryargs]+1}]
#puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
#set numvals [expr {[llength $queryargs]+1}]
##puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $querycommand {*}$queryargs]]
#set origin $querycommand
#set resolved $querycommand
@ -2068,9 +2109,10 @@ tcl::namespace::eval punk::ns {
#(possible curried arguments)
#review - curried arguments could be for ensembles!
set targetword $word1
set numvals [expr {[llength $queryargs]+1}]
#set numvals [expr {[llength $queryargs]+1}]
#puts "ALIAS THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
}
@ -2115,11 +2157,11 @@ tcl::namespace::eval punk::ns {
set nextqueryargs [list] ;#build a list of prefix-resolved queryargs
set queryargs_untested $queryargs
foreach q $queryargs {
if {[llength [dict get $def leader_names]]} {
set subitems [dict get $def leader_names]
if {[llength [dict get $def LEADER_NAMES]]} {
set subitems [dict get $def LEADER_NAMES]
if {[llength $subitems]} {
set next [lindex $subitems 0]
set arginfo [dict get $def arg_info $next]
set arginfo [dict get $def ARG_INFO $next]
set allchoices [list]
set choices [punk::args::system::Dict_getdef $arginfo -choices {}]
@ -2140,8 +2182,11 @@ tcl::namespace::eval punk::ns {
lpop queryargs_untested 0
if {$resolved_q ne $q} {
#we have our first difference - recurse with new query args
set numvals [expr {[llength $queryargs]+1}]
return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
#set numvals [expr {[llength $queryargs]+1}]
#return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
return [ punk::ns::arginfo {*}$opts $querycommand {*}$nextqueryargs {*}$queryargs_untested]
}
#check if subcommands so far have a custom args def
set currentid [list $querycommand {*}$nextqueryargs]
@ -2188,7 +2233,7 @@ tcl::namespace::eval punk::ns {
new {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} new"
@cmd -name "${$origin} new" -help\
"create object with specified command name.
@ -2200,22 +2245,22 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin new"]
}
create {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} create"
@cmd -name "${$origin} create" -help\
"create object with specified command name.
@ -2229,29 +2274,29 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin create"]
}
destroy {
#review - generally no doc
# but we may want notes about a specific destructor
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(audodef)${$origin} destroy"
@cmd -name "destroy" -help\
"delete object, calling destructor if any.
destroy accepts no arguments."
@values -min 0 -max 0
}]
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin destroy"]
}
default {
@ -2301,7 +2346,7 @@ tcl::namespace::eval punk::ns {
#assert - if we pre
set autoid "(autodef)$location $c1"
set arglist [lindex $def 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@cmd -name "${$location} ${$c1}" -help\
"(autogenerated)
@ -2314,13 +2359,13 @@ tcl::namespace::eval punk::ns {
1 {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
}
2 {
append argspec \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
append argdef \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
}
default {
error "punk::ns::arginfo unexpected argument signature '$arglist'\ndef:$def\nimplementaions:$implementations"
@ -2328,7 +2373,7 @@ tcl::namespace::eval punk::ns {
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
} else {
return "unable to resolve $origin method $c1"
@ -2378,14 +2423,14 @@ tcl::namespace::eval punk::ns {
set vline [list method -choices $public_methods -choicelabels $choicelabeldict -choiceprefix 0] ;#methods must be specified in full always? - review
#puts stderr "--->$vline"
set idauto "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$idauto}
@cmd -name "Object: ${$origin}" -help\
"Instance of class: ${$class} (info autogenerated)"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $idauto]
}
privateObject {
@ -2457,7 +2502,8 @@ tcl::namespace::eval punk::ns {
set match [tcl::prefix::match $subcommands [lindex $queryargs 0]]
if {$match in $subcommands} {
set subcmd [dict get $subcommand_dict $match]
return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
#return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
return [arginfo {*}$opts {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
}
}
@ -2491,15 +2537,15 @@ tcl::namespace::eval punk::ns {
set vline [list subcommand -choices $subcommands -choiceprefix $prefixes -choicelabels $choicelabeldict]
set autoid "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$autoid}
@cmd -help\
"(autogenerated)
ensemble: ${$origin}"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
}
@ -2918,7 +2964,7 @@ tcl::namespace::eval punk::ns {
}
interp alias "" use "" punk::ns::pkguse
punk::args::definition {
punk::args::define {
@id -id ::punk::ns::nsimport_noclobber
@cmd -name punk::ns::nsimport_noclobber -help\
"Import exported commands from a namespace into either the current namespace,

2
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm

@ -644,7 +644,7 @@ namespace eval punk::path {
return $ismatch
}
punk::args::definition {
punk::args::define {
@id -id ::punk::path::treefilenames
-directory -type directory -help\
"folder in which to begin recursive scan for files."

39
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm

@ -65,6 +65,22 @@ namespace eval punk::repo {
variable PUNKARGS
variable PUNKARGS_aliases
variable cached_command_paths
set cached_command_paths [dict create]
#anticipating possible removal of buggy caching from auto_execok
#mentioned in: https://core.tcl-lang.org/tcl/tktview/4dc35e0c0c
#this would leave the application to decide what it wants to cache in that regard.
proc Cached_auto_execok {name} {
return [auto_execok $name]
#variable cached_command_paths
#if {[dict exists $cached_command_paths $name]} {
# return [dict get $cached_command_paths $name]
#}
#set resolved [auto_execok $name]
#dict set cached_command_paths $name $resolved
#return $resolved
}
proc get_fossil_usage {} {
set allcmds [runout -n fossil help -a]
set mainhelp [runout -n fossil help]
@ -197,7 +213,7 @@ namespace eval punk::repo {
#emit warning whether or not multiple fossil repos
puts stdout [dict get $repostate warnings]
}
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog ne ""} {
{*}$fossil_prog {*}$args
} else {
@ -222,7 +238,10 @@ namespace eval punk::repo {
#uppercase FOSSIL to bypass fossil as alias to fossil_proxy
#only necessary on unix?
#Windows filesystem case insensitive so any non-lowercase fossil version goes out to get an ::auto_execs entry anyway
proc establish_FOSSIL {args} {
#review
if {![info exists ::auto_execs(FOSSIL)]} {
set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp
}
@ -499,7 +518,7 @@ namespace eval punk::repo {
#For this reason we will store 'unchanged' records for both git and fossil so that the combined dict should represent all files in the revision
if {$rt eq "fossil"} {
dict set resultdict repotype fossil
set fossil_cmd [auto_execok fossil]
set fossil_cmd [Cached_auto_execok fossil]
if {$fossil_cmd eq ""} {
error "workingdir_state error: fossil executable doesn't seem to be available"
}
@ -598,7 +617,7 @@ namespace eval punk::repo {
break
} elseif {$rt eq "git"} {
dict set resultdict repotype git
set git_cmd [auto_execok git]
set git_cmd [Cached_auto_execok git]
# -uno = suppress ? lines.
# -b = show ranch and tracking info
#our basic parsing/grepping assumes --porcelain=2
@ -988,7 +1007,7 @@ namespace eval punk::repo {
}
proc fossil_get_repository_file {{path {}}} {
if {$path eq {}} { set path [pwd] }
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set fossilinfo [::exec {*}$fossilcmd info]
@ -1073,7 +1092,7 @@ namespace eval punk::repo {
set startdir $opt_parentfolder
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog eq ""} {
puts stderr "Fossil not found. Please install fossil"
return
@ -1319,7 +1338,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1332,7 +1351,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1343,7 +1362,7 @@ namespace eval punk::repo {
proc fossil_revision {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd info]
@ -1357,7 +1376,7 @@ namespace eval punk::repo {
proc fossil_remote {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd remote ls]
@ -1423,7 +1442,7 @@ namespace eval punk::repo {
set original_cwd [pwd]
#attempt2 - let fossil do it for us - hopefully based on current folder
if {$path eq {}} {set path [pwd]}
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {![llength $fossilcmd]} {
set fossil_ok 0
} else {

2
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.2.tm

@ -8367,7 +8367,7 @@ tcl::namespace::eval textblock {
foreach tline $tlines {
if {[tcl::string::first $FSUB $tline] >= 0} {
set content_line [lindex $clines $contentindex]
if {[tcl::string::first $R $content_line] == 0} {
if {[tcl::string::first $R [string range $content_line 0 10]] == 0} {
set content_line [tcl::string::range $content_line $rlen end]
}
#make sure to replay opt_ansibase to the right of the replacement

8567
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.3.tm

File diff suppressed because it is too large Load Diff

10
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/commandstack-0.3.tm

@ -211,6 +211,7 @@ namespace eval commandstack {
set new_code [string trim $procbody]
if {$current_code eq $new_code} {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command with same procbody - Aborting rename."
puts stderr [show_stack $command]
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command - but appears to be with new code - proceeding."
puts stdout "----------"
@ -223,6 +224,7 @@ namespace eval commandstack {
}
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command, but is not immediate predecessor - proceeding anyway... (untested)"
puts stderr
set next_target ::commandstack::renamed_commands::${mungedcommand}-${munged_next_implementor}-$mungedrenamer-$tokenid
set do_rename 1
}
@ -374,13 +376,13 @@ namespace eval commandstack {
proc show_stack {{commandname_glob *}} {
variable all_stacks
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
if {[package provide punk::lib] ne ""} {
return [punk::lib::pdict -channel none all_stacks $commandname_glob/@*/@*.@*]
} else {
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
set result ""
set matchedkeys [dict keys $all_stacks $commandname_glob]
#don't try to calculate widest on empty list

309
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.6.5.tm

@ -449,7 +449,7 @@ tcl::namespace::eval overtype {
4 {
set inputchunks [list]
foreach ln [split $overblock \n] {
lappend inputchunks [string cat $ln \n]
lappend inputchunks $ln\n
}
if {[llength $inputchunks]} {
lset inputchunks end [tcl::string::range [lindex $inputchunks end] 0 end-1]
@ -499,9 +499,9 @@ tcl::namespace::eval overtype {
#set overtext [tcl::string::cat [lindex $replay_codes_overlay $overidx] $overtext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set overtext $replay_codes_overlay$overtext
if {[tcl::dict::exists $replay_codes_underlay $row]} {
set undertext [tcl::string::cat [tcl::dict::get $replay_codes_underlay $row] $undertext]
set undertext [tcl::dict::get $replay_codes_underlay $row]$undertext
}
#review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary -
#but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l
@ -1365,8 +1365,8 @@ tcl::namespace::eval overtype {
set udiff [expr {$renderwidth - $ulen}]
set undertext "$undertext[string repeat { } $udiff]"
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
#review - right-to-left langs should elide on left! - extra option required
@ -1518,8 +1518,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1545,7 +1545,7 @@ tcl::namespace::eval overtype {
}
}
if {$show_ellipsis} {
set ellipsis [tcl::string::cat $replay_codes $opt_ellipsistext]
set ellipsis $replay_codes$opt_ellipsistext
#todo - overflow on left if allign = right??
set rendered [overtype::right $rendered $ellipsis]
}
@ -1701,8 +1701,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1769,6 +1769,9 @@ tcl::namespace::eval overtype {
return [join $outputlines \n]
}
variable optimise_ptruns 10 ;# can be set to zero to disable the ptruns branches
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# renderline written from a left-right line orientation perspective as a first-shot at getting something useful.
# ultimately right-to-left, top-to-bottom and bottom-to-top are probably needed.
@ -1802,6 +1805,7 @@ tcl::namespace::eval overtype {
#[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation.
#puts stderr "renderline '$args'"
variable optimise_ptruns
if {[llength $args] < 2} {
error {usage: ?-info 0|1? ?-startcolumn <int>? ?-cursor_column <int>? ?-cursor_row <int>|""? ?-transparent [0|1|<regexp>]? ?-expand_right [1|0]? undertext overtext}
@ -1973,58 +1977,107 @@ tcl::namespace::eval overtype {
foreach {pt code} $undermap {
#pt = plain text
#append pt_underchars $pt
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
if {$pt ne ""} {
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set hex [format %x [scan $p1 %c]] ;#punk::char::char_hex
set re [tcl::string::cat {^[} \\U$hex {]+$}]
set is_ptrun [regexp $re $pt]
}
if {$is_ptrun} {
#switch -- $p1 {
# " " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
# a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
# z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
# set width 1
# }
# default {
# if {$p1 eq "\u0000"} {
# #use null as empty cell representation - review
# #use of this will probably collide with some application at some point
# #consider an option to set the empty cell character
# set width 1
# } else {
# set width [grapheme_width_cached $p1] ;# when zero???
# }
# }
#}
set width [grapheme_width_cached $p1] ;# when zero???
set ptlen [string length $pt]
if {$width <= 1} {
#review - 0 and 1?
incr i_u $ptlen
lappend understacks {*}[lrepeat $ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $ptlen $u_gx_stack]
lappend undercols {*}[lrepeat $ptlen $p1]
} else {
incr i_u $ptlen ;#2nd col empty str - so same as above
set 2ptlen [expr {$ptlen * 2}]
lappend understacks {*}[lrepeat $2ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $2ptlen $u_gx_stack]
set l [concat {*}[lrepeat $ptlen [list $p1 ""]]
lappend undercols {*}$l
unset l
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme]
set grapheme $gvis
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
#zero width still acts as 1 below??? review what should happen
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme] ;#can only use with graphemes that have a single replacement char..
set grapheme $gvis
set width 1
}
}
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
#underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2168,23 +2221,31 @@ tcl::namespace::eval overtype {
# -- --- --- --- --- --- --- ---
####
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left of the right number of columns.
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left containing the right number of columns.
#this will be processed as transparent - and handle doublewidth underlay characters appropriately
set startpad_overlay [string repeat " " [expr {$opt_colstart -1}]]
append startpad_overlay $overdata ;#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpad_overlay ne ""} {
if {[punk::ansi::ta::detect $startpad_overlay]} {
set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
set startpadding [string repeat " " [expr {$opt_colstart -1}]]
#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpadding ne "" || $overdata ne ""} {
if {[punk::ansi::ta::detect $overdata]} {
set overmap [punk::ansi::ta::split_codes_single $startpadding$overdata]
} else {
#single plaintext part
set overmap [list $startpad_overlay]
set overmap [list $startpadding$overdata]
}
} else {
set overmap [list]
}
#set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
####
#todo - detect plain ascii no-ansi input line (aside from leading ansi reset)
#will that allow some optimisations?
#todo - detect repeated transparent char in overlay
#regexp {^(.)\1+$} ;#backtracking regexp - relatively slow.
# - try set c [string index $data 0]; regexp [string map [list %c% $c] {^[%c%]+$}] $data
#we should be able to optimize to pass through the underlay??
#???
set colcursor $opt_colstart
#TODO - make a little virtual column object
@ -2206,41 +2267,78 @@ tcl::namespace::eval overtype {
#experiment
set overlay_grapheme_control_stacks [list]
foreach {pt code} $overmap {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
if {$pt ne ""} {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+$}]
set is_ptrun [regexp $re $pt]
#leading only? we would have to check for graphemes at the trailing boundary?
#set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+}]
#set is_ptrun [regexp -indices $re $pt runrange]
#if {$is_ptrun && 1} {
#}
}
if {$is_ptrun} {
#review - in theory a run over a certain length won't be part of some grapheme combo (graphemes can be long e.g 44?, but not as runs(?))
#could be edge cases for runs at line end? (should be ok as we include trailing \n in our data)
set len [string length $pt]
set g_element [list g $p1]
#lappend overstacks {*}[lrepeat $len $o_codestack]
#lappend overstacks_gx {*}[lrepeat $len $o_gxstack]
#incr i_o $len
#lappend overlay_grapheme_control_list {*}[lrepeat $len [list g $p1]]
#lappend overlay_grapheme_control_stacks {*}[lrepeat $len $o_codestack]
set pi 0
incr i_o $len
while {$pi < $len} {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
lappend overlay_grapheme_control_list $g_element
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr pi
}
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2324,6 +2422,7 @@ tcl::namespace::eval overtype {
set o_codestack [list $temp_cursor_saved]
lappend overlay_grapheme_control_list [list other $code]
} else {
#review
if {[punk::ansi::codetype::is_gx_open $code]} {
set o_gxstack [list "gx0_on"]
lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets
@ -2837,7 +2936,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 3 end]]
}
7CSI - 7OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
set codenorm $leadernorm[tcl::string::range $code 2 end]
}
7DCS {
#ESC P
@ -2849,7 +2949,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
}
7ESC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
set codenorm $leadernorm[tcl::string::range $code 1 end]
}
8CSI - 8OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
@ -2886,7 +2987,12 @@ tcl::namespace::eval overtype {
A {
#Row move - up
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
set num $param
#todo
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row -$num
@ -2904,9 +3010,12 @@ tcl::namespace::eval overtype {
B {
#CUD - Cursor Down
#Row move - down
set num $param
lassign [split $param {;}] num modifierkey
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move down
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row $num
@ -2924,7 +3033,10 @@ tcl::namespace::eval overtype {
#todo - consider right-to-left cursor mode (e.g Hebrew).. some day.
#cursor forward
#right-arrow/move forward
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
#todo - retrict to moving 1 position past datalen? restrict to column width?
@ -3028,7 +3140,10 @@ tcl::namespace::eval overtype {
#puts stdout "<-back"
#cursor back
#left-arrow/move-back when ltr mode
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
set version 2
@ -4518,7 +4633,7 @@ tcl::namespace::eval overtype::priv {
if {$existing eq "\0"} {
lset o $i $c
} else {
lset o $i [string cat $existing $c]
lset o $i $existing$c
}
}
#is actually addgrapheme?

242
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk-0.1.tm

@ -12,6 +12,242 @@ namespace eval punk {
#lazyload twapi ?
catch {package require vfs} ;#attempt load now so we can use faster 'package provide' to test existence later
variable can_exec_windowsapp
set can_exec_windowsapp unknown ;#don't spend a potential X00ms testing until needed
variable windowsappdir
set windowsappdir ""
variable cmdexedir
set cmdexedir ""
proc rehash {{refresh 0}} {
global auto_execs
if {!$refresh} {
unset -nocomplain auto_execs
} else {
set names [array names auto_execs]
unset -nocomplain auto_execs
foreach nm $names {
auto_execok_windows $nm
}
}
return
}
proc ::punk::auto_execok_original name [info body ::auto_execok]
variable better_autoexec
#set better_autoexec 0 ;#use this var via better_autoexec only
#proc ::punk::auto_execok_windows name {
# ::punk::auto_execok_original $name
#}
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
set has_commandstack [expr {![catch {package require commandstack}]}]
if {![interp issafe] && $has_commandstack && $::tcl_platform(platform) eq "windows"} {
#still a caching version of auto_execok - but with proper(fixed) search order
#set b [info body ::auto_execok]
#proc ::auto_execok_original name $b
proc better_autoexec {{onoff ""}} {
variable better_autoexec
if {$onoff eq ""} {
return $better_autoexec
}
if {![string is boolean -strict $onoff]} {
error "better_autoexec argument 'onoff' must be a boolean, received: $onoff"
}
if {$onoff && ($onoff != $better_autoexec)} {
puts "Turning on better_autoexec - search PATH first then extension"
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
punk::rehash
} elseif {!$onoff && ($onoff != $better_autoexec)} {
puts "Turning off better_autoexec - search extension then PATH"
set better_autoexec 0
proc ::punk::auto_execok_windows name {
::punk::auto_execok_original $name
}
punk::rehash
} else {
puts "no change"
}
}
#better_autoexec $better_autoexec ;#init to default
proc auto_execok_better name {
global auto_execs env tcl_platform
if {[info exists auto_execs($name)]} {
return $auto_execs($name)
}
#puts stdout "[a+ red]...[a]"
set auto_execs($name) ""
set shellBuiltins [list assoc cls copy date del dir echo erase exit ftype \
md mkdir mklink move rd ren rename rmdir start time type ver vol]
if {[info exists env(PATHEXT)]} {
# Add an initial ; to have the {} extension check first.
set execExtensions [split ";$env(PATHEXT)" ";"]
} else {
set execExtensions [list {} .com .exe .bat .cmd]
}
if {[string tolower $name] in $shellBuiltins} {
# When this is command.com for some reason on Win2K, Tcl won't
# exec it unless the case is right, which this corrects. COMSPEC
# may not point to a real file, so do the check.
set cmd $env(COMSPEC)
if {[file exists $cmd]} {
set cmd [file attributes $cmd -shortname]
}
return [set auto_execs($name) [list $cmd /c $name]]
}
if {[llength [file split $name]] != 1} {
foreach ext $execExtensions {
set file ${name}${ext}
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
return ""
}
#change1
#set path "[file dirname [info nameofexecutable]];.;"
set path "[file dirname [info nameofexecutable]];"
if {[info exists env(SystemRoot)]} {
set windir $env(SystemRoot)
} elseif {[info exists env(WINDIR)]} {
set windir $env(WINDIR)
}
if {[info exists windir]} {
append path "$windir/system32;$windir/system;$windir;"
}
foreach var {PATH Path path} {
if {[info exists env($var)]} {
append path ";$env($var)"
}
}
#change2
set lookfor [lmap ext $execExtensions {string cat ${name} ${ext}}]
foreach dir [split $path {;}] {
#set dir [file normalize $dir]
# Skip already checked directories
if {[info exists checked($dir)] || ($dir eq "")} {
continue
}
set checked($dir) {}
foreach match [glob -nocomplain -dir $dir -tail {*}$lookfor] {
set file [file join $dir $match]
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
}
#foreach ext $execExtensions {
#unset -nocomplain checked
#foreach dir [split $path {;}] {
# # Skip already checked directories
# if {[info exists checked($dir)] || ($dir eq "")} {
# continue
# }
# set checked($dir) {}
# set file [file join $dir ${name}${ext}]
# if {[file exists $file] && ![file isdirectory $file]} {
# return [set auto_execs($name) [list $file]]
# }
#}
#}
return ""
}
#review - what if punk package reloaded - but ::auto_execs has updated path for winget.exe?
#what if we create another interp and use the same ::auto_execs? The appdir won't be detected.
#TODO - see if there is a proper windows way to determine where the 'reparse point' apps are installed
#winget is installed on all modern windows and is an example of the problem this addresses
#we target apps with same location
#the main purpose of this override is to support windows app executables (installed as 'reparse points')
#for Tcl versions prior to the 2025-01 fix by APN https://core.tcl-lang.org/tcl/tktview/4f0b5767ac
#versions prior to this will use cmd.exe to resolve the links
set stackrecord [commandstack::rename_command -renamer ::punk auto_execok name {
#set windowsappdir "%appdir%"
upvar ::punk::can_exec_windowsapp can_exec_windowsapp
upvar ::punk::windowsappdir windowsappdir
upvar ::punk::cmdexedir cmdexedir
if {$windowsappdir eq ""} {
#we are targeting the winget location under the presumption this is where microsoft store apps are stored as 'reparse points'
#Tcl (2025) can't exec when given a path to these 0KB files
#This path is probably something like C:/Users/username/AppData/Local/Microsoft/WindowsApps
if {!([info exists ::env(LOCALAPPDATA)] &&
[file exists [set testapp [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]]])} {
#should be unlikely to get here - unless LOCALAPPDATA missing
set windowsappdir [file dirname [lindex [::punk::auto_execok_windows winget.exe] 0]]
puts stderr "(resolved winget by search)"
} else {
set windowsappdir [file dirname $testapp]
}
}
#set default_auto [$COMMANDSTACKNEXT $name]
set default_auto [::punk::auto_execok_windows $name]
#if {$name ni {cmd cmd.exe}} {
# unset -nocomplain ::auto_execs
#}
if {$default_auto eq ""} {
return
}
set namedir [file dirname [lindex $default_auto 0]]
if {$namedir eq $windowsappdir} {
if {$can_exec_windowsapp eq "unknown"} {
if {[catch {exec [file join $windowsappdir winget.exe] --version}]} {
set can_exec_windowsapp 0
} else {
set can_exec_windowsapp 1
}
}
if {$can_exec_windowsapp} {
return [file join $windowsappdir $name]
}
if {$cmdexedir eq ""} {
#cmd.exe very unlikely to move
set cmdexedir [file dirname [lindex [::punk::auto_execok_windows cmd.exe] 0]]
#auto_reset never seems to exist as a command - because auto_reset deletes all commands in the ::auto_index
#anyway.. it has other side effects (affects auto_load)
}
return "[file join $cmdexedir cmd.exe] /c $name"
}
return $default_auto
}]
}
}
@ -5321,8 +5557,8 @@ namespace eval punk {
}
return -options $opts $msg
} else {
dict incr opts -level
return -options $opts $msg
dict incr opts -level
return -options $opts $msg
}
}
}
@ -7152,7 +7388,7 @@ namespace eval punk {
dict filter $result value {?*}
}
punk::args::definition {
punk::args::define {
@id -id ::punk::inspect
@cmd -name punk::inspect -help\
"Function to display values - used pimarily in a punk pipeline.

1
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/aliascore-0.1.0.tm

@ -115,6 +115,7 @@ tcl::namespace::eval punk::aliascore {
pdict ::punk::lib::pdict\
plist {::punk::lib::pdict -roottype list}\
showlist {::punk::lib::showdict -roottype list}\
rehash ::punk::rehash\
showdict ::punk::lib::showdict\
ansistrip ::punk::ansi::ansistrip\
stripansi ::punk::ansi::ansistrip\

2
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm

@ -5568,6 +5568,7 @@ tcl::namespace::eval punk::ansi::class {
}
#does not affect object state
#REVIEW - icu or equiv required
method DoCount {plaintext} {
#- combiners/diacritics just map them away here - but for consistency we need to combine unicode grapheme clusters too.
#todo - joiners 200d? zwnbsp
@ -5672,6 +5673,7 @@ tcl::namespace::eval punk::ansi::class {
method renderbuf {} {
#get the underlying renderobj - if any
#return $o_renderout ;#also class_ansistring
if {$o_renderer eq ""} {error "renderbuf error: no active renderer"}
return [$o_renderer renderbuf]
}
method render {{maxgraphemes ""}} {

1930
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args-0.1.0.tm

File diff suppressed because it is too large Load Diff

4
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/char-0.1.0.tm

@ -1246,6 +1246,10 @@ tcl::namespace::eval punk::char {
return [charset_dict "Box Drawing"]
}
proc char_hex {char} {
return [format %08x [scan $char %c]]
}
proc char_info_hex {hex args} {
set hex [tcl::string::map [list _ ""] $hex]
if {[tcl::string::is xdigit -strict $hex]} {

2
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/console-0.1.1.tm

@ -1186,7 +1186,7 @@ namespace eval punk::console {
#todo - change -inoutchannels to -terminalobject with prebuilt default
punk::args::definition {
punk::args::define {
@id -id ::punk::console::cell_size
-inoutchannels -default {stdin stdout} -type list
@values -min 0 -max 1

2
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/fileline-0.1.0.tm

@ -1251,7 +1251,7 @@ namespace eval punk::fileline {
#[para] Core API functions for punk::fileline
#[list_begin definitions]
punk::args::definition {
punk::args::define {
@id -id ::punk::fileline::get_textinfo
@cmd -name punk::fileline::get_textinfo -help\
"return: textinfo object instance"

2
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/loadedlib-0.1.0.tm

@ -26,7 +26,7 @@ package require punk::lib
namespace eval punk::mix::commandset::loadedlib {
namespace export *
#search automatically wrapped in * * - can contain inner * ? globs
punk::args::definition {
punk::args::define {
@id -id ::punk::mix::commandset::loadedlib::search
@cmd -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}

2
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm

@ -141,7 +141,7 @@ namespace eval punk::mix::commandset::module {
set moduletypes [punk::mix::cli::lib::module_types]
punk::args::definition [subst {
punk::args::define [subst {
@id -id ::punk::mix::commandset::module::new
@cmd -name "punk::mix::commandset::module::new" -help\
"Create a new module file in the appropriate folder within src/modules.

4
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -636,7 +636,7 @@ tcl::namespace::eval punk::nav::fs {
# c:/repo/jn/punk/../../blah
#dirfiles assumes we don't have glob chars in the filenames or paths - dirfiles_dict can be called directly with explicit -tailglob in the rare case that assumption doesn't hold
# dirfiles will test last segment (tail) of supplied searchspecs for fileness vs folderness (when no globchars present in tail) so that it can pass the appropriate flags downstream
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles
-stripbase -default 1 -type boolean
-formatsizes -default 1 -type boolean -help "Format file size numbers for clarity"
@ -992,7 +992,7 @@ tcl::namespace::eval punk::nav::fs {
return [dict merge $listing $updated]
}
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles_dict_as_lines
-stripbase -default 0 -type boolean
-formatsizes -default 1 -type boolean

122
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ns-0.1.0.tm

@ -1893,7 +1893,31 @@ tcl::namespace::eval punk::ns {
}
} |data@@ok/result> {lmap v $data {punk::ns::nstail $v}} |> lsort |> {join $data \n} <ns/0|
proc ensemble_subcommands {origin} {
punk::args::define {
@id -id ::punk::ns::ensemble_subcommands
@cmd -name punk::ns::ensemble_subcommands -help\
"Returns a dictionary keyed on subcommand with each value pointing
to the implementation command.
This is not guaranteed to be complete - e.g for ensembles which use
the namespace ensemble 'unknown' mechanism to implement subcommands.
The subcommand information is gathered from entries in the '-map' as
well as those exported from the namespace in '-namespace' if the
'-subcommands' list has been configured for the ensemble.
"
-return -default dict -choices {show dict} -choicelabels {
show "display the result in 'showdict' format"
}
@values -min 1 -max 1
origin -help\
"Name of ensemble command for which subcommand info is gathered."
}
proc ensemble_subcommands {args} {
set argd [punk::args::get_by_id ::punk::ns::ensemble_subcommands $args]
set opts [dict get $argd opts]
set origin [dict get $argd values origin]
set ensembleinfo [namespace ensemble configure $origin]
set prefixes [dict get $ensembleinfo -prefixes]
set map [dict get $ensembleinfo -map]
@ -1936,12 +1960,16 @@ tcl::namespace::eval punk::ns {
}
}
}
return $subcommand_dict
if {[dict get $opts -return] eq "dict"} {
return $subcommand_dict
} else {
return [punk::lib::showdict $subcommand_dict]
}
}
#todo - -cache or -refresh to configure whether we introspect ensembles/objects each time?
# - as this is interactive generally introspection should be ok at the top level
# but if we need to go down multiple levels of subcommands generating/testing prefixes - could be an issue ??
punk::args::definition {
punk::args::define -dynamic 0 {
@id -id ::punk::ns::arginfo
@cmd -name punk::ns::arginfo -help\
"Show usage info for a command.
@ -1965,6 +1993,10 @@ tcl::namespace::eval punk::ns {
exit the interp etc)
"
-return -type string -default table -choices {string table tableobject}
} {${[punk::args::get_spec ::punk::args::arg_error -scheme]}} {
-- -type none -help\
"End of options marker
Use this if the command to view begins with a -"
@ -1977,6 +2009,13 @@ tcl::namespace::eval punk::ns {
}
proc arginfo {args} {
lassign [dict values [punk::args::get_by_id ::punk::ns::arginfo $args]] leaders opts values received
#review - setting this afterwards is an architecture smell - we should be able to override the default in the dynamic part
#todo - enable retrieving by id just the record_opts part - so we can treat as a dict directly, as well as easily apply it as a different flag name.
if {![dict exists $received -scheme]} {
dict set opts -scheme info
}
set querycommand [dict get $values commandpath]
set queryargs [dict get $values subcommand]
punk::args::update_definitions ;#ensure any packages that register PUNKARGS have been loaded
@ -2035,9 +2074,11 @@ tcl::namespace::eval punk::ns {
} else {
#namespace as relative to current doesn't seem to exist
#Tcl would also attempt to resolve as global
set numvals [expr {[llength $queryargs]+1}]
#puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
#set numvals [expr {[llength $queryargs]+1}]
##puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $querycommand {*}$queryargs]]
#set origin $querycommand
#set resolved $querycommand
@ -2068,9 +2109,10 @@ tcl::namespace::eval punk::ns {
#(possible curried arguments)
#review - curried arguments could be for ensembles!
set targetword $word1
set numvals [expr {[llength $queryargs]+1}]
#set numvals [expr {[llength $queryargs]+1}]
#puts "ALIAS THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
}
@ -2115,11 +2157,11 @@ tcl::namespace::eval punk::ns {
set nextqueryargs [list] ;#build a list of prefix-resolved queryargs
set queryargs_untested $queryargs
foreach q $queryargs {
if {[llength [dict get $def leader_names]]} {
set subitems [dict get $def leader_names]
if {[llength [dict get $def LEADER_NAMES]]} {
set subitems [dict get $def LEADER_NAMES]
if {[llength $subitems]} {
set next [lindex $subitems 0]
set arginfo [dict get $def arg_info $next]
set arginfo [dict get $def ARG_INFO $next]
set allchoices [list]
set choices [punk::args::system::Dict_getdef $arginfo -choices {}]
@ -2140,8 +2182,11 @@ tcl::namespace::eval punk::ns {
lpop queryargs_untested 0
if {$resolved_q ne $q} {
#we have our first difference - recurse with new query args
set numvals [expr {[llength $queryargs]+1}]
return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
#set numvals [expr {[llength $queryargs]+1}]
#return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
return [ punk::ns::arginfo {*}$opts $querycommand {*}$nextqueryargs {*}$queryargs_untested]
}
#check if subcommands so far have a custom args def
set currentid [list $querycommand {*}$nextqueryargs]
@ -2188,7 +2233,7 @@ tcl::namespace::eval punk::ns {
new {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} new"
@cmd -name "${$origin} new" -help\
"create object with specified command name.
@ -2200,22 +2245,22 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin new"]
}
create {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} create"
@cmd -name "${$origin} create" -help\
"create object with specified command name.
@ -2229,29 +2274,29 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin create"]
}
destroy {
#review - generally no doc
# but we may want notes about a specific destructor
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(audodef)${$origin} destroy"
@cmd -name "destroy" -help\
"delete object, calling destructor if any.
destroy accepts no arguments."
@values -min 0 -max 0
}]
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin destroy"]
}
default {
@ -2301,7 +2346,7 @@ tcl::namespace::eval punk::ns {
#assert - if we pre
set autoid "(autodef)$location $c1"
set arglist [lindex $def 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@cmd -name "${$location} ${$c1}" -help\
"(autogenerated)
@ -2314,13 +2359,13 @@ tcl::namespace::eval punk::ns {
1 {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
}
2 {
append argspec \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
append argdef \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
}
default {
error "punk::ns::arginfo unexpected argument signature '$arglist'\ndef:$def\nimplementaions:$implementations"
@ -2328,7 +2373,7 @@ tcl::namespace::eval punk::ns {
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
} else {
return "unable to resolve $origin method $c1"
@ -2378,14 +2423,14 @@ tcl::namespace::eval punk::ns {
set vline [list method -choices $public_methods -choicelabels $choicelabeldict -choiceprefix 0] ;#methods must be specified in full always? - review
#puts stderr "--->$vline"
set idauto "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$idauto}
@cmd -name "Object: ${$origin}" -help\
"Instance of class: ${$class} (info autogenerated)"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $idauto]
}
privateObject {
@ -2457,7 +2502,8 @@ tcl::namespace::eval punk::ns {
set match [tcl::prefix::match $subcommands [lindex $queryargs 0]]
if {$match in $subcommands} {
set subcmd [dict get $subcommand_dict $match]
return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
#return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
return [arginfo {*}$opts {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
}
}
@ -2491,15 +2537,15 @@ tcl::namespace::eval punk::ns {
set vline [list subcommand -choices $subcommands -choiceprefix $prefixes -choicelabels $choicelabeldict]
set autoid "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$autoid}
@cmd -help\
"(autogenerated)
ensemble: ${$origin}"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
}
@ -2918,7 +2964,7 @@ tcl::namespace::eval punk::ns {
}
interp alias "" use "" punk::ns::pkguse
punk::args::definition {
punk::args::define {
@id -id ::punk::ns::nsimport_noclobber
@cmd -name punk::ns::nsimport_noclobber -help\
"Import exported commands from a namespace into either the current namespace,

2
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm

@ -644,7 +644,7 @@ namespace eval punk::path {
return $ismatch
}
punk::args::definition {
punk::args::define {
@id -id ::punk::path::treefilenames
-directory -type directory -help\
"folder in which to begin recursive scan for files."

39
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/repo-0.1.1.tm

@ -65,6 +65,22 @@ namespace eval punk::repo {
variable PUNKARGS
variable PUNKARGS_aliases
variable cached_command_paths
set cached_command_paths [dict create]
#anticipating possible removal of buggy caching from auto_execok
#mentioned in: https://core.tcl-lang.org/tcl/tktview/4dc35e0c0c
#this would leave the application to decide what it wants to cache in that regard.
proc Cached_auto_execok {name} {
return [auto_execok $name]
#variable cached_command_paths
#if {[dict exists $cached_command_paths $name]} {
# return [dict get $cached_command_paths $name]
#}
#set resolved [auto_execok $name]
#dict set cached_command_paths $name $resolved
#return $resolved
}
proc get_fossil_usage {} {
set allcmds [runout -n fossil help -a]
set mainhelp [runout -n fossil help]
@ -197,7 +213,7 @@ namespace eval punk::repo {
#emit warning whether or not multiple fossil repos
puts stdout [dict get $repostate warnings]
}
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog ne ""} {
{*}$fossil_prog {*}$args
} else {
@ -222,7 +238,10 @@ namespace eval punk::repo {
#uppercase FOSSIL to bypass fossil as alias to fossil_proxy
#only necessary on unix?
#Windows filesystem case insensitive so any non-lowercase fossil version goes out to get an ::auto_execs entry anyway
proc establish_FOSSIL {args} {
#review
if {![info exists ::auto_execs(FOSSIL)]} {
set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp
}
@ -499,7 +518,7 @@ namespace eval punk::repo {
#For this reason we will store 'unchanged' records for both git and fossil so that the combined dict should represent all files in the revision
if {$rt eq "fossil"} {
dict set resultdict repotype fossil
set fossil_cmd [auto_execok fossil]
set fossil_cmd [Cached_auto_execok fossil]
if {$fossil_cmd eq ""} {
error "workingdir_state error: fossil executable doesn't seem to be available"
}
@ -598,7 +617,7 @@ namespace eval punk::repo {
break
} elseif {$rt eq "git"} {
dict set resultdict repotype git
set git_cmd [auto_execok git]
set git_cmd [Cached_auto_execok git]
# -uno = suppress ? lines.
# -b = show ranch and tracking info
#our basic parsing/grepping assumes --porcelain=2
@ -988,7 +1007,7 @@ namespace eval punk::repo {
}
proc fossil_get_repository_file {{path {}}} {
if {$path eq {}} { set path [pwd] }
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set fossilinfo [::exec {*}$fossilcmd info]
@ -1073,7 +1092,7 @@ namespace eval punk::repo {
set startdir $opt_parentfolder
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog eq ""} {
puts stderr "Fossil not found. Please install fossil"
return
@ -1319,7 +1338,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1332,7 +1351,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1343,7 +1362,7 @@ namespace eval punk::repo {
proc fossil_revision {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd info]
@ -1357,7 +1376,7 @@ namespace eval punk::repo {
proc fossil_remote {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd remote ls]
@ -1423,7 +1442,7 @@ namespace eval punk::repo {
set original_cwd [pwd]
#attempt2 - let fossil do it for us - hopefully based on current folder
if {$path eq {}} {set path [pwd]}
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {![llength $fossilcmd]} {
set fossil_ok 0
} else {

2
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.2.tm

@ -8367,7 +8367,7 @@ tcl::namespace::eval textblock {
foreach tline $tlines {
if {[tcl::string::first $FSUB $tline] >= 0} {
set content_line [lindex $clines $contentindex]
if {[tcl::string::first $R $content_line] == 0} {
if {[tcl::string::first $R [string range $content_line 0 10]] == 0} {
set content_line [tcl::string::range $content_line $rlen end]
}
#make sure to replay opt_ansibase to the right of the replacement

8567
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.3.tm

File diff suppressed because it is too large Load Diff

10
src/vendormodules/commandstack-0.3.tm

@ -211,6 +211,7 @@ namespace eval commandstack {
set new_code [string trim $procbody]
if {$current_code eq $new_code} {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command with same procbody - Aborting rename."
puts stderr [show_stack $command]
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command - but appears to be with new code - proceeding."
puts stdout "----------"
@ -223,6 +224,7 @@ namespace eval commandstack {
}
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command, but is not immediate predecessor - proceeding anyway... (untested)"
puts stderr
set next_target ::commandstack::renamed_commands::${mungedcommand}-${munged_next_implementor}-$mungedrenamer-$tokenid
set do_rename 1
}
@ -374,13 +376,13 @@ namespace eval commandstack {
proc show_stack {{commandname_glob *}} {
variable all_stacks
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
if {[package provide punk::lib] ne ""} {
return [punk::lib::pdict -channel none all_stacks $commandname_glob/@*/@*.@*]
} else {
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
set result ""
set matchedkeys [dict keys $all_stacks $commandname_glob]
#don't try to calculate widest on empty list

309
src/vendormodules/overtype-1.6.5.tm

@ -449,7 +449,7 @@ tcl::namespace::eval overtype {
4 {
set inputchunks [list]
foreach ln [split $overblock \n] {
lappend inputchunks [string cat $ln \n]
lappend inputchunks $ln\n
}
if {[llength $inputchunks]} {
lset inputchunks end [tcl::string::range [lindex $inputchunks end] 0 end-1]
@ -499,9 +499,9 @@ tcl::namespace::eval overtype {
#set overtext [tcl::string::cat [lindex $replay_codes_overlay $overidx] $overtext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set overtext $replay_codes_overlay$overtext
if {[tcl::dict::exists $replay_codes_underlay $row]} {
set undertext [tcl::string::cat [tcl::dict::get $replay_codes_underlay $row] $undertext]
set undertext [tcl::dict::get $replay_codes_underlay $row]$undertext
}
#review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary -
#but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l
@ -1365,8 +1365,8 @@ tcl::namespace::eval overtype {
set udiff [expr {$renderwidth - $ulen}]
set undertext "$undertext[string repeat { } $udiff]"
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
#review - right-to-left langs should elide on left! - extra option required
@ -1518,8 +1518,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1545,7 +1545,7 @@ tcl::namespace::eval overtype {
}
}
if {$show_ellipsis} {
set ellipsis [tcl::string::cat $replay_codes $opt_ellipsistext]
set ellipsis $replay_codes$opt_ellipsistext
#todo - overflow on left if allign = right??
set rendered [overtype::right $rendered $ellipsis]
}
@ -1701,8 +1701,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1769,6 +1769,9 @@ tcl::namespace::eval overtype {
return [join $outputlines \n]
}
variable optimise_ptruns 10 ;# can be set to zero to disable the ptruns branches
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# renderline written from a left-right line orientation perspective as a first-shot at getting something useful.
# ultimately right-to-left, top-to-bottom and bottom-to-top are probably needed.
@ -1802,6 +1805,7 @@ tcl::namespace::eval overtype {
#[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation.
#puts stderr "renderline '$args'"
variable optimise_ptruns
if {[llength $args] < 2} {
error {usage: ?-info 0|1? ?-startcolumn <int>? ?-cursor_column <int>? ?-cursor_row <int>|""? ?-transparent [0|1|<regexp>]? ?-expand_right [1|0]? undertext overtext}
@ -1973,58 +1977,107 @@ tcl::namespace::eval overtype {
foreach {pt code} $undermap {
#pt = plain text
#append pt_underchars $pt
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
if {$pt ne ""} {
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set hex [format %x [scan $p1 %c]] ;#punk::char::char_hex
set re [tcl::string::cat {^[} \\U$hex {]+$}]
set is_ptrun [regexp $re $pt]
}
if {$is_ptrun} {
#switch -- $p1 {
# " " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
# a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
# z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
# set width 1
# }
# default {
# if {$p1 eq "\u0000"} {
# #use null as empty cell representation - review
# #use of this will probably collide with some application at some point
# #consider an option to set the empty cell character
# set width 1
# } else {
# set width [grapheme_width_cached $p1] ;# when zero???
# }
# }
#}
set width [grapheme_width_cached $p1] ;# when zero???
set ptlen [string length $pt]
if {$width <= 1} {
#review - 0 and 1?
incr i_u $ptlen
lappend understacks {*}[lrepeat $ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $ptlen $u_gx_stack]
lappend undercols {*}[lrepeat $ptlen $p1]
} else {
incr i_u $ptlen ;#2nd col empty str - so same as above
set 2ptlen [expr {$ptlen * 2}]
lappend understacks {*}[lrepeat $2ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $2ptlen $u_gx_stack]
set l [concat {*}[lrepeat $ptlen [list $p1 ""]]
lappend undercols {*}$l
unset l
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme]
set grapheme $gvis
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
#zero width still acts as 1 below??? review what should happen
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme] ;#can only use with graphemes that have a single replacement char..
set grapheme $gvis
set width 1
}
}
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
#underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2168,23 +2221,31 @@ tcl::namespace::eval overtype {
# -- --- --- --- --- --- --- ---
####
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left of the right number of columns.
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left containing the right number of columns.
#this will be processed as transparent - and handle doublewidth underlay characters appropriately
set startpad_overlay [string repeat " " [expr {$opt_colstart -1}]]
append startpad_overlay $overdata ;#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpad_overlay ne ""} {
if {[punk::ansi::ta::detect $startpad_overlay]} {
set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
set startpadding [string repeat " " [expr {$opt_colstart -1}]]
#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpadding ne "" || $overdata ne ""} {
if {[punk::ansi::ta::detect $overdata]} {
set overmap [punk::ansi::ta::split_codes_single $startpadding$overdata]
} else {
#single plaintext part
set overmap [list $startpad_overlay]
set overmap [list $startpadding$overdata]
}
} else {
set overmap [list]
}
#set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
####
#todo - detect plain ascii no-ansi input line (aside from leading ansi reset)
#will that allow some optimisations?
#todo - detect repeated transparent char in overlay
#regexp {^(.)\1+$} ;#backtracking regexp - relatively slow.
# - try set c [string index $data 0]; regexp [string map [list %c% $c] {^[%c%]+$}] $data
#we should be able to optimize to pass through the underlay??
#???
set colcursor $opt_colstart
#TODO - make a little virtual column object
@ -2206,41 +2267,78 @@ tcl::namespace::eval overtype {
#experiment
set overlay_grapheme_control_stacks [list]
foreach {pt code} $overmap {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
if {$pt ne ""} {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+$}]
set is_ptrun [regexp $re $pt]
#leading only? we would have to check for graphemes at the trailing boundary?
#set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+}]
#set is_ptrun [regexp -indices $re $pt runrange]
#if {$is_ptrun && 1} {
#}
}
if {$is_ptrun} {
#review - in theory a run over a certain length won't be part of some grapheme combo (graphemes can be long e.g 44?, but not as runs(?))
#could be edge cases for runs at line end? (should be ok as we include trailing \n in our data)
set len [string length $pt]
set g_element [list g $p1]
#lappend overstacks {*}[lrepeat $len $o_codestack]
#lappend overstacks_gx {*}[lrepeat $len $o_gxstack]
#incr i_o $len
#lappend overlay_grapheme_control_list {*}[lrepeat $len [list g $p1]]
#lappend overlay_grapheme_control_stacks {*}[lrepeat $len $o_codestack]
set pi 0
incr i_o $len
while {$pi < $len} {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
lappend overlay_grapheme_control_list $g_element
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr pi
}
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2324,6 +2422,7 @@ tcl::namespace::eval overtype {
set o_codestack [list $temp_cursor_saved]
lappend overlay_grapheme_control_list [list other $code]
} else {
#review
if {[punk::ansi::codetype::is_gx_open $code]} {
set o_gxstack [list "gx0_on"]
lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets
@ -2837,7 +2936,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 3 end]]
}
7CSI - 7OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
set codenorm $leadernorm[tcl::string::range $code 2 end]
}
7DCS {
#ESC P
@ -2849,7 +2949,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
}
7ESC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
set codenorm $leadernorm[tcl::string::range $code 1 end]
}
8CSI - 8OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
@ -2886,7 +2987,12 @@ tcl::namespace::eval overtype {
A {
#Row move - up
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
set num $param
#todo
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row -$num
@ -2904,9 +3010,12 @@ tcl::namespace::eval overtype {
B {
#CUD - Cursor Down
#Row move - down
set num $param
lassign [split $param {;}] num modifierkey
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move down
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row $num
@ -2924,7 +3033,10 @@ tcl::namespace::eval overtype {
#todo - consider right-to-left cursor mode (e.g Hebrew).. some day.
#cursor forward
#right-arrow/move forward
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
#todo - retrict to moving 1 position past datalen? restrict to column width?
@ -3028,7 +3140,10 @@ tcl::namespace::eval overtype {
#puts stdout "<-back"
#cursor back
#left-arrow/move-back when ltr mode
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
set version 2
@ -4518,7 +4633,7 @@ tcl::namespace::eval overtype::priv {
if {$existing eq "\0"} {
lset o $i $c
} else {
lset o $i [string cat $existing $c]
lset o $i $existing$c
}
}
#is actually addgrapheme?

4
src/vfs/_vfscommon.vfs/modules/argparsingtest-0.1.0.tm

@ -296,7 +296,7 @@ namespace eval argparsingtest {
return [tcl::dict::get $argd opts]
}
punk::args::definition {
punk::args::define {
@id -id ::test1_punkargs_by_id
@cmd -name argtest4 -help "test of punk::args::get_dict comparative performance"
@opts -anyopts 0
@ -318,7 +318,7 @@ namespace eval argparsingtest {
return [tcl::dict::get $argd opts]
}
punk::args::definition {
punk::args::define {
@id -id ::argparsingtest::test1_punkargs2
@cmd -name argtest4 -help "test of punk::args::get_dict comparative performance"
@opts -anyopts 0

10
src/vfs/_vfscommon.vfs/modules/commandstack-0.3.tm

@ -211,6 +211,7 @@ namespace eval commandstack {
set new_code [string trim $procbody]
if {$current_code eq $new_code} {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command with same procbody - Aborting rename."
puts stderr [show_stack $command]
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command - but appears to be with new code - proceeding."
puts stdout "----------"
@ -223,6 +224,7 @@ namespace eval commandstack {
}
} else {
puts stderr "(commandstack::rename_command) WARNING - renamer '$renamer' has already renamed the '$command' command, but is not immediate predecessor - proceeding anyway... (untested)"
puts stderr
set next_target ::commandstack::renamed_commands::${mungedcommand}-${munged_next_implementor}-$mungedrenamer-$tokenid
set do_rename 1
}
@ -374,13 +376,13 @@ namespace eval commandstack {
proc show_stack {{commandname_glob *}} {
variable all_stacks
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
if {[package provide punk::lib] ne ""} {
return [punk::lib::pdict -channel none all_stacks $commandname_glob/@*/@*.@*]
} else {
if {![regexp {[?*]} $commandname_glob]} {
#if caller is attempting exact match - use the calling context to resolve in case they didn't supply namespace
set commandname_glob [uplevel 1 [list namespace which $commandname_glob]]
}
set result ""
set matchedkeys [dict keys $all_stacks $commandname_glob]
#don't try to calculate widest on empty list

309
src/vfs/_vfscommon.vfs/modules/overtype-1.6.5.tm

@ -449,7 +449,7 @@ tcl::namespace::eval overtype {
4 {
set inputchunks [list]
foreach ln [split $overblock \n] {
lappend inputchunks [string cat $ln \n]
lappend inputchunks $ln\n
}
if {[llength $inputchunks]} {
lset inputchunks end [tcl::string::range [lindex $inputchunks end] 0 end-1]
@ -499,9 +499,9 @@ tcl::namespace::eval overtype {
#set overtext [tcl::string::cat [lindex $replay_codes_overlay $overidx] $overtext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set overtext $replay_codes_overlay$overtext
if {[tcl::dict::exists $replay_codes_underlay $row]} {
set undertext [tcl::string::cat [tcl::dict::get $replay_codes_underlay $row] $undertext]
set undertext [tcl::dict::get $replay_codes_underlay $row]$undertext
}
#review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary -
#but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l
@ -1365,8 +1365,8 @@ tcl::namespace::eval overtype {
set udiff [expr {$renderwidth - $ulen}]
set undertext "$undertext[string repeat { } $udiff]"
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
#review - right-to-left langs should elide on left! - extra option required
@ -1518,8 +1518,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1545,7 +1545,7 @@ tcl::namespace::eval overtype {
}
}
if {$show_ellipsis} {
set ellipsis [tcl::string::cat $replay_codes $opt_ellipsistext]
set ellipsis $replay_codes$opt_ellipsistext
#todo - overflow on left if allign = right??
set rendered [overtype::right $rendered $ellipsis]
}
@ -1701,8 +1701,8 @@ tcl::namespace::eval overtype {
set startoffset 0 ;#negative?
}
set undertext [tcl::string::cat $replay_codes_underlay $undertext]
set overtext [tcl::string::cat $replay_codes_overlay $overtext]
set undertext $replay_codes_underlay$undertext
set overtext $replay_codes_overlay$overtext
set overflowlength [expr {$overtext_datalen - $renderwidth}]
if {$overflowlength > 0} {
@ -1769,6 +1769,9 @@ tcl::namespace::eval overtype {
return [join $outputlines \n]
}
variable optimise_ptruns 10 ;# can be set to zero to disable the ptruns branches
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# renderline written from a left-right line orientation perspective as a first-shot at getting something useful.
# ultimately right-to-left, top-to-bottom and bottom-to-top are probably needed.
@ -1802,6 +1805,7 @@ tcl::namespace::eval overtype {
#[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation.
#puts stderr "renderline '$args'"
variable optimise_ptruns
if {[llength $args] < 2} {
error {usage: ?-info 0|1? ?-startcolumn <int>? ?-cursor_column <int>? ?-cursor_row <int>|""? ?-transparent [0|1|<regexp>]? ?-expand_right [1|0]? undertext overtext}
@ -1973,58 +1977,107 @@ tcl::namespace::eval overtype {
foreach {pt code} $undermap {
#pt = plain text
#append pt_underchars $pt
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
if {$pt ne ""} {
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set hex [format %x [scan $p1 %c]] ;#punk::char::char_hex
set re [tcl::string::cat {^[} \\U$hex {]+$}]
set is_ptrun [regexp $re $pt]
}
if {$is_ptrun} {
#switch -- $p1 {
# " " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
# a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
# z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
# set width 1
# }
# default {
# if {$p1 eq "\u0000"} {
# #use null as empty cell representation - review
# #use of this will probably collide with some application at some point
# #consider an option to set the empty cell character
# set width 1
# } else {
# set width [grapheme_width_cached $p1] ;# when zero???
# }
# }
#}
set width [grapheme_width_cached $p1] ;# when zero???
set ptlen [string length $pt]
if {$width <= 1} {
#review - 0 and 1?
incr i_u $ptlen
lappend understacks {*}[lrepeat $ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $ptlen $u_gx_stack]
lappend undercols {*}[lrepeat $ptlen $p1]
} else {
incr i_u $ptlen ;#2nd col empty str - so same as above
set 2ptlen [expr {$ptlen * 2}]
lappend understacks {*}[lrepeat $2ptlen $u_codestack]
lappend understacks_gx {*}[lrepeat $2ptlen $u_gx_stack]
set l [concat {*}[lrepeat $ptlen [list $p1 ""]]
lappend undercols {*}$l
unset l
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme]
set grapheme $gvis
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
#an ugly but easy hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
#todo - test decimal value instead, compare performance
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
}
default {
if {$grapheme eq "\u0000"} {
#use null as empty cell representation - review
#use of this will probably collide with some application at some point
#consider an option to set the empty cell character
set width 1
} else {
#zero width still acts as 1 below??? review what should happen
set width [grapheme_width_cached $grapheme]
#we still want most controls and other zero-length codepoints such as \u200d (zero width joiner) to stay zero-length
#we substitute lone ESC that weren't captured within ANSI context as a debugging aid to see malformed ANSI
#todo - default to off and add a flag (?) to enable this substitution
set sub_stray_escapes 0
if {$sub_stray_escapes && $width == 0} {
if {$grapheme eq "\x1b"} {
set gvis [ansistring VIEW $grapheme] ;#can only use with graphemes that have a single replacement char..
set grapheme $gvis
set width 1
}
}
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
}
#set width [grapheme_width_cached $grapheme]
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols $grapheme
if {$width > 1} {
#presumably there are no triple-column or wider unicode chars.. until the aliens arrive.(?)
#but what about emoji combinations etc - can they be wider than 2?
#todo - if -etabs enabled - then we treat \t as the width determined by our elastic tabstop
incr i_u
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
lappend undercols ""
}
}
#underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2168,23 +2221,31 @@ tcl::namespace::eval overtype {
# -- --- --- --- --- --- --- ---
####
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left of the right number of columns.
#if opt_colstart - we need to build a space (or any singlewidth char ?) padding on the left containing the right number of columns.
#this will be processed as transparent - and handle doublewidth underlay characters appropriately
set startpad_overlay [string repeat " " [expr {$opt_colstart -1}]]
append startpad_overlay $overdata ;#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpad_overlay ne ""} {
if {[punk::ansi::ta::detect $startpad_overlay]} {
set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
set startpadding [string repeat " " [expr {$opt_colstart -1}]]
#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
if {$startpadding ne "" || $overdata ne ""} {
if {[punk::ansi::ta::detect $overdata]} {
set overmap [punk::ansi::ta::split_codes_single $startpadding$overdata]
} else {
#single plaintext part
set overmap [list $startpad_overlay]
set overmap [list $startpadding$overdata]
}
} else {
set overmap [list]
}
#set overmap [punk::ansi::ta::split_codes_single $startpad_overlay]
####
#todo - detect plain ascii no-ansi input line (aside from leading ansi reset)
#will that allow some optimisations?
#todo - detect repeated transparent char in overlay
#regexp {^(.)\1+$} ;#backtracking regexp - relatively slow.
# - try set c [string index $data 0]; regexp [string map [list %c% $c] {^[%c%]+$}] $data
#we should be able to optimize to pass through the underlay??
#???
set colcursor $opt_colstart
#TODO - make a little virtual column object
@ -2206,41 +2267,78 @@ tcl::namespace::eval overtype {
#experiment
set overlay_grapheme_control_stacks [list]
foreach {pt code} $overmap {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
if {$pt ne ""} {
#todo - wrap in test for empty pt (we used split_codes_single - and it may be common for sgr sequences to be unmerged and so have empty pts between)
if {$cp437_glyphs} {
set pt [tcl::string::map $cp437_map $pt]
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
append pt_overchars $pt
#will get empty pt between adjacent codes
if {!$crm_mode} {
set is_ptrun 0
if {$optimise_ptruns && [tcl::string::length $pt] >= $optimise_ptruns} {
set p1 [tcl::string::index $pt 0]
set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+$}]
set is_ptrun [regexp $re $pt]
#leading only? we would have to check for graphemes at the trailing boundary?
#set re [tcl::string::cat {^[} \\U[format %x [scan $p1 %c]] {]+}]
#set is_ptrun [regexp -indices $re $pt runrange]
#if {$is_ptrun && 1} {
#}
}
if {$is_ptrun} {
#review - in theory a run over a certain length won't be part of some grapheme combo (graphemes can be long e.g 44?, but not as runs(?))
#could be edge cases for runs at line end? (should be ok as we include trailing \n in our data)
set len [string length $pt]
set g_element [list g $p1]
#lappend overstacks {*}[lrepeat $len $o_codestack]
#lappend overstacks_gx {*}[lrepeat $len $o_gxstack]
#incr i_o $len
#lappend overlay_grapheme_control_list {*}[lrepeat $len [list g $p1]]
#lappend overlay_grapheme_control_stacks {*}[lrepeat $len $o_codestack]
set pi 0
incr i_o $len
while {$pi < $len} {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
lappend overlay_grapheme_control_list $g_element
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr pi
}
} else {
foreach grapheme [punk::char::grapheme_split $pt] {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
} else {
set tsbegin [clock micros]
foreach grapheme_original [punk::char::grapheme_split $pt] {
set pt_crm [ansistring VIEW -nul 1 -lf 2 -vt 2 -ff 2 $grapheme_original]
#puts stderr "ptlen [string length $pt] graphemelen[string length $grapheme_original] pt_crmlen[string length $pt_crm] $pt_crm"
foreach grapheme [punk::char::grapheme_split $pt_crm] {
if {$grapheme eq "\n"} {
lappend overlay_grapheme_control_stacks $o_codestack
lappend overlay_grapheme_control_list [list crmcontrol "\x1b\[00001E"]
} else {
lappend overstacks $o_codestack
lappend overstacks_gx $o_gxstack
incr i_o
lappend overlay_grapheme_control_list [list g $grapheme]
lappend overlay_grapheme_control_stacks $o_codestack
}
}
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
set elapsed [expr {[clock micros] - $tsbegin}]
puts stderr "ptlen [string length $pt] elapsedus:$elapsed"
}
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
@ -2324,6 +2422,7 @@ tcl::namespace::eval overtype {
set o_codestack [list $temp_cursor_saved]
lappend overlay_grapheme_control_list [list other $code]
} else {
#review
if {[punk::ansi::codetype::is_gx_open $code]} {
set o_gxstack [list "gx0_on"]
lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets
@ -2837,7 +2936,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 3 end]]
}
7CSI - 7OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 2 end]]
set codenorm $leadernorm[tcl::string::range $code 2 end]
}
7DCS {
#ESC P
@ -2849,7 +2949,8 @@ tcl::namespace::eval overtype {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
}
7ESC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
#set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
set codenorm $leadernorm[tcl::string::range $code 1 end]
}
8CSI - 8OSC {
set codenorm [tcl::string::cat $leadernorm [tcl::string::range $code 1 end]]
@ -2886,7 +2987,12 @@ tcl::namespace::eval overtype {
A {
#Row move - up
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
set num $param
#todo
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row -$num
@ -2904,9 +3010,12 @@ tcl::namespace::eval overtype {
B {
#CUD - Cursor Down
#Row move - down
set num $param
lassign [split $param {;}] num modifierkey
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move down
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
incr cursor_row $num
@ -2924,7 +3033,10 @@ tcl::namespace::eval overtype {
#todo - consider right-to-left cursor mode (e.g Hebrew).. some day.
#cursor forward
#right-arrow/move forward
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
#todo - retrict to moving 1 position past datalen? restrict to column width?
@ -3028,7 +3140,10 @@ tcl::namespace::eval overtype {
#puts stdout "<-back"
#cursor back
#left-arrow/move-back when ltr mode
set num $param
lassign [split $param {;}] num modifierkey
if {$modifierkey ne ""} {
puts stderr "modifierkey:$modifierkey"
}
if {$num eq ""} {set num 1}
set version 2
@ -4518,7 +4633,7 @@ tcl::namespace::eval overtype::priv {
if {$existing eq "\0"} {
lset o $i $c
} else {
lset o $i [string cat $existing $c]
lset o $i $existing$c
}
}
#is actually addgrapheme?

3
src/vfs/_vfscommon.vfs/modules/patternpunk-1.1.tm

@ -111,7 +111,8 @@ proc TCL {args} {
return $version
}
punk::args::definition {
punk::args::define {
#Review
@id -id ">punk . poses"
@cmd -name ">punk . poses" -help "Show or list the poses for the Punk mascot"
-censored -default 1 -type boolean -help "Set true to include mild toilet humour poses"

2
src/vfs/_vfscommon.vfs/modules/poshinfo-0.1.0.tm

@ -198,7 +198,7 @@ tcl::namespace::eval poshinfo {
error "unimplemented"
}
punk::args::definition {
punk::args::define {
@id -id ::poshinfo::themes
@cmd -name poshinfo::themes
-format -default all -multiple 1 -choices {all yaml json}\

242
src/vfs/_vfscommon.vfs/modules/punk-0.1.tm

@ -12,6 +12,242 @@ namespace eval punk {
#lazyload twapi ?
catch {package require vfs} ;#attempt load now so we can use faster 'package provide' to test existence later
variable can_exec_windowsapp
set can_exec_windowsapp unknown ;#don't spend a potential X00ms testing until needed
variable windowsappdir
set windowsappdir ""
variable cmdexedir
set cmdexedir ""
proc rehash {{refresh 0}} {
global auto_execs
if {!$refresh} {
unset -nocomplain auto_execs
} else {
set names [array names auto_execs]
unset -nocomplain auto_execs
foreach nm $names {
auto_execok_windows $nm
}
}
return
}
proc ::punk::auto_execok_original name [info body ::auto_execok]
variable better_autoexec
#set better_autoexec 0 ;#use this var via better_autoexec only
#proc ::punk::auto_execok_windows name {
# ::punk::auto_execok_original $name
#}
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
set has_commandstack [expr {![catch {package require commandstack}]}]
if {![interp issafe] && $has_commandstack && $::tcl_platform(platform) eq "windows"} {
#still a caching version of auto_execok - but with proper(fixed) search order
#set b [info body ::auto_execok]
#proc ::auto_execok_original name $b
proc better_autoexec {{onoff ""}} {
variable better_autoexec
if {$onoff eq ""} {
return $better_autoexec
}
if {![string is boolean -strict $onoff]} {
error "better_autoexec argument 'onoff' must be a boolean, received: $onoff"
}
if {$onoff && ($onoff != $better_autoexec)} {
puts "Turning on better_autoexec - search PATH first then extension"
set better_autoexec 1
proc ::punk::auto_execok_windows name {
::punk::auto_execok_better $name
}
punk::rehash
} elseif {!$onoff && ($onoff != $better_autoexec)} {
puts "Turning off better_autoexec - search extension then PATH"
set better_autoexec 0
proc ::punk::auto_execok_windows name {
::punk::auto_execok_original $name
}
punk::rehash
} else {
puts "no change"
}
}
#better_autoexec $better_autoexec ;#init to default
proc auto_execok_better name {
global auto_execs env tcl_platform
if {[info exists auto_execs($name)]} {
return $auto_execs($name)
}
#puts stdout "[a+ red]...[a]"
set auto_execs($name) ""
set shellBuiltins [list assoc cls copy date del dir echo erase exit ftype \
md mkdir mklink move rd ren rename rmdir start time type ver vol]
if {[info exists env(PATHEXT)]} {
# Add an initial ; to have the {} extension check first.
set execExtensions [split ";$env(PATHEXT)" ";"]
} else {
set execExtensions [list {} .com .exe .bat .cmd]
}
if {[string tolower $name] in $shellBuiltins} {
# When this is command.com for some reason on Win2K, Tcl won't
# exec it unless the case is right, which this corrects. COMSPEC
# may not point to a real file, so do the check.
set cmd $env(COMSPEC)
if {[file exists $cmd]} {
set cmd [file attributes $cmd -shortname]
}
return [set auto_execs($name) [list $cmd /c $name]]
}
if {[llength [file split $name]] != 1} {
foreach ext $execExtensions {
set file ${name}${ext}
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
return ""
}
#change1
#set path "[file dirname [info nameofexecutable]];.;"
set path "[file dirname [info nameofexecutable]];"
if {[info exists env(SystemRoot)]} {
set windir $env(SystemRoot)
} elseif {[info exists env(WINDIR)]} {
set windir $env(WINDIR)
}
if {[info exists windir]} {
append path "$windir/system32;$windir/system;$windir;"
}
foreach var {PATH Path path} {
if {[info exists env($var)]} {
append path ";$env($var)"
}
}
#change2
set lookfor [lmap ext $execExtensions {string cat ${name} ${ext}}]
foreach dir [split $path {;}] {
#set dir [file normalize $dir]
# Skip already checked directories
if {[info exists checked($dir)] || ($dir eq "")} {
continue
}
set checked($dir) {}
foreach match [glob -nocomplain -dir $dir -tail {*}$lookfor] {
set file [file join $dir $match]
if {[file exists $file] && ![file isdirectory $file]} {
return [set auto_execs($name) [list $file]]
}
}
}
#foreach ext $execExtensions {
#unset -nocomplain checked
#foreach dir [split $path {;}] {
# # Skip already checked directories
# if {[info exists checked($dir)] || ($dir eq "")} {
# continue
# }
# set checked($dir) {}
# set file [file join $dir ${name}${ext}]
# if {[file exists $file] && ![file isdirectory $file]} {
# return [set auto_execs($name) [list $file]]
# }
#}
#}
return ""
}
#review - what if punk package reloaded - but ::auto_execs has updated path for winget.exe?
#what if we create another interp and use the same ::auto_execs? The appdir won't be detected.
#TODO - see if there is a proper windows way to determine where the 'reparse point' apps are installed
#winget is installed on all modern windows and is an example of the problem this addresses
#we target apps with same location
#the main purpose of this override is to support windows app executables (installed as 'reparse points')
#for Tcl versions prior to the 2025-01 fix by APN https://core.tcl-lang.org/tcl/tktview/4f0b5767ac
#versions prior to this will use cmd.exe to resolve the links
set stackrecord [commandstack::rename_command -renamer ::punk auto_execok name {
#set windowsappdir "%appdir%"
upvar ::punk::can_exec_windowsapp can_exec_windowsapp
upvar ::punk::windowsappdir windowsappdir
upvar ::punk::cmdexedir cmdexedir
if {$windowsappdir eq ""} {
#we are targeting the winget location under the presumption this is where microsoft store apps are stored as 'reparse points'
#Tcl (2025) can't exec when given a path to these 0KB files
#This path is probably something like C:/Users/username/AppData/Local/Microsoft/WindowsApps
if {!([info exists ::env(LOCALAPPDATA)] &&
[file exists [set testapp [file join $::env(LOCALAPPDATA) "Microsoft" "WindowsApps" "winget.exe"]]])} {
#should be unlikely to get here - unless LOCALAPPDATA missing
set windowsappdir [file dirname [lindex [::punk::auto_execok_windows winget.exe] 0]]
puts stderr "(resolved winget by search)"
} else {
set windowsappdir [file dirname $testapp]
}
}
#set default_auto [$COMMANDSTACKNEXT $name]
set default_auto [::punk::auto_execok_windows $name]
#if {$name ni {cmd cmd.exe}} {
# unset -nocomplain ::auto_execs
#}
if {$default_auto eq ""} {
return
}
set namedir [file dirname [lindex $default_auto 0]]
if {$namedir eq $windowsappdir} {
if {$can_exec_windowsapp eq "unknown"} {
if {[catch {exec [file join $windowsappdir winget.exe] --version}]} {
set can_exec_windowsapp 0
} else {
set can_exec_windowsapp 1
}
}
if {$can_exec_windowsapp} {
return [file join $windowsappdir $name]
}
if {$cmdexedir eq ""} {
#cmd.exe very unlikely to move
set cmdexedir [file dirname [lindex [::punk::auto_execok_windows cmd.exe] 0]]
#auto_reset never seems to exist as a command - because auto_reset deletes all commands in the ::auto_index
#anyway.. it has other side effects (affects auto_load)
}
return "[file join $cmdexedir cmd.exe] /c $name"
}
return $default_auto
}]
}
}
@ -5321,8 +5557,8 @@ namespace eval punk {
}
return -options $opts $msg
} else {
dict incr opts -level
return -options $opts $msg
dict incr opts -level
return -options $opts $msg
}
}
}
@ -7152,7 +7388,7 @@ namespace eval punk {
dict filter $result value {?*}
}
punk::args::definition {
punk::args::define {
@id -id ::punk::inspect
@cmd -name punk::inspect -help\
"Function to display values - used pimarily in a punk pipeline.

1
src/vfs/_vfscommon.vfs/modules/punk/aliascore-0.1.0.tm

@ -115,6 +115,7 @@ tcl::namespace::eval punk::aliascore {
pdict ::punk::lib::pdict\
plist {::punk::lib::pdict -roottype list}\
showlist {::punk::lib::showdict -roottype list}\
rehash ::punk::rehash\
showdict ::punk::lib::showdict\
ansistrip ::punk::ansi::ansistrip\
stripansi ::punk::ansi::ansistrip\

2
src/vfs/_vfscommon.vfs/modules/punk/ansi-0.1.1.tm

@ -5568,6 +5568,7 @@ tcl::namespace::eval punk::ansi::class {
}
#does not affect object state
#REVIEW - icu or equiv required
method DoCount {plaintext} {
#- combiners/diacritics just map them away here - but for consistency we need to combine unicode grapheme clusters too.
#todo - joiners 200d? zwnbsp
@ -5672,6 +5673,7 @@ tcl::namespace::eval punk::ansi::class {
method renderbuf {} {
#get the underlying renderobj - if any
#return $o_renderout ;#also class_ansistring
if {$o_renderer eq ""} {error "renderbuf error: no active renderer"}
return [$o_renderer renderbuf]
}
method render {{maxgraphemes ""}} {

1930
src/vfs/_vfscommon.vfs/modules/punk/args-0.1.0.tm

File diff suppressed because it is too large Load Diff

100
src/vfs/_vfscommon.vfs/modules/punk/args/tclcore-0.1.0.tm

@ -208,7 +208,7 @@ tcl::namespace::eval punk::args::tclcore {
#todo - make generic - take command and known_groups_dict
proc info_subcommands {} {
package require punk::ns
set subdict [punk::ns::ensemble_subcommands info]
set subdict [punk::ns::ensemble_subcommands -return dict info]
set allsubs [dict keys $subdict]
dict set groups "system" {hostname library nameofexecutable patchlevel script sharedlibextension tclversion}
dict set groups "{proc introspection}" {args body default}
@ -234,8 +234,58 @@ tcl::namespace::eval punk::args::tclcore {
}
append argdef " \}" \n
#todo -choicelabels
#detect subcommand further info available e.g if oo or ensemble or punk::args id exists..
#consider a different mechanism to add a label on rhs of same line as choice (for (i) marker)
return $argdef
}
lappend PUNKARGS [list -dynamic 1 {
#test of @form
@id -id ::AFTER
@cmd -name "Builtin: after" -help\
"Execute a command after a time delay."
# ---------- shared elements -------------
@ref -id common_script_help -help\
"script argument to be concatenated in the same fashion as the concat command"
# ---------- shared elements -------------
@form -form {delay} -synopsis "after ms"
@form -form {schedule_ms} -synopsis "after ms ?script...?"
#@values -form {*} #note "classify next argument as a value not a leader"
ms -form {*} -type int
@values -form {delay} -min 1 -max 1
@values -form {schedule_ms} -min 2
script -form {schedule_ms} -multiple 1 -optional 1 ref-help common_script_help
@form -form {cancelid} -synopsis "after cancel id"
@values
cancel -choices {cancel}
id
@form -form {cancelscript} -synopsis "after cancel script ?script...?"
@values -min 2
cancel -choices {cancel}
script -multiple 1 -optional 0 ref-help common_script_help
@form -form {schedule_idle} -synopsis "after idle script ?script...?"
@values -min 1
idle -choices {idle}
script -multiple 1 -optional 1 ref-help common_script_help
@form -form {info} -synopsis "after info ?id?"
info -choices {info}
id -optional 1
} "@doc -name Manpage: -url [manpage_tcl after]" ]
lappend PUNKARGS [list -dynamic 1 {
@id -id ::info
@cmd -name "Builtin: info" -help\
@ -290,11 +340,11 @@ tcl::namespace::eval punk::args::tclcore {
characters are used. When decoding, upper and lower characters are accepted."
} "@doc -name Manpage: -url [manpage_tcl binary]" ]
lappend PUNKARGS [list {
@id -id "::tcl::binary::encode::hex"
@default -id (default)::tcl::binary::*::hex
@cmd -name "binary encode hex"
@values -min 1 -max 1
data -type string
@id -id "::tcl::binary::encode::hex"
@default -id (default)::tcl::binary::*::hex
@cmd -name "binary encode hex"
@values -min 1 -max 1
data -type string
} ]
lappend PUNKARGS [list {
@id -id "::tcl::binary::decode::hex"
@ -534,7 +584,7 @@ tcl::namespace::eval punk::args::tclcore {
value -type any -optional 1 -multiple 1
} "@doc -name Manpage: -url [manpage_tcl lappend]"]
punk::args::definition {
punk::args::define {
@id -id ::ledit
@cmd -name "builtin: ledit" -help\
"Replace elements of a list stored in variable
@ -547,7 +597,7 @@ tcl::namespace::eval punk::args::tclcore {
value -type any -optional 1 -multiple 1
} "@doc -name Manpage: -url [manpage_tcl ledit]"
punk::args::definition {
punk::args::define {
@id -id ::lpop
@cmd -name "builtin: lpop" -help\
"Get and remove an element in a list
@ -567,7 +617,7 @@ tcl::namespace::eval punk::args::tclcore {
in sublists, similar to lindex and lset."
} "@doc -name Manpage: -url [manpage_tcl lpop]"
punk::args::definition {
punk::args::define {
@id -id ::lrange
@cmd -name "builtin: lrange" -help\
"return one or more adjacent elements from a list.
@ -587,23 +637,23 @@ tcl::namespace::eval punk::args::tclcore {
} "@doc -name Manpage: -url [manpage_tcl lrange]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::cat
@cmd -name "builtin: tcl::string::cat" -help\
"Concatente the given strings just like placing them directly next to each other and
"Concatenate the given strings just like placing them directly next to each other and
return the resulting compound string. If no strings are present, the result is an
empty string.
This primitive is occasionally handier than juxtaposition of strings when mixed quoting
is wanted, or when the aim is to return the result of a concatentation without resorting
to return -level 0, and is more efficient than building a list of arguments and using
join with an empty join string."
@form -synopsis "string cat ?string...?"
@values -min 0 -max -1
string -type string -optional 1 -multiple 1
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::compare
@cmd -name "builtin: tcl::string::compare" -help\
@ -623,7 +673,7 @@ tcl::namespace::eval punk::args::tclcore {
string2 -type string
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::equal
@cmd -name "builtin: tcl::string::equal" -help\
@ -642,7 +692,7 @@ tcl::namespace::eval punk::args::tclcore {
string2 -type string
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::first
@cmd -name "builtin: tcl::string::first" -help\
"Search haystackString for a sequence of characters that exactly match the characters
@ -658,7 +708,7 @@ tcl::namespace::eval punk::args::tclcore {
"integer or simple expression."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::insert
@cmd -name "builtin: tcl::string::insert" -help\
"Returns a copy of string with insertString inserted at the index'th character.
@ -679,7 +729,7 @@ tcl::namespace::eval punk::args::tclcore {
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::last
@cmd -name "builtin: tcl::string::last" -help\
"Search haystackString for a sequence of characters that exactly match the characters
@ -695,7 +745,7 @@ tcl::namespace::eval punk::args::tclcore {
"integer or simple expression."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::repeat
@cmd -name "builtin: tcl::string::repeat" -help\
"Returns a string consisting of string concatenated with itself count times."
@ -705,7 +755,7 @@ tcl::namespace::eval punk::args::tclcore {
"If count is 0, the empty string will be returned."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::replace
@cmd -name "builtin: tcl::string::replace" -help\
"Removes a range of consecutive characters from string, starting with the character whose
@ -725,7 +775,7 @@ tcl::namespace::eval punk::args::tclcore {
"If newstring is specified, then it is placed in the removed character range."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::totitle
@cmd -name "builtin: tcl::string::totitle" -help\
"Returns a value equal to string except that the first character in string is converted to
@ -740,7 +790,7 @@ tcl::namespace::eval punk::args::tclcore {
"If last is specified, it refers to the char index in the string to stop at (inclusive)."
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::wordend
@cmd -name "builtin: tcl::string::wordend" -help\
"Returns the index of the character just after the last one in the word containing
@ -756,7 +806,7 @@ tcl::namespace::eval punk::args::tclcore {
e.g M+N"
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::tcl::string::wordstart
@cmd -name "builtin: tcl::string::wordstart" -help\
"Returns the index of the first character in the word containing
@ -773,7 +823,7 @@ tcl::namespace::eval punk::args::tclcore {
e.g M+N"
} "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition [punk::lib::tstr -return string {
punk::args::define [punk::lib::tstr -return string {
@id -id ::tcl::string::is
@cmd -name "builtin: tcl::string::is" -help\
"Returns 1 if string is a valid member of the specified character class, otherwise returns 0.
@ -932,7 +982,7 @@ tcl::namespace::eval punk::args::tclcore {
string -type string -optional 0
}] "@doc -name Manpage: -url [manpage_tcl string]"
punk::args::definition {
punk::args::define {
@id -id ::zlib
@cmd -name "builtin: ::zlib" -help\
"zlib - compression and decompression operations
@ -960,7 +1010,7 @@ tcl::namespace::eval punk::args::tclcore {
}
} "@doc -name Manpage: -url [manpage_tcl zlib]"
punk::args::definition {
punk::args::define {
@id -id "::zlib adler32"
@cmd -name "builtin: ::zlib adler32" -help\
"Compute a checksum of binary string ${$I}string${$NI} using the Adler32

8
src/vfs/_vfscommon.vfs/modules/punk/blockletter-0.1.0.tm

@ -119,7 +119,7 @@ tcl::namespace::eval punk::blockletter {
set logo_letter_colours [list Web-red Web-green Web-royalblue Web-purple Web-orange]
set logo_letter_colours [list Red Green Blue Purple Yellow]
punk::args::definition [tstr -return string {
punk::args::define [tstr -return string {
@id -id ::punk::blockletter::logo
-frametype -default {${$default_frametype}}
-outlinecolour -default "web-white"
@ -218,7 +218,7 @@ tcl::namespace::eval punk::blockletter {
append out [textblock::join_basic -- $left $centre $right]
}
punk::args::definition [tstr -return string {
punk::args::define [tstr -return string {
@id -id ::punk::blockletter::text
-bgcolour -default "Web-red"
-bordercolour -default "web-white"
@ -280,7 +280,9 @@ tcl::namespace::eval punk::blockletter::lib {
#}
punk::args::definition [tstr -return string {
#use tstr when resolving params as a one-off at definition time
#versus slower -dynamic 1 if defaults/choices etc need to reflect the current state of the system.
punk::args::define [tstr -return string {
@id -id ::punk::blockletter::block
-height -default 2
-width -default 4

4
src/vfs/_vfscommon.vfs/modules/punk/char-0.1.0.tm

@ -1246,6 +1246,10 @@ tcl::namespace::eval punk::char {
return [charset_dict "Box Drawing"]
}
proc char_hex {char} {
return [format %08x [scan $char %c]]
}
proc char_info_hex {hex args} {
set hex [tcl::string::map [list _ ""] $hex]
if {[tcl::string::is xdigit -strict $hex]} {

2
src/vfs/_vfscommon.vfs/modules/punk/console-0.1.1.tm

@ -1186,7 +1186,7 @@ namespace eval punk::console {
#todo - change -inoutchannels to -terminalobject with prebuilt default
punk::args::definition {
punk::args::define {
@id -id ::punk::console::cell_size
-inoutchannels -default {stdin stdout} -type list
@values -min 0 -max 1

2
src/vfs/_vfscommon.vfs/modules/punk/fileline-0.1.0.tm

@ -1251,7 +1251,7 @@ namespace eval punk::fileline {
#[para] Core API functions for punk::fileline
#[list_begin definitions]
punk::args::definition {
punk::args::define {
@id -id ::punk::fileline::get_textinfo
@cmd -name punk::fileline::get_textinfo -help\
"return: textinfo object instance"

2
src/vfs/_vfscommon.vfs/modules/punk/mix/commandset/loadedlib-0.1.0.tm

@ -26,7 +26,7 @@ package require punk::lib
namespace eval punk::mix::commandset::loadedlib {
namespace export *
#search automatically wrapped in * * - can contain inner * ? globs
punk::args::definition {
punk::args::define {
@id -id ::punk::mix::commandset::loadedlib::search
@cmd -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}

2
src/vfs/_vfscommon.vfs/modules/punk/mix/commandset/module-0.1.0.tm

@ -141,7 +141,7 @@ namespace eval punk::mix::commandset::module {
set moduletypes [punk::mix::cli::lib::module_types]
punk::args::definition [subst {
punk::args::define [subst {
@id -id ::punk::mix::commandset::module::new
@cmd -name "punk::mix::commandset::module::new" -help\
"Create a new module file in the appropriate folder within src/modules.

4
src/vfs/_vfscommon.vfs/modules/punk/nav/fs-0.1.0.tm

@ -636,7 +636,7 @@ tcl::namespace::eval punk::nav::fs {
# c:/repo/jn/punk/../../blah
#dirfiles assumes we don't have glob chars in the filenames or paths - dirfiles_dict can be called directly with explicit -tailglob in the rare case that assumption doesn't hold
# dirfiles will test last segment (tail) of supplied searchspecs for fileness vs folderness (when no globchars present in tail) so that it can pass the appropriate flags downstream
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles
-stripbase -default 1 -type boolean
-formatsizes -default 1 -type boolean -help "Format file size numbers for clarity"
@ -992,7 +992,7 @@ tcl::namespace::eval punk::nav::fs {
return [dict merge $listing $updated]
}
punk::args::definition {
punk::args::define {
@id -id ::punk::nav::fs::dirfiles_dict_as_lines
-stripbase -default 0 -type boolean
-formatsizes -default 1 -type boolean

122
src/vfs/_vfscommon.vfs/modules/punk/ns-0.1.0.tm

@ -1893,7 +1893,31 @@ tcl::namespace::eval punk::ns {
}
} |data@@ok/result> {lmap v $data {punk::ns::nstail $v}} |> lsort |> {join $data \n} <ns/0|
proc ensemble_subcommands {origin} {
punk::args::define {
@id -id ::punk::ns::ensemble_subcommands
@cmd -name punk::ns::ensemble_subcommands -help\
"Returns a dictionary keyed on subcommand with each value pointing
to the implementation command.
This is not guaranteed to be complete - e.g for ensembles which use
the namespace ensemble 'unknown' mechanism to implement subcommands.
The subcommand information is gathered from entries in the '-map' as
well as those exported from the namespace in '-namespace' if the
'-subcommands' list has been configured for the ensemble.
"
-return -default dict -choices {show dict} -choicelabels {
show "display the result in 'showdict' format"
}
@values -min 1 -max 1
origin -help\
"Name of ensemble command for which subcommand info is gathered."
}
proc ensemble_subcommands {args} {
set argd [punk::args::get_by_id ::punk::ns::ensemble_subcommands $args]
set opts [dict get $argd opts]
set origin [dict get $argd values origin]
set ensembleinfo [namespace ensemble configure $origin]
set prefixes [dict get $ensembleinfo -prefixes]
set map [dict get $ensembleinfo -map]
@ -1936,12 +1960,16 @@ tcl::namespace::eval punk::ns {
}
}
}
return $subcommand_dict
if {[dict get $opts -return] eq "dict"} {
return $subcommand_dict
} else {
return [punk::lib::showdict $subcommand_dict]
}
}
#todo - -cache or -refresh to configure whether we introspect ensembles/objects each time?
# - as this is interactive generally introspection should be ok at the top level
# but if we need to go down multiple levels of subcommands generating/testing prefixes - could be an issue ??
punk::args::definition {
punk::args::define -dynamic 0 {
@id -id ::punk::ns::arginfo
@cmd -name punk::ns::arginfo -help\
"Show usage info for a command.
@ -1965,6 +1993,10 @@ tcl::namespace::eval punk::ns {
exit the interp etc)
"
-return -type string -default table -choices {string table tableobject}
} {${[punk::args::get_spec ::punk::args::arg_error -scheme]}} {
-- -type none -help\
"End of options marker
Use this if the command to view begins with a -"
@ -1977,6 +2009,13 @@ tcl::namespace::eval punk::ns {
}
proc arginfo {args} {
lassign [dict values [punk::args::get_by_id ::punk::ns::arginfo $args]] leaders opts values received
#review - setting this afterwards is an architecture smell - we should be able to override the default in the dynamic part
#todo - enable retrieving by id just the record_opts part - so we can treat as a dict directly, as well as easily apply it as a different flag name.
if {![dict exists $received -scheme]} {
dict set opts -scheme info
}
set querycommand [dict get $values commandpath]
set queryargs [dict get $values subcommand]
punk::args::update_definitions ;#ensure any packages that register PUNKARGS have been loaded
@ -2035,9 +2074,11 @@ tcl::namespace::eval punk::ns {
} else {
#namespace as relative to current doesn't seem to exist
#Tcl would also attempt to resolve as global
set numvals [expr {[llength $queryargs]+1}]
#puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
#set numvals [expr {[llength $queryargs]+1}]
##puts "THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]"
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $querycommand {*}$queryargs]]
#set origin $querycommand
#set resolved $querycommand
@ -2068,9 +2109,10 @@ tcl::namespace::eval punk::ns {
#(possible curried arguments)
#review - curried arguments could be for ensembles!
set targetword $word1
set numvals [expr {[llength $queryargs]+1}]
#set numvals [expr {[llength $queryargs]+1}]
#puts "ALIAS THROWBACK: namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]"
return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
#return [namespace eval :: [list punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
return [namespace eval :: [list punk::ns::arginfo {*}$opts $targetword {*}[lrange $tgt 1 end] {*}$queryargs]]
}
@ -2115,11 +2157,11 @@ tcl::namespace::eval punk::ns {
set nextqueryargs [list] ;#build a list of prefix-resolved queryargs
set queryargs_untested $queryargs
foreach q $queryargs {
if {[llength [dict get $def leader_names]]} {
set subitems [dict get $def leader_names]
if {[llength [dict get $def LEADER_NAMES]]} {
set subitems [dict get $def LEADER_NAMES]
if {[llength $subitems]} {
set next [lindex $subitems 0]
set arginfo [dict get $def arg_info $next]
set arginfo [dict get $def ARG_INFO $next]
set allchoices [list]
set choices [punk::args::system::Dict_getdef $arginfo -choices {}]
@ -2140,8 +2182,11 @@ tcl::namespace::eval punk::ns {
lpop queryargs_untested 0
if {$resolved_q ne $q} {
#we have our first difference - recurse with new query args
set numvals [expr {[llength $queryargs]+1}]
return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
#set numvals [expr {[llength $queryargs]+1}]
#return [ punk::ns::arginfo {*}[lrange $args 0 end-$numvals] $querycommand {*}$nextqueryargs {*}$queryargs_untested]
return [ punk::ns::arginfo {*}$opts $querycommand {*}$nextqueryargs {*}$queryargs_untested]
}
#check if subcommands so far have a custom args def
set currentid [list $querycommand {*}$nextqueryargs]
@ -2188,7 +2233,7 @@ tcl::namespace::eval punk::ns {
new {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} new"
@cmd -name "${$origin} new" -help\
"create object with specified command name.
@ -2200,22 +2245,22 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin new"]
}
create {
set constructorinfo [info class constructor $origin]
set arglist [lindex $constructorinfo 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(autodef)${$origin} create"
@cmd -name "${$origin} create" -help\
"create object with specified command name.
@ -2229,29 +2274,29 @@ tcl::namespace::eval punk::ns {
if {[llength $a] == 1} {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
} else {
append argspec \n "[lindex $a 0] -default [lindex $a 1]"
append argdef \n "[lindex $a 0] -default [lindex $a 1]"
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin create"]
}
destroy {
#review - generally no doc
# but we may want notes about a specific destructor
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "(audodef)${$origin} destroy"
@cmd -name "destroy" -help\
"delete object, calling destructor if any.
destroy accepts no arguments."
@values -min 0 -max 0
}]
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts "(autodef)$origin destroy"]
}
default {
@ -2301,7 +2346,7 @@ tcl::namespace::eval punk::ns {
#assert - if we pre
set autoid "(autodef)$location $c1"
set arglist [lindex $def 0]
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@cmd -name "${$location} ${$c1}" -help\
"(autogenerated)
@ -2314,13 +2359,13 @@ tcl::namespace::eval punk::ns {
1 {
if {$i == [llength $arglist]-1 && $a eq "args"} {
#'args' is only special if last
append argspec \n "args -optional 1 -multiple 1"
append argdef \n "args -optional 1 -multiple 1"
} else {
append argspec \n "$a"
append argdef \n "$a"
}
}
2 {
append argspec \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
append argdef \n "[lindex $a 0] -default {[lindex $a 1]} -optional 1"
}
default {
error "punk::ns::arginfo unexpected argument signature '$arglist'\ndef:$def\nimplementaions:$implementations"
@ -2328,7 +2373,7 @@ tcl::namespace::eval punk::ns {
}
incr i
}
punk::args::definition $argspec
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
} else {
return "unable to resolve $origin method $c1"
@ -2378,14 +2423,14 @@ tcl::namespace::eval punk::ns {
set vline [list method -choices $public_methods -choicelabels $choicelabeldict -choiceprefix 0] ;#methods must be specified in full always? - review
#puts stderr "--->$vline"
set idauto "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$idauto}
@cmd -name "Object: ${$origin}" -help\
"Instance of class: ${$class} (info autogenerated)"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $idauto]
}
privateObject {
@ -2457,7 +2502,8 @@ tcl::namespace::eval punk::ns {
set match [tcl::prefix::match $subcommands [lindex $queryargs 0]]
if {$match in $subcommands} {
set subcmd [dict get $subcommand_dict $match]
return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
#return [arginfo {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
return [arginfo {*}$opts {*}$subcmd {*}[lrange $queryargs 1 end]] ;#subcmd is sometimes multiple words (implemented as a further ensemble subcommand) (e.g huddle string -> "Type_string string")
}
}
@ -2491,15 +2537,15 @@ tcl::namespace::eval punk::ns {
set vline [list subcommand -choices $subcommands -choiceprefix $prefixes -choicelabels $choicelabeldict]
set autoid "(autodef)$origin"
set argspec [punk::lib::tstr -return string {
set argdef [punk::lib::tstr -return string {
@id -id ${$autoid}
@cmd -help\
"(autogenerated)
ensemble: ${$origin}"
@values -min 1
}]
append argspec \n $vline
punk::args::definition $argspec
append argdef \n $vline
punk::args::define $argdef
return [punk::args::usage {*}$opts $autoid]
}
@ -2918,7 +2964,7 @@ tcl::namespace::eval punk::ns {
}
interp alias "" use "" punk::ns::pkguse
punk::args::definition {
punk::args::define {
@id -id ::punk::ns::nsimport_noclobber
@cmd -name punk::ns::nsimport_noclobber -help\
"Import exported commands from a namespace into either the current namespace,

2
src/vfs/_vfscommon.vfs/modules/punk/path-0.1.0.tm

@ -644,7 +644,7 @@ namespace eval punk::path {
return $ismatch
}
punk::args::definition {
punk::args::define {
@id -id ::punk::path::treefilenames
-directory -type directory -help\
"folder in which to begin recursive scan for files."

2
src/vfs/_vfscommon.vfs/modules/punk/repl-0.1.tm

@ -1580,7 +1580,7 @@ proc punk::repl::console_debugview {editbuf consolewidth args} {
set spacepatch [textblock::block $debug_width $patch_height " "]
puts -nonewline [punk::ansi::cursor_off]
#use non cursorsave versions - cursor save/restore will interfere with any concurrent ansi rendering that uses save/restore - because save/restore is a single item, not a stack.
set debug_offset [[expr {$consolewidth - $debug_width - $opt_rightmargin}]]
set debug_offset [expr {$consolewidth - $debug_width - $opt_rightmargin}]
set row_clear [expr {$opt_row -2}]
punk::console::move_emitblock_return $row_clear $debug_offset $spacepatch
punk::console::move_emitblock_return $opt_row $debug_offset $info

39
src/vfs/_vfscommon.vfs/modules/punk/repo-0.1.1.tm

@ -65,6 +65,22 @@ namespace eval punk::repo {
variable PUNKARGS
variable PUNKARGS_aliases
variable cached_command_paths
set cached_command_paths [dict create]
#anticipating possible removal of buggy caching from auto_execok
#mentioned in: https://core.tcl-lang.org/tcl/tktview/4dc35e0c0c
#this would leave the application to decide what it wants to cache in that regard.
proc Cached_auto_execok {name} {
return [auto_execok $name]
#variable cached_command_paths
#if {[dict exists $cached_command_paths $name]} {
# return [dict get $cached_command_paths $name]
#}
#set resolved [auto_execok $name]
#dict set cached_command_paths $name $resolved
#return $resolved
}
proc get_fossil_usage {} {
set allcmds [runout -n fossil help -a]
set mainhelp [runout -n fossil help]
@ -197,7 +213,7 @@ namespace eval punk::repo {
#emit warning whether or not multiple fossil repos
puts stdout [dict get $repostate warnings]
}
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog ne ""} {
{*}$fossil_prog {*}$args
} else {
@ -222,7 +238,10 @@ namespace eval punk::repo {
#uppercase FOSSIL to bypass fossil as alias to fossil_proxy
#only necessary on unix?
#Windows filesystem case insensitive so any non-lowercase fossil version goes out to get an ::auto_execs entry anyway
proc establish_FOSSIL {args} {
#review
if {![info exists ::auto_execs(FOSSIL)]} {
set ::auto_execs(FOSSIL) [auto_execok fossil] ;#may fail in safe interp
}
@ -499,7 +518,7 @@ namespace eval punk::repo {
#For this reason we will store 'unchanged' records for both git and fossil so that the combined dict should represent all files in the revision
if {$rt eq "fossil"} {
dict set resultdict repotype fossil
set fossil_cmd [auto_execok fossil]
set fossil_cmd [Cached_auto_execok fossil]
if {$fossil_cmd eq ""} {
error "workingdir_state error: fossil executable doesn't seem to be available"
}
@ -598,7 +617,7 @@ namespace eval punk::repo {
break
} elseif {$rt eq "git"} {
dict set resultdict repotype git
set git_cmd [auto_execok git]
set git_cmd [Cached_auto_execok git]
# -uno = suppress ? lines.
# -b = show ranch and tracking info
#our basic parsing/grepping assumes --porcelain=2
@ -988,7 +1007,7 @@ namespace eval punk::repo {
}
proc fossil_get_repository_file {{path {}}} {
if {$path eq {}} { set path [pwd] }
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set fossilinfo [::exec {*}$fossilcmd info]
@ -1073,7 +1092,7 @@ namespace eval punk::repo {
set startdir $opt_parentfolder
set fossil_prog [auto_execok fossil]
set fossil_prog [Cached_auto_execok fossil]
if {$fossil_prog eq ""} {
puts stderr "Fossil not found. Please install fossil"
return
@ -1319,7 +1338,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] rev-parse HEAD] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1332,7 +1351,7 @@ namespace eval punk::repo {
try {
#git describe will error with 'No names found' if repo has no tags
#set v [::exec {*}[auto_execok git] describe]
set v [::exec {*}[auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
set v [::exec {*}[Cached_auto_execok git] remote -v] ;# consider 'git rev-parse --short HEAD'
} on error {e o} {
set v [lindex [split [dict get $o -errorinfo] \n] 0]
}
@ -1343,7 +1362,7 @@ namespace eval punk::repo {
proc fossil_revision {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd info]
@ -1357,7 +1376,7 @@ namespace eval punk::repo {
proc fossil_remote {{path {}}} {
if {$path eq {}} { set path [pwd] }
# ::kettle::path::revision.fossil
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {[llength $fossilcmd]} {
do_in_path $path {
set info [::exec {*}$fossilcmd remote ls]
@ -1423,7 +1442,7 @@ namespace eval punk::repo {
set original_cwd [pwd]
#attempt2 - let fossil do it for us - hopefully based on current folder
if {$path eq {}} {set path [pwd]}
set fossilcmd [auto_execok fossil]
set fossilcmd [Cached_auto_execok fossil]
if {![llength $fossilcmd]} {
set fossil_ok 0
} else {

8
src/vfs/_vfscommon.vfs/modules/punk/safe-0.1.0.tm

@ -458,7 +458,7 @@ tcl::namespace::eval punk::safe {
# If we have exactly 2 arguments the semantic is a "configure get"
lassign $args child arg
set spec_dict [punk::args::definition [punk::args::get_spec punk::safe::interpIC]]
set spec_dict [punk::args::define [punk::args::get_spec punk::safe::interpIC]]
set opt_names [dict get $spec_dict opt_names]
CheckInterp $child
@ -761,7 +761,7 @@ tcl::namespace::eval punk::safe::system {
append OPTS \n {-autoPath -type list -default {} -help\
"::auto_path for the child"}
}
punk::args::definition $OPTS
punk::args::define $OPTS
set optlines [punk::args::get_spec punk::safe::OPTS -*]
set INTERPCREATE {
@ -775,7 +775,7 @@ tcl::namespace::eval punk::safe::system {
}
append INTERPCREATE \n $optlines
append INTERPCREATE \n {@values -max 0}
punk::args::definition $INTERPCREATE
punk::args::define $INTERPCREATE
set INTERPIC {
@ -786,7 +786,7 @@ tcl::namespace::eval punk::safe::system {
}
append INTERPIC \n $optlines
append INTERPIC \n {@values -max 0}
punk::args::definition $INTERPIC
punk::args::define $INTERPIC
####

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save