Browse Source

punk::ns use info cmdtype on 8.7+, major refactor of punk::repl and punk::args

master
Julian Noble 7 months ago
parent
commit
27ca9cf38d
  1. 1
      src/bootsupport/include_modules.config
  2. 6
      src/bootsupport/modules/README.md
  3. 1912
      src/bootsupport/modules/natsort-0.1.1.6.tm
  4. 108
      src/bootsupport/modules/punk/ansi-0.1.1.tm
  5. 983
      src/bootsupport/modules/punk/args-0.1.0.tm
  6. 25
      src/bootsupport/modules/punk/cap-0.1.0.tm
  7. 27
      src/bootsupport/modules/punk/cap/handlers/templates-0.1.0.tm
  8. 14
      src/bootsupport/modules/punk/char-0.1.0.tm
  9. 42
      src/bootsupport/modules/punk/console-0.1.1.tm
  10. 17
      src/bootsupport/modules/punk/du-0.1.0.tm
  11. 47
      src/bootsupport/modules/punk/fileline-0.1.0.tm
  12. 730
      src/bootsupport/modules/punk/lib-0.1.1.tm
  13. 2
      src/bootsupport/modules/punk/mix/base-0.1.tm
  14. 56
      src/bootsupport/modules/punk/mix/cli-0.3.tm
  15. 1
      src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm
  16. 4
      src/bootsupport/modules/punk/mix/commandset/module-0.1.0.tm
  17. 18
      src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm
  18. 50
      src/bootsupport/modules/punk/mix/commandset/scriptwrap-0.1.0.tm
  19. 200
      src/bootsupport/modules/punk/ns-0.1.0.tm
  20. 15
      src/bootsupport/modules/punk/path-0.1.0.tm
  21. 18
      src/bootsupport/modules/punk/repo-0.1.1.tm
  22. 2
      src/bootsupport/modules/punkcheck-0.1.0.tm
  23. 372
      src/bootsupport/modules/textblock-0.1.1.tm
  24. 318
      src/embedded/man/files/_module_argparsingtest-0.1.0.tm.n
  25. 354
      src/embedded/man/files/_module_overtype-1.6.3.tm.n
  26. 318
      src/embedded/man/files/punk/_module_aliascore-0.1.0.tm.n
  27. 25
      src/embedded/man/files/punk/_module_ansi-0.1.1.tm.n
  28. 156
      src/embedded/man/files/punk/_module_args-0.1.0.tm.n
  29. 490
      src/embedded/man/files/punk/_module_island-0.1.0.tm.n
  30. 31
      src/embedded/man/files/punk/_module_lib-0.1.1.tm.n
  31. 318
      src/embedded/man/files/punk/repl/_module_codethread-0.1.0.tm.n
  32. 30
      src/embedded/man/index.n
  33. 15
      src/embedded/man/toc.n
  34. 5
      src/embedded/md/.doc/tocdoc
  35. 2
      src/embedded/md/.idx
  36. 2
      src/embedded/md/.toc
  37. 2
      src/embedded/md/.xrf
  38. 87
      src/embedded/md/doc/files/_module_argparsingtest-0.1.0.tm.md
  39. 139
      src/embedded/md/doc/files/_module_overtype-1.6.3.tm.md
  40. 87
      src/embedded/md/doc/files/punk/_module_aliascore-0.1.0.tm.md
  41. 222
      src/embedded/md/doc/files/punk/_module_ansi-0.1.1.tm.md
  42. 177
      src/embedded/md/doc/files/punk/_module_args-0.1.0.tm.md
  43. 254
      src/embedded/md/doc/files/punk/_module_island-0.1.0.tm.md
  44. 33
      src/embedded/md/doc/files/punk/_module_lib-0.1.1.tm.md
  45. 87
      src/embedded/md/doc/files/punk/repl/_module_codethread-0.1.0.tm.md
  46. 10
      src/embedded/md/doc/toc.md
  47. 17
      src/embedded/md/index.md
  48. 10
      src/embedded/md/toc.md
  49. 5
      src/embedded/www/.doc/tocdoc
  50. 2
      src/embedded/www/.idx
  51. 2
      src/embedded/www/.toc
  52. 2
      src/embedded/www/.xrf
  53. 187
      src/embedded/www/doc/files/_module_argparsingtest-0.1.0.tm.html
  54. 191
      src/embedded/www/doc/files/_module_overtype-1.6.3.tm.html
  55. 187
      src/embedded/www/doc/files/punk/_module_aliascore-0.1.0.tm.html
  56. 210
      src/embedded/www/doc/files/punk/_module_ansi-0.1.1.tm.html
  57. 115
      src/embedded/www/doc/files/punk/_module_args-0.1.0.tm.html
  58. 304
      src/embedded/www/doc/files/punk/_module_island-0.1.0.tm.html
  59. 17
      src/embedded/www/doc/files/punk/_module_lib-0.1.1.tm.html
  60. 187
      src/embedded/www/doc/files/punk/repl/_module_codethread-0.1.0.tm.html
  61. 48
      src/embedded/www/doc/toc.html
  62. 46
      src/embedded/www/index.html
  63. 48
      src/embedded/www/toc.html
  64. 468
      src/modules/argparsingtest-999999.0a1.0.tm
  65. 3
      src/modules/argparsingtest-buildversion.txt
  66. 42
      src/modules/flagfilter-0.3.tm
  67. 1912
      src/modules/natsort-0.1.1.6.tm
  68. 519
      src/modules/punk-0.1.tm
  69. 221
      src/modules/punk/aliascore-999999.0a1.0.tm
  70. 3
      src/modules/punk/aliascore-buildversion.txt
  71. 108
      src/modules/punk/ansi-999999.0a1.0.tm
  72. 983
      src/modules/punk/args-999999.0a1.0.tm
  73. 5
      src/modules/punk/basictelnet-999999.0a1.0.tm
  74. 25
      src/modules/punk/cap-999999.0a1.0.tm
  75. 27
      src/modules/punk/cap/handlers/templates-999999.0a1.0.tm
  76. 14
      src/modules/punk/char-999999.0a1.0.tm
  77. 9
      src/modules/punk/config-0.1.tm
  78. 42
      src/modules/punk/console-999999.0a1.0.tm
  79. 17
      src/modules/punk/du-999999.0a1.0.tm
  80. 47
      src/modules/punk/fileline-999999.0a1.0.tm
  81. 561
      src/modules/punk/island-999999.0a1.0.tm
  82. 3
      src/modules/punk/island-buildversion.txt
  83. 730
      src/modules/punk/lib-999999.0a1.0.tm
  84. 17
      src/modules/punk/mix-0.1.tm
  85. 2
      src/modules/punk/mix/base-0.1.tm
  86. 56
      src/modules/punk/mix/cli-0.3.tm
  87. 1
      src/modules/punk/mix/commandset/doc-999999.0a1.0.tm
  88. 4
      src/modules/punk/mix/commandset/module-999999.0a1.0.tm
  89. 18
      src/modules/punk/mix/commandset/project-999999.0a1.0.tm
  90. 50
      src/modules/punk/mix/commandset/scriptwrap-999999.0a1.0.tm
  91. 4
      src/modules/punk/mix/templates/modules/template_module-0.0.1.tm
  92. 200
      src/modules/punk/ns-999999.0a1.0.tm
  93. 15
      src/modules/punk/path-999999.0a1.0.tm
  94. 1348
      src/modules/punk/repl-0.1.tm
  95. 255
      src/modules/punk/repl/codethread-999999.0a1.0.tm
  96. 3
      src/modules/punk/repl/codethread-buildversion.txt
  97. 18
      src/modules/punk/repo-999999.0a1.0.tm
  98. 2
      src/modules/punk/sshrun-999999.0a1.0.tm
  99. 2
      src/modules/punk/uc-999999.0a1.0.tm
  100. 6
      src/modules/punk/unixywindows-999999.0a1.0.tm
  101. Some files were not shown because too many files have changed in this diff Show More

1
src/bootsupport/include_modules.config

@ -19,6 +19,7 @@ set bootsupport_modules [list\
src/vendormodules md5\ src/vendormodules md5\
src/vendormodules sha1\ src/vendormodules sha1\
modules punkcheck\ modules punkcheck\
modules natsort\
modules punk::ansi\ modules punk::ansi\
modules punk::assertion\ modules punk::assertion\
modules punk::args\ modules punk::args\

6
src/bootsupport/modules/README.md

@ -6,12 +6,12 @@ The .tm modules here may be required for your build script if it intended the in
The modules here are loaded by your initialisation scripts and so can be a snapshot of different versions than those in your project src. The modules here are loaded by your initialisation scripts and so can be a snapshot of different versions than those in your project src.
The modules can be your own, or 3rd party such as individual items from tcllib. The modules can be your own, or 3rd party such as individual items from tcllib.
You can copy modules from a running punk shell to this location using the pmix command. You can copy modules from a running punk shell to this location using the dev command.
e.g e.g
>pmix visible_lib_copy_to_modulefolder some::module::lib bootsupport dev lib.copyasmodule some::module::lib bootsupport
The pmix command will help you pick the latest version, and will create any necessary file structure matching the namespace of the package. The dev command will help you pick the latest version, and will create any necessary file structure matching the namespace of the package.
e.g the result might be a file such as e.g the result might be a file such as
<projectname>/src/bootsupport/some/module/lib-0.1.tm <projectname>/src/bootsupport/some/module/lib-0.1.tm

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

File diff suppressed because it is too large Load Diff

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

@ -141,19 +141,20 @@ namespace eval punk::ansi::class {
if {[llength $arglist] %2 != 0} { if {[llength $arglist] %2 != 0} {
puts stderr "render_to_input_line usage: ?-dimensions WxH? ?-minus charcount? x" puts stderr "render_to_input_line usage: ?-dimensions WxH? ?-minus charcount? x"
} }
set defaults [dict create\ set opts [dict create\
-dimensions 80x24\ -dimensions 80x24\
-minus 0\ -minus 0\
] ]
dict for {k v} $arglist { dict for {k v} $arglist {
switch -- $k { switch -- $k {
-dimensions - -minus { } -dimensions - -minus {
dict set opts $k $v
}
default { default {
puts stderr "render_to_input_line unexpected argument '$k' usage: ?-dimensions WxH? ?-minus charcount? x" puts stderr "render_to_input_line unexpected argument '$k' usage: ?-dimensions WxH? ?-minus charcount? x"
} }
} }
} }
set opts [dict merge $defaults $arglist]
set opt_dimensions [dict get $opts -dimensions] set opt_dimensions [dict get $opts -dimensions]
set opt_minus [dict get $opts -minus] set opt_minus [dict get $opts -minus]
lassign [split $opt_dimensions x] w h lassign [split $opt_dimensions x] w h
@ -221,15 +222,17 @@ namespace eval punk::ansi::class {
-vt 0\ -vt 0\
-width "auto"\ -width "auto"\
] ]
set opts $defaults
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-lf - -vt - -width {} -lf - -vt - -width {
dict set opts $k $v
}
default { default {
error "viewcodes unrecognised option '$k'. Known options [dict keys $defaults]" error "viewcodes unrecognised option '$k'. Known options [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opts_lf [dict get $opts -lf] set opts_lf [dict get $opts -lf]
set opts_vt [dict get $opts -vt] set opts_vt [dict get $opts -vt]
set opts_width [dict get $opts -width] set opts_width [dict get $opts -width]
@ -249,15 +252,17 @@ namespace eval punk::ansi::class {
set defaults [list\ set defaults [list\
-width "auto"\ -width "auto"\
] ]
set opts $defaults
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-width {} -width {
dict set opts $k $v
}
default { default {
error "viewchars unrecognised option '$k'. Known options [dict keys $defaults]" error "viewchars unrecognised option '$k'. Known options [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opts_width [dict get $opts -width] set opts_width [dict get $opts -width]
if {$opts_width eq ""} { if {$opts_width eq ""} {
return [punk::ansi::stripansiraw [$o_ansistringobj get]] return [punk::ansi::stripansiraw [$o_ansistringobj get]]
@ -275,15 +280,17 @@ namespace eval punk::ansi::class {
set defaults [list\ set defaults [list\
-width "auto"\ -width "auto"\
] ]
set opts $defaults
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-width {} -width {
dict set opts $k $v
}
default { default {
error "viewstyle unrecognised option '$k'. Known options [dict keys $defaults]" error "viewstyle unrecognised option '$k'. Known options [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opts_width [dict get $opts -width] set opts_width [dict get $opts -width]
if {$opts_width eq ""} { if {$opts_width eq ""} {
return [ansistring VIEWSTYLE [$o_ansistringobj get]] return [ansistring VIEWSTYLE [$o_ansistringobj get]]
@ -1423,16 +1430,17 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
} }
proc colourmap1 {args} { proc colourmap1 {args} {
set defaults {-bg Web-white -forcecolour 0} set opts {-bg Web-white -forcecolour 0}
dict for {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-bg - -forcecolour {} -bg - -forcecolour {
dict set opts $k $v
}
default { default {
error "colourmap1 unrecognised option $k. Known-options: [dict keys $defaults] error "colourmap1 unrecognised option $k. Known-options: [dict keys $opts]
} }
} }
} }
set opts [dict merge $defaults $args]
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc "forcecolour" set fc "forcecolour"
} else { } else {
@ -1815,16 +1823,17 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
# $WEB_colour_map_gray\ # $WEB_colour_map_gray\
#] #]
proc colourtable_web {args} { proc colourtable_web {args} {
set defaults {-forcecolour 0 -groups *} set opts {-forcecolour 0 -groups *}
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-groups - -forcecolour {} -groups - -forcecolour {
dict set opts $k $v
}
default { default {
error "colourtable_web unrecognised option '$k'. Known-options: [dict keys $defaults]" error "colourtable_web unrecognised option '$k'. Known-options: [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set fc "" set fc ""
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc "forcecolour" set fc "forcecolour"
@ -1894,19 +1903,20 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
proc colourtable_x11diff {args} { proc colourtable_x11diff {args} {
variable X11_colour_map_diff variable X11_colour_map_diff
variable WEB_colour_map variable WEB_colour_map
set defaults [dict create\ set opts [dict create\
-forcecolour 0\ -forcecolour 0\
-return "string"\ -return "string"\
] ]
dict for {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-return - -forcecolour {} -return - -forcecolour {
dict set opts $k $v
}
default { default {
error "colourtable_x11diff unrecognised option '$k'. Known options [dict keys $defaults]" error "colourtable_x11diff unrecognised option '$k'. Known options [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set fc "" set fc ""
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc "forcecolour" set fc "forcecolour"
@ -3698,20 +3708,21 @@ namespace eval punk::ansi {
variable codestate_empty variable codestate_empty
set othercodes [list] set othercodes [list]
set defaults [dict create\ set opts [dict create\
-filter_fg 0\ -filter_fg 0\
-filter_bg 0\ -filter_bg 0\
-filter_reset 0\ -filter_reset 0\
] ]
dict for {k v} $args { dict for {k v} $args {
switch -- $k { switch -- $k {
-filter_fg - -filter_bg - -filter_reset {} -filter_fg - -filter_bg - -filter_reset {
dict set opts $k $v
}
default { default {
error "sgr_merge unknown option '$k'. Known options [dict keys $defaults]" error "sgr_merge unknown option '$k'. Known options [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set codestate $codestate_empty set codestate $codestate_empty
set codestate_initial $codestate_empty ;#keep a copy for resets. set codestate_initial $codestate_empty ;#keep a copy for resets.
@ -4331,6 +4342,39 @@ namespace eval punk::ansi::ta {
} }
return [lappend list [string range $text $start end]] return [lappend list [string range $text $start end]]
} }
#experiment for coroutine generator
proc _perlish_split_yield {re text} {
if {[string length $text] == 0} {
yield {}
}
set list [list]
set start 0
#We can get $matchEnd < $matchStart; we need to ensure there is an exit condition for non-greedy empty results REVIEW
while {[regexp -start $start -indices -- $re $text match]} {
lassign $match matchStart matchEnd
#puts "->start $start ->match $matchStart $matchEnd"
if {$matchEnd < $matchStart} {
yield [string range $text $start $matchStart-1]
yield [string index $text $matchStart]
incr start
if {$start >= [string length $text]} {
break
}
continue
}
yield [string range $text $start $matchStart-1]
yield [string range $text $matchStart $matchEnd]
set start [expr {$matchEnd+1}]
#?
if {$start >= [string length $text]} {
break
}
}
#return [lappend list [string range $text $start end]]
yield [string range $text $start end]
}
proc _perlish_split2 {re text} { proc _perlish_split2 {re text} {
if {[string length $text] == 0} { if {[string length $text] == 0} {
return {} return {}
@ -4399,7 +4443,7 @@ namespace eval punk::ansi::class {
error {usage: ?-width <int>? ?-wrap [1|0]? ?-overflow [1|0]? from_ansistring to_ansistring} error {usage: ?-width <int>? ?-wrap [1|0]? ?-overflow [1|0]? from_ansistring to_ansistring}
} }
lassign [lrange $args end-1 end] from_ansistring to_ansistring lassign [lrange $args end-1 end] from_ansistring to_ansistring
set defaults [dict create\ set opts [dict create\
-width \uFFEF\ -width \uFFEF\
-wrap 1\ -wrap 1\
-overflow 0\ -overflow 0\
@ -4411,17 +4455,17 @@ namespace eval punk::ansi::class {
] ]
puts "[info object class [self]] renderer [self] constructor from ansistring $from_ansistring to ansistring $to_ansistring" puts "[info object class [self]] renderer [self] constructor from ansistring $from_ansistring to ansistring $to_ansistring"
set argsflags [lrange $args 0 end-2] set argsflags [lrange $args 0 end-2]
dict for {k v} $argsflags { foreach {k v} $argsflags {
switch -- $k { switch -- $k {
-width - -wrap - -overflow - -appendlines - -looplimit - -experimental {} -width - -wrap - -overflow - -appendlines - -looplimit - -experimental {
dict set opts $k $v
}
default { default {
set known_opts [dict keys $defaults]
#don't use [self class] - or we'll get the superclass #don't use [self class] - or we'll get the superclass
error "[info object class [self]] unknown option '$k'. Known options: $known_opts" error "[info object class [self]] unknown option '$k'. Known options: [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $argsflags]
set o_width [dict get $opts -width] set o_width [dict get $opts -width]
set o_wrap [dict get $opts -wrap] set o_wrap [dict get $opts -wrap]
set o_overflow [dict get $opts -overflow] set o_overflow [dict get $opts -overflow]

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

File diff suppressed because it is too large Load Diff

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

@ -350,15 +350,19 @@ namespace eval punk::cap {
variable pkgcapsdeclared variable pkgcapsdeclared
variable pkgcapsaccepted variable pkgcapsaccepted
variable caps variable caps
set defaults [dict create\ set opts [dict create\
-nowarnings false -nowarnings false
] ]
dict for {k v} $args { foreach {k v} $args {
if {$k ni $defaults} { switch -- $k {
error "Unrecognized option $k. Known options [dict keys $defaults]" -nowarnings {
dict set opts $k $v
}
default {
error "Unrecognized option $k. Known options [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
set warnings [expr {! [dict get $opts -nowarnings]}] set warnings [expr {! [dict get $opts -nowarnings]}]
if {[string match ::* $pkg]} { if {[string match ::* $pkg]} {
@ -433,13 +437,14 @@ namespace eval punk::cap {
#another call to register_pkg with same pkg may have been made (most likely with different capname) so we must append - but check not already present #another call to register_pkg with same pkg may have been made (most likely with different capname) so we must append - but check not already present
#dict lappend pkgcapsdeclared $pkg $capabilitylist #dict lappend pkgcapsdeclared $pkg $capabilitylist
if {[dict exists $pkgcapsdeclared $pkg]} { if {[dict exists $pkgcapsdeclared $pkg]} {
set capspecs [dict get $pkgcapsdeclared $pkg] #review - untested
foreach spec $capspecs { set mergecapspecs [dict get $pkgcapsdeclared $pkg]
if {$spec ni $capspecs} { foreach spec $capabilitylist {
lappend capspecs $spec if {$spec ni $mergecapspecs} {
lappend mergecapspecs $spec
} }
} }
dict set pkgcapsdeclared $pkg $capspecs dict set pkgcapsdeclared $pkg $mergecapspecs
} else { } else {
dict set pkgcapsdeclared $pkg $capabilitylist dict set pkgcapsdeclared $pkg $capabilitylist
} }

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

@ -242,9 +242,12 @@ namespace eval punk::cap::handlers::templates {
set capabilityname $capname set capabilityname $capname
} }
method folders {args} { method folders {args} {
lassign [punk::args::opts_values { set argd [punk::args::get_dict {
-startdir -default "" -startdir -default ""
} $args -maxvalues 0] _o opts *values -max 0
} $args]
set opts [dict get $argd opts]
set opt_startdir [dict get $opts -startdir] set opt_startdir [dict get $opts -startdir]
if {$opt_startdir eq ""} { if {$opt_startdir eq ""} {
set startdir [pwd] set startdir [pwd]
@ -456,11 +459,14 @@ namespace eval punk::cap::handlers::templates {
return $folderdict return $folderdict
} }
method get_itemdict_projectlayouts {args} { method get_itemdict_projectlayouts {args} {
lassign [punk::args::opts_values { set argd [punk::args::get_dict {
-startdir -default "" *opts -anyopts 1
#peek -startdir while allowing all other opts/vals to be verified down-the-line instead of here #peek -startdir while allowing all other opts/vals to be verified down-the-line instead of here
} $args -maxvalues -1 -anyopts 1] _o opts _v values -startdir -default ""
set opt_startdir [dict get $opts -startdir] *values -maxvalues -1
} $args]
set opt_startdir [dict get $argd opts -startdir]
if {$opt_startdir eq ""} { if {$opt_startdir eq ""} {
set searchbase [pwd] set searchbase [pwd]
} else { } else {
@ -628,15 +634,18 @@ namespace eval punk::cap::handlers::templates {
#and a file selection mechanism command -command_get_items_from_base #and a file selection mechanism command -command_get_items_from_base
#and a name determining command -command_get_item_name #and a name determining command -command_get_item_name
method _get_itemdict {args} { method _get_itemdict {args} {
lassign [punk::args::opts_values { set argd [punk::args::get_dict {
*opts -anyopts 0
-startdir -default "" -startdir -default ""
-templatefolder_subdir -optional 0 -templatefolder_subdir -optional 0
-command_get_items_from_base -optional 0 -command_get_items_from_base -optional 0
-command_get_item_name -optional 0 -command_get_item_name -optional 0
-not -default "" -multiple 1 -not -default "" -multiple 1
*values -maxvalues -1
globsearches -default * -multiple 1 globsearches -default * -multiple 1
} $args -maxvalues -1] _o opts _v values } $args]
set globsearches [dict get $values globsearches]; #note that in this case our globsearch won't reduce the machine's effort in scannning the filesystem - as we need to search on the renamed results set opts [dict get $argd opts]
set globsearches [dict get $argd values globsearches]; #note that in this case our globsearch won't reduce the machine's effort in scannning the filesystem - as we need to search on the renamed results
# -- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- ---
set opt_startdir [dict get $opts -startdir] set opt_startdir [dict get $opts -startdir]
set opt_templatefolder_subdir [dict get $opts -templatefolder_subdir] set opt_templatefolder_subdir [dict get $opts -templatefolder_subdir]

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

@ -1205,22 +1205,25 @@ namespace eval punk::char {
} }
proc char_info_dec {dec args} { proc char_info_dec {dec args} {
set dec_char [expr {$dec}] set dec_char [expr {$dec}]
set defaults [dict create\ set opts [dict create\
-fields {default}\ -fields {default}\
-except {}\ -except {}\
] ]
set known_opts [dict keys $defaults]
#testwidth is so named because it peforms an actual test on the console using ansi escapes - and the name gives a hint that it is a little slow #testwidth is so named because it peforms an actual test on the console using ansi escapes - and the name gives a hint that it is a little slow
set known_fields [list all default dec hex desc short testwidth char memberof] ;#maint fields from charinfo 'desc' 'short' set known_fields [list all default dec hex desc short testwidth char memberof] ;#maint fields from charinfo 'desc' 'short'
#todo - unicode properties #todo - unicode properties
# tclwhitespace (different to unicode concept of whitespace. review ) # tclwhitespace (different to unicode concept of whitespace. review )
foreach {k v} $args { foreach {k v} $args {
if {![dict exists $defaults $k]} { switch -- $k {
error "char_info unrecognised option '$k'. Known options:'$known_opts' known_fields: $known_fields usage: char_info <char> ?-fields {<fieldnames>}? ?-except {<fieldnames>}?" -fields - -except {
dict set opts $k $v
}
default {
error "char_info unrecognised option '$k'. Known options:'[dict keys $opts]' known_fields: $known_fields usage: char_info <char> ?-fields {<fieldnames>}? ?-except {<fieldnames>}?"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- ---
set opt_fields [dict get $opts -fields] set opt_fields [dict get $opts -fields]
set opt_except [dict get $opts -except] set opt_except [dict get $opts -except]
@ -1569,6 +1572,7 @@ namespace eval punk::char {
if {$name_or_glob eq "*"} { if {$name_or_glob eq "*"} {
return [lsort [dict keys $charsets]] return [lsort [dict keys $charsets]]
} }
#dict keys $dict <pattern> doesn't have option for case insensitive searches
return [lsort [lsearch -all -inline -nocase [dict keys $charsets] $name_or_glob]] return [lsort [lsearch -all -inline -nocase [dict keys $charsets] $name_or_glob]]
} }
} }

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

@ -671,7 +671,7 @@ namespace eval punk::console {
} else { } else {
#! todo? for now, emit a clue as to what's happening. #! todo? for now, emit a clue as to what's happening.
puts stderr "[punk::ansi::a+ yellow bold]-->punk::console::get_ansi_response_payload cannot trigger existing handler $existing_handler while over-read data is in punk::console::input_chunks_waiting($input) instead of channel [ansistring VIEW $input_chunks_waiting($input)][punk::ansi::a]" puts stderr "[punk::ansi::a+ yellow bold]-->punk::console::get_ansi_response_payload cannot trigger existing handler $existing_handler while over-read data is in punk::console::input_chunks_waiting($input) instead of channel [ansistring VIEW $input_chunks_waiting($input)][punk::ansi::a]"
if {$::repl::running} { if {[package provide punk::repl::codethread] ne "" && [punk::repl::codethread::is_running]} {
if {[eof $input]} { if {[eof $input]} {
puts stdout "restarting repl" puts stdout "restarting repl"
repl::reopen_stdin repl::reopen_stdin
@ -682,7 +682,7 @@ namespace eval punk::console {
#Note - we still may be in_repl_handler here (which disables its own reader while executing commandlines) #Note - we still may be in_repl_handler here (which disables its own reader while executing commandlines)
#The input_chunks_waiting may really belong to the existing_handler we found - but if it doesn't consume them they will end up being read by the repl_handler when it eventually re-enables. #The input_chunks_waiting may really belong to the existing_handler we found - but if it doesn't consume them they will end up being read by the repl_handler when it eventually re-enables.
#todo - some better structure than just a list of waiting chunks indexed by input channel, so repl/other handlers can determine the context in which these waiting chunks were generated? #todo - some better structure than just a list of waiting chunks indexed by input channel, so repl/other handlers can determine the context in which these waiting chunks were generated?
} elseif {$::repl::running} { } elseif {[package provide punk::repl::codethread] ne "" && [punk::repl::codethread::is_running]} {
if {[llength $input_chunks_waiting($input)]} { if {[llength $input_chunks_waiting($input)]} {
#don't trigger the repl handler manually - we will inevitably get things out of order - as it knows when to enable/disable itself based on whether chunks are waiting. #don't trigger the repl handler manually - we will inevitably get things out of order - as it knows when to enable/disable itself based on whether chunks are waiting.
#triggering it by putting it on the eventloop will potentially result in re-entrancy #triggering it by putting it on the eventloop will potentially result in re-entrancy
@ -1030,10 +1030,29 @@ namespace eval punk::console {
#todo - determine cursor on/off state before the call to restore properly. May only be possible #todo - determine cursor on/off state before the call to restore properly. May only be possible
proc get_size {{inoutchannels {stdin stdout}}} { proc get_size {{inoutchannels {stdin stdout}}} {
lassign $inoutchannels in out lassign $inoutchannels in out
#we can't reliably use [chan names] for stdin,stdout. There could be stacked channels and they may have a names such as file22fb27fe810
#chan eof is faster whether chan exists or not than
if {[catch {chan eof $in} is_eof]} {
error "punk::console::get_size input channel $in seems to be closed ([info level 1])"
} else {
if {$is_eof} {
error "punk::console::get_size eof on input channel $in ([info level 1])"
}
}
if {[catch {chan eof $out} is_eof]} {
error "punk::console::get_size output channel $out seems to be closed ([info level 1])"
} else {
if {$is_eof} {
error "punk::console::get_size eof on output channel $out ([info level 1])"
}
}
#keep out of catch - no point in even trying a restore move if we can't get start position - just fail here.
lassign [get_cursor_pos_list $inoutchannels] start_row start_col
if {[catch { if {[catch {
#some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that.
#This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere.
lassign [get_cursor_pos_list $inoutchannels] start_row start_col
puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::move 2000 2000] puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::move 2000 2000]
lassign [get_cursor_pos_list $inoutchannels] lines cols lassign [get_cursor_pos_list $inoutchannels] lines cols
puts -nonewline $out [punk::ansi::move $start_row $start_col][punk::console::cursor_on];flush stdout puts -nonewline $out [punk::ansi::move $start_row $start_col][punk::console::cursor_on];flush stdout
@ -1251,7 +1270,7 @@ namespace eval punk::console {
return [exec {*}$cmd1] return [exec {*}$cmd1]
} else { } else {
puts stderr "infocmp doesn't seem to be present" puts stderr "infocmp doesn't seem to be present"
if {$::tcl_platform(os) eq "FreeBSD"} { if {$::tcl_platform(platform) eq "FreeBSD"} {
puts stderr "For FreeBSD - install ncurses to get infocmp and related binaries and also install terminfo-db" puts stderr "For FreeBSD - install ncurses to get infocmp and related binaries and also install terminfo-db"
} }
set tcmd [auto_execok tput] set tcmd [auto_execok tput]
@ -1395,6 +1414,9 @@ namespace eval punk::console {
namespace import ansi::insert_lines namespace import ansi::insert_lines
namespace import ansi::delete_lines namespace import ansi::delete_lines
interp alias {} smcup {} ::punk::console::enable_alt_screen
interp alias {} rmcup {} ::punk::console::disable_alt_screen
#experimental #experimental
proc rhs_prompt {col text} { proc rhs_prompt {col text} {
package require textblock package require textblock
@ -1784,11 +1806,13 @@ namespace eval punk::console {
interp alias {} colour {} punk::console::colour
interp alias {} ansi {} punk::console::ansi
interp alias {} color {} punk::console::colour
interp alias {} a+ {} punk::console::code_a+
interp alias {} a= {} punk::console::code_a
interp alias {} a {} punk::console::code_a
interp alias {} a? {} punk::console::code_a?

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

@ -25,8 +25,10 @@ namespace eval punk::du {
variable has_twapi 0 variable has_twapi 0
} }
if {"windows" eq $::tcl_platform(platform)} { if {"windows" eq $::tcl_platform(platform)} {
if {![interp issafe]} {
package require zzzload package require zzzload
zzzload::pkg_require twapi zzzload::pkg_require twapi
}
if {[catch {package require twapi}]} { if {[catch {package require twapi}]} {
puts stderr "Warning: punk::du - unable to load twapi. Disk operations may be much slower on windows without the twapi package" puts stderr "Warning: punk::du - unable to load twapi. Disk operations may be much slower on windows without the twapi package"
@ -818,19 +820,22 @@ namespace eval punk::du {
#this is the cross-platform pure-tcl version - which calls glob multiple times to make sure it gets everythign it needs and can ignore everything it needs to. #this is the cross-platform pure-tcl version - which calls glob multiple times to make sure it gets everythign it needs and can ignore everything it needs to.
#These repeated calls to glob will be a killer for performance - especially on a network share or when walking a large directory structure #These repeated calls to glob will be a killer for performance - especially on a network share or when walking a large directory structure
proc du_dirlisting_generic {folderpath args} { proc du_dirlisting_generic {folderpath args} {
set defaults [dict create\ set opts [dict create\
-glob *\ -glob *\
-with_sizes 0\ -with_sizes 0\
-with_times 0\ -with_times 0\
] ]
set errors [dict create] set errors [dict create]
set known_opts [dict keys $defaults] foreach {k v} $args {
dict for {k -} $args { switch -- $k {
if {$k ni $known_opts} { -glob - -with_sizes - -with_times {
error "du_dirlisting_generic unknown-option $k" dict set opts $k $v
}
default {
error "du_dirlisting_generic unknown-option '$k'. Known-options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_glob [dict get $opts -glob] set opt_glob [dict get $opts -glob]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---

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

@ -1,4 +1,4 @@
# -*- tcl -*- # -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt # Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
# #
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. # Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem.
@ -275,7 +275,7 @@ namespace eval punk::fileline::class {
#[call class::textinfo [method chunk_boundary_display]] #[call class::textinfo [method chunk_boundary_display]]
#[para]Returns a string displaying the boundaries at chunksize bytes between chunkstart and chunkend #[para]Returns a string displaying the boundaries at chunksize bytes between chunkstart and chunkend
#[para]Defaults to using ansi colour if punk::ansi module is available. Use -ansi 0 to disable colour #[para]Defaults to using ansi colour if punk::ansi module is available. Use -ansi 0 to disable colour
set defaults [dict create\ set opts [dict create\
-ansi $::punk::fileline::ansi::enabled\ -ansi $::punk::fileline::ansi::enabled\
-offset 0\ -offset 0\
-displaybytes 200\ -displaybytes 200\
@ -292,11 +292,15 @@ namespace eval punk::fileline::class {
] ]
set known_opts [dict keys $defaults] set known_opts [dict keys $defaults]
foreach {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
error "[self]::chunk_boundary error: unknown option '$k'. Known options: $known_opts" -ansi - -offset - -displaybytes - -truncatedmark - -completemark - -moremark - -continuemark - -linemaxwidth - -linebase - -limit - -boundaries - -showconfig - -boundaryheader {
dict set opts $k $v
}
default {
error "[self]::chunk_boundary error: unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_ansi [dict get $opts -ansi] set opt_ansi [dict get $opts -ansi]
set opt_offset [dict get $opts -offset] set opt_offset [dict get $opts -offset]
@ -612,20 +616,23 @@ namespace eval punk::fileline::class {
#[para]This is true even if only a single square bracket is being searched for. e.g {*[lb]file*} will not find the word file followed by a left square-bracket - even though the search didn't close the square brackets. #[para]This is true even if only a single square bracket is being searched for. e.g {*[lb]file*} will not find the word file followed by a left square-bracket - even though the search didn't close the square brackets.
#[para]In the above case - the literal search should be {*\[lb]file*} #[para]In the above case - the literal search should be {*\[lb]file*}
set defaults [dict create\ set opts [dict create\
-limit 0\ -limit 0\
-strategy 1\ -strategy 1\
-start 0\ -start 0\
-end end\ -end end\
-limitfrom start\ -limitfrom start\
] ]
set known_opts [dict keys $defaults] foreach {k v} $args {
dict for {k v} $args { switch -- $k {
if {$k ni $known_opts} { -limit - -strategy - -start - -end - -limitfrom {
error "linepayload_find_glob unknown option '$k'. Known options: $known_opts" dict set opts $k $v
}
default {
error "linepayload_find_glob unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_limit [dict get $opts -limit] set opt_limit [dict get $opts -limit]
if {![string is integer -strict $opt_limit] || $opt_limit < 0} { if {![string is integer -strict $opt_limit] || $opt_limit < 0} {
@ -1261,13 +1268,14 @@ namespace eval punk::fileline {
#[para]Currently only utf-8, utf-16* and utf-32* are properly supported even though the other BOMs are detected, reported via get_bomid, and stripped from the data. #[para]Currently only utf-8, utf-16* and utf-32* are properly supported even though the other BOMs are detected, reported via get_bomid, and stripped from the data.
#[para]GB18030 falls back to cp936/gbk (unless a gb18030 encoding has been installed). Use -encoding binary if this isn't suitable and you need to do your own processing of the raw data. #[para]GB18030 falls back to cp936/gbk (unless a gb18030 encoding has been installed). Use -encoding binary if this isn't suitable and you need to do your own processing of the raw data.
set defaults { set argument_specification {
-file -default {} -type existingfile -file -default {} -type existingfile
-translation -default binary -translation -default binary
-encoding -default "\uFFFF" -encoding -default "\uFFFF"
-includebom -default 0 -includebom -default 0
*values -min 0 -max 1
} }
lassign [dict values [punk::args::opts_values $defaults $args -minvalues 0 -maxvalues 1]] opts values lassign [dict values [punk::args::get_dict $argument_specification $args]] opts values
# -- --- --- --- # -- --- --- ---
set opt_file [dict get $opts -file] set opt_file [dict get $opts -file]
set opt_translation [dict get $opts -translation] set opt_translation [dict get $opts -translation]
@ -1591,16 +1599,19 @@ namespace eval punk::fileline::system {
#much faster when resultant boundary size is large (at least when offset 0) #much faster when resultant boundary size is large (at least when offset 0)
proc _range_spans_chunk_boundaries_lseq {start end chunksize args} { proc _range_spans_chunk_boundaries_lseq {start end chunksize args} {
if {$chunksize < 1} {error "chunksize must be > 0"} ;#sanitycheck in case called directly if {$chunksize < 1} {error "chunksize must be > 0"} ;#sanitycheck in case called directly
set defaults [dict create\ set opts [dict create\
-offset 0\ -offset 0\
] ]
set known_opts [dict keys $defaults]
foreach {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
error "unknown option '$k'. Known options: $known_opts" -offset {
dict set opts $k $v
}
default {
error "unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- # -- --- --- ---
set opt_offset [dict get $opts -offset] set opt_offset [dict get $opts -offset]
# -- --- --- --- # -- --- --- ---

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

@ -96,6 +96,57 @@ namespace eval punk::lib::class {
} }
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::lib::ensemble {
#wiki.tcl-lang.org/page/ensemble+extend
# extend an ensemble-like routine with the routines in some namespace
proc extend {routine extension} {
if {![string match ::* $routine]} {
set resolved [uplevel 1 [list ::namespace which $routine]]
if {$resolved eq {}} {
error [list {no such routine} $routine]
}
set routine $resolved
}
set routinens [namespace qualifiers $routine]
if {$routinens eq {::}} {
set routinens {}
}
set routinetail [namespace tail $routine]
if {![string match ::* $extension]} {
set extension [uplevel 1 [
list [namespace which namespace] current]]::$extension
}
if {![namespace exists $extension]} {
error [list {no such namespace} $extension]
}
set extension [namespace eval $extension [
list [namespace which namespace] current]]
namespace eval $extension [
list [namespace which namespace] export *]
while 1 {
set renamed ${routinens}::${routinetail}_[info cmdcount]
if {[namespace which $renamed] eq {}} break
}
rename $routine $renamed
namespace eval $extension [
list namespace ensemble create -command $routine -unknown [
list apply {{renamed ensemble routine args} {
list $renamed $routine
}} $renamed
]
]
return $routine
}
}
namespace eval punk::lib::compat { namespace eval punk::lib::compat {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::lib::compat}] #[subsection {Namespace punk::lib::compat}]
@ -228,6 +279,46 @@ namespace eval punk::lib::compat {
return $result return $result
} }
#tcl8.7/9 compatibility for 8.6
if {[info commands ::tcl::string::insert] eq ""} {
#https://wiki.tcl-lang.org/page/string+insert
# Pure Tcl implementation of [string insert] command.
proc ::tcl::string::insert {string index insertString} {
# Convert end-relative and TIP 176 indexes to simple integers.
if {[regexp -expanded {
^(end(?![\t\n\v\f\r ]) # "end" is never followed by whitespace
|[\t\n\v\f\r ]*[+-]?\d+) # m, with optional leading whitespace
(?:([+-]) # op, omitted when index is "end"
([+-]?\d+))? # n, omitted when index is "end"
[\t\n\v\f\r ]*$ # optional whitespace (unless "end")
} $index _ m op n]} {
# Convert first index to an integer.
switch $m {
end {set index [string length $string]}
default {scan $m %d index}
}
# Add or subtract second index, if provided.
switch $op {
+ {set index [expr {$index + $n}]}
- {set index [expr {$index - $n}]}
}
} elseif {![string is integer -strict $index]} {
# Reject invalid indexes.
return -code error "bad index \"$index\": must be\
integer?\[+-\]integer? or end?\[+-\]integer?"
}
# Concatenate the pre-insert, insertion, and post-insert strings.
string cat [string range $string 0 [expr {$index - 1}]] $insertString\
[string range $string $index end]
}
# Bind [string insert] to [::tcl::string::insert].
namespace ensemble configure string -map [dict replace\
[namespace ensemble configure string -map]\
insert ::tcl::string::insert]
}
#*** !doctools #*** !doctools
#[list_end] [comment {--- end definitions namespace punk::lib::compat ---}] #[list_end] [comment {--- end definitions namespace punk::lib::compat ---}]
} }
@ -244,6 +335,28 @@ namespace eval punk::lib {
#[para] Core API functions for punk::lib #[para] Core API functions for punk::lib
#[list_begin definitions] #[list_begin definitions]
proc range {from to args} {
if {[info commands lseq] ne ""} {
#tcl 8.7+ lseq significantly faster for larger ranges
return [lseq $from $to]
}
set count [expr {($to -$from) + 1}]
incr from -1
return [lmap v [lrepeat $count 0] {incr from}]
}
proc is_list_all_in_list {small large} {
package require struct::list
package require struct::set
set small_in_large [lsort [struct::set intersect [lsort -unique $small] $large ]]
return [struct::list equal [lsort $small] $small_in_large]
}
proc is_list_all_ni_list {a b} {
package require struct::set
set i [struct::set intersect $a $b]
return [expr {[llength $i] == 0}]
}
#The closure-like behaviour is *very* slow especially when called from a context such as the global namespace with lots of vars and large arrays such as ::env #The closure-like behaviour is *very* slow especially when called from a context such as the global namespace with lots of vars and large arrays such as ::env
proc lmapflat_closure {varnames list script} { proc lmapflat_closure {varnames list script} {
set result [list] set result [list]
@ -548,16 +661,14 @@ namespace eval punk::lib {
if {[llength $argopts]%2 !=0} { if {[llength $argopts]%2 !=0} {
error "[namespace current]::hex2dec arguments prior to list_largeHex must be option/value pairs - received '$argopts'" error "[namespace current]::hex2dec arguments prior to list_largeHex must be option/value pairs - received '$argopts'"
} }
set defaults [dict create\ set opts [dict create\
-validate 1\ -validate 1\
-empty_as_hex "INVALID set -empty_as_hex to a hex string e.g FF if empty values should be replaced"\ -empty_as_hex "INVALID set -empty_as_hex to a hex string e.g FF if empty values should be replaced"\
] ]
set known_opts [dict keys $defaults] set known_opts [dict keys $opts]
set fullopts [dict create] foreach {k v} $argopts {
dict for {k v} $argopts { dict set opts [tcl::prefix match -message "options for hex2dec. Unexpected option" $known_opts $k] $v
dict set fullopts [tcl::prefix match -message "options for hex2dec. Unexpected option" $known_opts $k] $v
} }
set opts [dict merge $defaults $fullopts]
# -- --- --- --- # -- --- --- ---
set opt_validate [dict get $opts -validate] set opt_validate [dict get $opts -validate]
set opt_empty [dict get $opts -empty_as_hex] set opt_empty [dict get $opts -empty_as_hex]
@ -606,7 +717,7 @@ namespace eval punk::lib {
] ]
set known_opts [dict keys $defaults] set known_opts [dict keys $defaults]
set fullopts [dict create] set fullopts [dict create]
dict for {k v} $argopts { foreach {k v} $argopts {
dict set fullopts [tcl::prefix match -message "options for [namespace current]::dec2hex. Unexpected option" $known_opts $k] $v dict set fullopts [tcl::prefix match -message "options for [namespace current]::dec2hex. Unexpected option" $known_opts $k] $v
} }
set opts [dict merge $defaults $fullopts] set opts [dict merge $defaults $fullopts]
@ -1050,10 +1161,13 @@ namespace eval punk::lib {
return [join $lines $joinchar] return [join $lines $joinchar]
} }
proc list_as_lines2 {args} { proc list_as_lines2 {args} {
#eat or own dogfood version - shows the implementation is simpler - but unfortunately not suitable for a simple function like this which should be as fast as possible #eat or own dogfood version - shows the implementation is simpler - but unfortunately not suitable for a simple function like this which should be as fast as possible?
lassign [dict values [punk::lib::opts_values -minvalues 1 -maxvalues 1 { lassign [dict values [punk::args::get_dict {
-joinchar -default \n -joinchar -default \n
*values -min 1 -max 1
} $args]] opts values } $args]] opts values
puts "opts:$opts"
puts "values:$values"
return [join [dict get $values 0] [dict get $opts -joinchar]] return [join [dict get $values 0] [dict get $opts -joinchar]]
} }
@ -1089,7 +1203,8 @@ namespace eval punk::lib {
#-anyopts 1 avoids having to know what to say if odd numbers of options passed etc #-anyopts 1 avoids having to know what to say if odd numbers of options passed etc
#we don't have to decide what is an opt vs a value #we don't have to decide what is an opt vs a value
#even if the caller provides the argument -block without a value the next function's validation will report a reasonable error because there is now nothing in $values (consumed by -block) #even if the caller provides the argument -block without a value the next function's validation will report a reasonable error because there is now nothing in $values (consumed by -block)
lassign [dict values [punk::lib::opts_values -anyopts 1 { lassign [dict values [punk::args::get_dict {
*opts -any 1
-block -default {} -block -default {}
} $args]] opts valuedict } $args]] opts valuedict
tailcall linelist {*}$opts {*}[dict values $valuedict] tailcall linelist {*}$opts {*}[dict values $valuedict]
@ -1107,22 +1222,23 @@ namespace eval punk::lib {
set text [string map [list \r\n \n] $text] ;#review - option? set text [string map [list \r\n \n] $text] ;#review - option?
set arglist [lrange $args 0 end-1] set arglist [lrange $args 0 end-1]
set defaults [dict create\ set opts [dict create\
-block {trimhead1 trimtail1}\ -block {trimhead1 trimtail1}\
-line {}\ -line {}\
-commandprefix ""\ -commandprefix ""\
-ansiresets auto\ -ansiresets auto\
-ansireplays 0\ -ansireplays 0\
] ]
dict for {o v} $arglist { foreach {o v} $arglist {
switch -- $o { switch -- $o {
-block - -line - -commandprefix - -ansiresets - -ansireplays {} -block - -line - -commandprefix - -ansiresets - -ansireplays {
dict set opts $o $v
}
default { default {
error "linelist: Unrecognized option '$o' usage:$usage" error "linelist: Unrecognized option '$o' usage:$usage"
} }
} }
} }
set opts [dict merge $defaults $arglist]
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_block [dict get $opts -block] set opt_block [dict get $opts -block]
if {[llength $opt_block]} { if {[llength $opt_block]} {
@ -1157,9 +1273,20 @@ namespace eval punk::lib {
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_line [dict get $opts -line] set opt_line [dict get $opts -line]
set tl_left 0
set tl_right 0
set tl_both 0
foreach lo $opt_line { foreach lo $opt_line {
switch -- $lo { switch -- $lo {
trimline - trimleft - trimright {} trimline {
set tl_both 1
}
trimleft {
set tl_left 1
}
trimright {
set tl_right 1
}
default { default {
set known_lineopts [list trimline trimleft trimright] set known_lineopts [list trimline trimleft trimright]
error "linelist: unknown -line option value: $lo known values: $known_lineopts" error "linelist: unknown -line option value: $lo known values: $known_lineopts"
@ -1167,8 +1294,9 @@ namespace eval punk::lib {
} }
} }
#normalize trimleft trimright combo #normalize trimleft trimright combo
if {"trimleft" in $opt_line && "trimright" in $opt_line} { if {$tl_left && $tl_right} {
set opt_line [list "trimline"] set opt_line [list "trimline"]
set tl_both 1
} }
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_commandprefix [dict get $opts -commandprefix] set opt_commandprefix [dict get $opts -commandprefix]
@ -1192,13 +1320,17 @@ namespace eval punk::lib {
set linelist $nlsplit set linelist $nlsplit
#lappend linelist {*}$nlsplit #lappend linelist {*}$nlsplit
} else { } else {
foreach ln $nlsplit {
#already normalized trimleft+trimright to trimline #already normalized trimleft+trimright to trimline
if {"trimline" in $opt_line} { if {$tl_both} {
foreach ln $nlsplit {
lappend linelist [string trim $ln] lappend linelist [string trim $ln]
} elseif {"trimleft" in $opt_line} { }
} elseif {$tl_left} {
foreach ln $nlsplit {
lappend linelist [string trimleft $ln] lappend linelist [string trimleft $ln]
} elseif {"trimright" in $opt_line} { }
} elseif {$tl_right} {
foreach ln $nlsplit {
lappend linelist [string trimright $ln] lappend linelist [string trimright $ln]
} }
} }
@ -1397,544 +1529,6 @@ namespace eval punk::lib {
return $linelist return $linelist
} }
#maintenance - take over from punk::args - or put back in punk::args once fixed to support pipeline argument order
#possible improvements - after the 1st call, replace the callsite in the calling proc with an inline script to process and validate the arguments as specified in optionspecs
#This would require a tcl parser .. and probably lots of other work
#It would also probably only be practical if there are no dynamic entries in the optionspecs. An option for opts_values to indicate the caller wants this optimisation would probably be best.
#generally we expect values to contain leading dashes only if -- specified. Otherwise no reliable way determine difference between bad flags and values
#If no eopts (--) specified we stop looking for opts at the first nondash encountered in a position we'd expect a dash - so without eopt, values could contain dashes - but not in first position after flags.
#only supports -flag val pairs, not solo options
#If an option is supplied multiple times - only the last value is used.
proc opts_values {args} {
#*** !doctools
#[call [fun opts_values] [opt {option value...}] [arg optionspecs] [arg rawargs] ]
#[para]Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values
#[para]Returns a dict of the form: opts <options_dict> values <values_dict>
#[para]ARGUMENTS:
#[list_begin arguments]
#[arg_def multiline-string optionspecs]
#[para] This a block of text with records delimited by newlines (lf or crlf) - but with multiline values allowed if properly quoted/braced
#[para]'info complete' is used to determine if a record spans multiple lines due to multiline values
#[para]Each optionspec line must be of the form:
#[para]-optionname -key val -key2 val2...
#[para]where the valid keys for each option specification are: -default -type -range -choices -optional
#[arg_def list rawargs]
#[para] This is a list of the arguments to parse. Usually it will be the \$args value from the containing proc
#[list_end]
#[para]
#consider line-processing example below for we need info complete to determine record boundaries
#punk::lib::opt_values {
# -opt1 -default {}
# -opt2 -default {
# etc
# } -multiple 1
#} $args
#-- cannot be used to allow opts_values itself to accept rawargs as separate values - so it doesn't serve much purpose other than as an indicator of intention
#For consistency we support it anyway.
#we have to be careful with end-of-options flag --
#It may legitimately be the only value in the rawargs list (which is a bit odd - but possible) or it may occur immediately before optionspecs and rawargs
#if there is more than one entry in rawargs - we won't find it anyway - so that's ok
set eopts_posn [lsearch $args --]
if {$eopts_posn == ([llength $args]-1)} {
#sole argument in rawargs - not the one we're looking for
set eopts_posn -1
}
if {$eopts_posn >= 0} {
set ov_opts [lrange $args 0 $eopts_posn-1]
set ov_vals [lrange $args $eopts_posn+1 end]
} else {
set ov_opts [lrange $args 0 end-2]
set ov_vals [lrange $args end-1 end]
}
if {[llength $ov_vals] < 2 || [llength $ov_opts] %2 != 0} {
error "opts_args wrong # args: should be opts_values ?opt val?... optionspecs rawargs_as_list
}
set optionspecs [lindex $ov_vals 0]
set optionspecs [string map [list \r\n \n] $optionspecs]
set rawargs [lindex $ov_vals 1]
set optspec_defaults [dict create\
-optional 1\
-allow_ansi 1\
-validate_without_ansi 0\
-strip_ansi 0\
-nocase 0\
]
set required_opts [list]
set required_vals [list]
set arg_info [dict create]
set defaults_dict_opts [dict create]
set defaults_dict_values [dict create]
#first process dashed and non-dashed argspecs without regard to whether non-dashed are at the beginning or end
set value_names [list]
set records [list]
set linebuild ""
foreach rawline [split $optionspecs \n] {
set recordsofar [string cat $linebuild $rawline]
if {![info complete $recordsofar]} {
append linebuild [string trimleft $rawline] \n
} else {
lappend records [string cat $linebuild $rawline]
set linebuild ""
}
}
foreach ln $records {
set trimln [string trim $ln]
switch -- [string index $trimln 0] {
"" - # {continue}
}
set argname [lindex $trimln 0]
set argspecs [lrange $trimln 1 end]
if {[llength $argspecs] %2 != 0} {
error "punk::lib::opts_values - bad optionspecs line for argument '$argname' Remaining items on line must be in paired option-value format - received '$argspecs'"
}
if {[string match -* $argname]} {
dict set argspecs -ARGTYPE option
set is_opt 1
} else {
dict set argspecs -ARGTYPE value
lappend value_names $argname
set is_opt 0
}
dict for {spec specval} $argspecs {
switch -- $spec {
-default - -type - -range - -choices - -nocase - -optional - -multiple - -validate_without_ansi - -allow_ansi - -strip_ansi - -ARGTYPE {}
default {
set known_argspecs [list -default -type -range -choices -nocase -optional -multiple -validate_without_ansi -allow_ansi -strip_ansi -ARGTYPE]
error "punk::lib::opts_values - unrecognised key '$spec' in specifications for argument '$argname' Known option specification keys: $known_argspecs"
}
}
}
set argspecs [dict merge $optspec_defaults $argspecs]
dict set arg_info $argname $argspecs
if {![dict get $argspecs -optional]} {
if {$is_opt} {
lappend required_opts $argname
} else {
lappend required_vals $argname
}
}
if {[dict exists $arg_info $argname -default]} {
if {$is_opt} {
dict set defaults_dict_opts $argname [dict get $arg_info $argname -default]
} else {
dict set defaults_dict_values $argname [dict get $arg_info $argname -default]
}
}
}
#puts "--> [info frame -2] <--"
set cmdinfo [dict get [info frame -2] cmd]
#we can't treat cmdinfo as a list - it may be something like {command {*}$args} in which case lindex $cmdinfo 0 won't work
#hopefully first word is a plain proc name if this function was called in the normal manner - directly from a proc
#we will break at first space and assume the lhs of that will give enough info to be reasonable - (alternatively we could use entire cmdinfo - but it might be big and ugly)
set caller [regexp -inline {\S+} $cmdinfo]
#if called from commandline or some other contexts such as outside of a proc in a namespace - caller may just be "namespace"
if {$caller eq "namespace"} {
set caller "punk::lib::opts_values called from namespace"
}
# ------------------------------
if {$caller ne "punk::lib::opts_values"} {
#1) check our caller's call to us - recursive version - perhaps more elegant to eat our own dogfood - but maybe too much overhead for a script-based args processor which is already quite heavy :/
#lassign [punk::lib::opts_values "-anyopts -default 0 -type integer\n -minvalues -default 0 -type integer\n -maxvalues -default -1 -type integer" $args] _o ownopts _v ownvalues
#if {[dict size $ownvalues] != 2} {
# error "punk::lib::opts_values expected: a multiline text block of option-specifications, a list of args and at most three option pairs -minvalues <int>, -maxvalues <int>, -anyopts true|false - got extra arguments: '$ownvalues'"
#}
#set opt_minvalues [dict get $ownopts -minvalues]
#set opt_maxvalues [dict get $ownopts -maxvalues]
#set opt_anyopts [dict get $ownopts -anyopts]
#2) Quick and dirty - but we don't need much validation
set defaults [dict create\
-minvalues 0\
-maxvalues -1\
-anyopts 0\
]
dict for {k v} $ov_opts {
if {$k ni {-minvalues -maxvalues -anyopts}} {
error "punk::lib::opts_values unrecognised option $k. Known values [dict keys $defaults]"
}
if {![string is integer -strict $v]} {
error "punk::lib::opts_values argument $k must be of type integer"
}
}
set ov_opts [dict merge $defaults $ov_opts]
set opt_minvalues [dict get $ov_opts -minvalues]
set opt_maxvalues [dict get $ov_opts -maxvalues]
set opt_anyopts [dict get $ov_opts -anyopts]
} else {
#don't recurse ie don't check our own args if we called ourself
set opt_minvalues 2
set opt_maxvalues 2
set opt_anyopts 0
}
# ------------------------------
if {[set eopts [lsearch $rawargs "--"]] >= 0} {
set values [lrange $rawargs $eopts+1 end]
set arglist [lrange $rawargs 0 $eopts-1]
} else {
if {[lsearch $rawargs -*] >= 0} {
#to support option values with leading dash e.g -offset -1 , we can't just take the last flagindex
set i 0
foreach {k v} $rawargs {
if {![string match -* $k]} {
break
}
if {$i+1 >= [llength $rawargs]} {
#no value for last flag
error "bad options for $caller. No value supplied for last option $k"
}
incr i 2
}
set arglist [lrange $rawargs 0 $i-1]
set values [lrange $rawargs $i end]
} else {
set arglist [list]
set values $rawargs ;#no -flags detected
}
}
#confirm any valnames before last don't have -multiple key
foreach valname [lrange $value_names 0 end-1] {
if {[dict exists $arg_info $valname -multiple ]} {
error "bad key -multiple on argument spec for '$valname'. Only the last value argument specification can be marked -multiple"
}
}
set values_dict [dict create]
set validx 0
set in_multiple ""
foreach valname $value_names val $values {
if {$validx+1 > [llength $values]} {
break
}
if {$valname ne ""} {
if {[dict exists $arg_info $valname -multiple] && [dict get $arg_info $valname -multiple]} {
dict lappend values_dict $valname $val
set in_multiple $valname
} else {
dict set values_dict $valname $val
}
} else {
if {$in_multiple ne ""} {
dict lappend values_dict $in_multiple $val
} else {
dict set values_dict $validx $val
}
}
incr validx
}
if {$opt_maxvalues == -1} {
#only check min
if {[llength $values] < $opt_minvalues} {
error "bad number of trailing values for $caller. Got [llength $values] values. Expected at least $opt_minvalues"
}
} else {
if {[llength $values] < $opt_minvalues || [llength $values] > $opt_maxvalues} {
if {$opt_minvalues == $opt_maxvalues} {
error "bad number of trailing values for $caller. Got [llength $values] values. Expected exactly $opt_minvalues"
} else {
error "bad number of trailing values for $caller. Got [llength $values] values. Expected between $opt_minvalues and $opt_maxvalues inclusive"
}
}
}
#opts explicitly marked as -optional 0 must be present - regardless of -anyopts (which allows us to ignore additional opts to pass on to next call)
#however - if -anyopts is true, there is a risk we will treat a shortened option name as matching our default - when it was intended for the next call
#We will always require exact matches for all required opts to avoid this risk, even though an ultimately-called function may not require the full-length option-name REVIEW
#The aim is to allow a wrapper function to specify a default value for an option (and/or other changes/restrictions to a particular option or two) - without having to re-specify all the options for the underlying function.
#without full respecification in the wrapper - we can't know that a supplied prefix is unambiguous at the next level
#For this reason we need to pass on full-length opts for any defined options in the wrapper even if anyopts is true
set argnamespresent [dict keys $arglist]
foreach r $required_opts {
if {$r ni $argspresent} {
error "Required option missing for $caller. '$r' is marked with -optional false - so must be present in its full-length form"
}
}
set valuenamespresent [dict keys $values_dict]
foreach r $required_vals {
if {$r ni $valuenamespresent} {
error "Required value missing for $caller. '$r' is marked with -optional false - so must be present"
}
}
if {!$opt_anyopts} {
set checked_args [dict create]
for {set i 0} {$i < [llength $arglist]} {incr i} {
#allow this to error out with message indicating expected flags
set val [lindex $arglist $i+1]
set fullopt [tcl::prefix match -message "options for $caller. Unexpected option" [dict keys $arg_info] [lindex $arglist $i]]
if {[dict exists $arg_info $fullopt -multiple] && [dict get $arg_info $fullopt -multiple]} {
dict lappend checked_args $fullopt $val
} else {
dict set checked_args $fullopt $val
}
incr i ;#skip val
}
} else {
#still need to use tcl::prefix match to normalize - but don't raise an error
set checked_args [dict create]
dict for {k v} $arglist {
if {![catch {tcl::prefix::match [dict keys $arg_info] $k} fullopt]} {
if {[dict exists $arg_info $fullopt -multiple] && [dict get $arg_info $fullopt -multiple]} {
dict lappend checked_args $fullopt $v
} else {
dict set checked_args $fullopt $v
}
} else {
#opt was unspecified
dict set checked_args $k $v
}
}
}
set opts [dict merge $defaults_dict_opts $checked_args]
#assertion - checked_args keys are full-length option names if -anyopts was false or if the supplied option as a shortname matched one of our defined options
set values [dict merge $defaults_dict_values $values_dict]
#todo - allow defaults outside of choices/ranges
#check types,ranges,choices
set opts_and_values [concat $opts $values]
set combined_defaults [concat $defaults_dict_values $defaults_dict_opts] ;#can be no key collisions - we don't allow a value key beginning with dash - opt names must begin with dash
dict for {o v} $opts_and_values {
if {[dict exists $arg_info $o -multiple] && [dict get $arg_info $o -multiple]} {
set vlist $v
} else {
set vlist [list $v]
}
if {[dict exists $arg_info $o -validate_without_ansi] && [dict get $arg_info $o -validate_without_ansi]} {
set validate_without_ansi 1
package require punk::ansi
} else {
set validate_without_ansi 0
}
if {[dict exists $arg_info $o -allow_ansi] && [dict get $arg_info $o -allow_ansi]} {
set allow_ansi 1
} else {
#ironically - we need punk::ansi to detect and disallow - but we don't need it if ansi is allowed
package require punk::ansi
set allow_ansi 0
}
if {!$allow_ansi} {
#detect should work fine directly on whole list
if {[punk::ansi::ta::detect $vlist]} {
error "Option $o for $caller contains ansi - but -allow_ansi is false. Received: [ansistring VIEW $vlist]"
}
#foreach e $vlist {
# if {[punk::ansi::ta::detect $e]} {
# error "Option $o for $caller contains ansi - but -allow_ansi is false. Received: '$e'"
# }
#}
}
set vlist_check [list]
foreach e $vlist {
#could probably stripansi entire list safely in one go? - review
if {$validate_without_ansi} {
lappend vlist_check [punk::ansi::stripansi $e]
} else {
lappend vlist_check $e
}
}
set is_default 0
foreach e $vlist e_check $vlist_check {
if {[dict exists $combined_defaults $o] && ($e_check eq [dict get $combined_defaults $o])} {
incr is_default
}
}
if {$is_default eq [llength $vlist]} {
set is_default true
}
#we want defaults to pass through - even if they don't pass the checks that would be required for a specified value
#If the caller manually specified a value that happens to match the default - we don't detect that as any different from an unspecified value - Review.
if {!$is_default} {
if {[dict exists $arg_info $o -type]} {
set type [dict get $arg_info $o -type]
set ltype [string tolower $type]
switch -- $type {
int -
integer -
double {
switch -- $ltype {
int -
integer {
foreach e $vlist e_check $vlist_check {
if {![string is integer -strict $e_check]} {
error "Option $o for $caller requires type 'integer'. Received: '$e'"
}
}
}
double {
foreach e $vlist e_check $vlist_check {
if {![string is double -strict $e_check]} {
error "Option $o for $caller requires type 'double'. Received: '$e'"
}
}
}
}
#todo - small-value double comparisons with error-margin? review
if {[dict exists $arg_info $o -range]} {
lassign [dict get $arg_info $o -range] low high
foreach e $vlist e_check $vlist_check {
if {$e_check < $low || $e_check > $high} {
error "Option $o for $caller must be between $low and $high. Received: '$e'"
}
}
}
}
bool -
boolean {
foreach e $vlist e_check $vlist_check {
if {![string is boolean -strict $e_check]} {
error "Option $o for $caller requires type 'boolean'. Received: '$e'"
}
}
}
alnum -
alpha -
ascii -
control -
digit -
graph -
lower -
print -
punct -
space -
upper -
wordchar -
xdigit {
foreach e $vlist e_check $vlist_check {
if {![string is [string tolower $type] $e_check]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e'"
}
}
}
file -
directory -
existingfile -
existingdirectory {
foreach e $vlist e_check $vlist_check {
if {!([string length $e_check]>0 && ![regexp {[\"*?<>\;]} $e_check])} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which doesn't look like it could be a file or directory"
}
}
if {[string tolower $type] in {existingfile}} {
foreach e $vlist e_check $vlist_check {
if {![file exists $e_check]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which is not an existing file"
}
}
} elseif {[string tolower $type] in {existingdirectory}} {
foreach e $vlist e_check $vlist_check {
if {![file isdirectory $e_check]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which is not an existing directory"
}
}
}
}
char -
character {
foreach e $vlist e_check $vlist_check {
if {[string length != 1]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which is not a single character"
}
}
}
}
}
if {[dict exists $arg_info $o -choices]} {
set choices [dict get $arg_info $o -choices]
set nocase [dict get $arg_info $o -nocase]
foreach e $vlist e_check $vlist_check {
if {$nocase} {
set casemsg "(case insensitive)"
set choices_test [string tolower $choices]
set v_test [string tolower $e_check]
} else {
set casemsg "(case sensitive)"
set v_test $e_check
set choices_test $choices
}
if {$v_test ni $choices_test} {
error "Option $o for $caller must be one of the listed values $choices $casemsg. Received: '$e'"
}
}
}
}
if {[dict exists $arg_info $o -strip_ansi] && [dict get $arg_info $o -strip_ansi]} {
set stripped_list [list]
foreach e $vlist {
lappend stripped_list [punk::ansi::stripansi $e]
}
if {[dict exists $arg_info $o -multiple] && [dict get $arg_info $o -multiple]} {
if {[dict get $arg_info $o -ARGTYPE] eq "option"} {
dict set opts $o $stripped_list
} else {
dict set values $o $stripped_list
}
} else {
if {[dict get $arg_info $o -ARGTYPE] eq "option"} {
dict set opts $o [lindex $stripped_list 0]
} else {
dict set values [lindex $stripped_list 0]
}
}
}
}
#maintain order of opts $opts values $values as caller may use lassign.
return [dict create opts $opts values $values]
}
#tcl8.7/9 compatibility for 8.6
if {[info commands ::tcl::string::insert] eq ""} {
#https://wiki.tcl-lang.org/page/string+insert
# Pure Tcl implementation of [string insert] command.
proc ::tcl::string::insert {string index insertString} {
# Convert end-relative and TIP 176 indexes to simple integers.
if {[regexp -expanded {
^(end(?![\t\n\v\f\r ]) # "end" is never followed by whitespace
|[\t\n\v\f\r ]*[+-]?\d+) # m, with optional leading whitespace
(?:([+-]) # op, omitted when index is "end"
([+-]?\d+))? # n, omitted when index is "end"
[\t\n\v\f\r ]*$ # optional whitespace (unless "end")
} $index _ m op n]} {
# Convert first index to an integer.
switch $m {
end {set index [string length $string]}
default {scan $m %d index}
}
# Add or subtract second index, if provided.
switch $op {
+ {set index [expr {$index + $n}]}
- {set index [expr {$index - $n}]}
}
} elseif {![string is integer -strict $index]} {
# Reject invalid indexes.
return -code error "bad index \"$index\": must be\
integer?\[+-\]integer? or end?\[+-\]integer?"
}
# Concatenate the pre-insert, insertion, and post-insert strings.
string cat [string range $string 0 [expr {$index - 1}]] $insertString\
[string range $string $index end]
}
# Bind [string insert] to [::tcl::string::insert].
namespace ensemble configure string -map [dict replace\
[namespace ensemble configure string -map]\
insert ::tcl::string::insert]
}
interp alias {} errortime {} punk::lib::errortime interp alias {} errortime {} punk::lib::errortime
proc errortime {script groupsize {iters 2}} { proc errortime {script groupsize {iters 2}} {
@ -2051,6 +1645,26 @@ namespace eval punk::lib::system {
#[para] Internal functions that are not part of the API #[para] Internal functions that are not part of the API
#[list_begin definitions] #[list_begin definitions]
proc has_script_var_bug {} {
set script {set j [list spud] ; list}
append script \n
uplevel #0 $script
set rep1 [tcl::unsupported::representation $::j]
set script ""
set rep2 [tcl::unsupported::representation $::j]
set nostring1 [string match "*no string" $rep1]
set nostring2 [string match "*no string" $rep2]
#we assume it should have no string rep in either case
#Review: check Tcl versions for behaviour/consistency
if {!$nostring2} {
return true
} else {
return false
}
}
proc mostFactorsBelow {n} { proc mostFactorsBelow {n} {
##*** !doctools ##*** !doctools
#[call [fun mostFactorsBelow] [arg n]] #[call [fun mostFactorsBelow] [arg n]]

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

@ -740,7 +740,7 @@ namespace eval punk::mix::base {
proc cksum_filter_opts {args} { proc cksum_filter_opts {args} {
set ck_opt_names [dict keys [cksum_default_opts]] set ck_opt_names [dict keys [cksum_default_opts]]
set ck_opts [dict create] set ck_opts [dict create]
dict for {k v} $args { foreach {k v} $args {
if {$k in $ck_opt_names} { if {$k in $ck_opt_names} {
dict set ck_opts $k $v dict set ck_opts $k $v
} }

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

@ -24,7 +24,8 @@ package require punkcheck ;#checksum and/or timestamp records
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#review
#deck - rename to dev
namespace eval punk::mix::cli { namespace eval punk::mix::cli {
namespace eval temp_import { namespace eval temp_import {
} }
@ -101,11 +102,6 @@ namespace eval punk::mix::cli {
#interp alias {} ::punk::mix::cli::project.new {} ::punk::mix::cli::new #interp alias {} ::punk::mix::cli::project.new {} ::punk::mix::cli::new
proc make {args} { proc make {args} {
set startdir [pwd] set startdir [pwd]
set project_base "" ;#empty for unknown set project_base "" ;#empty for unknown
@ -209,17 +205,20 @@ namespace eval punk::mix::cli {
} }
proc validate_modulename {modulename args} { proc validate_modulename {modulename args} {
set defaults [list\ set opts [list\
-errorprefix validate_modulename\ -errorprefix validate_modulename\
] ]
if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"} if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"}
set known_opts [dict keys $defaults] foreach {k v} $args {
foreach k [dict keys $args] { switch -- $k {
if {$k ni $known_opts} { -errorprefix {
error "validate_modulename error: unknown option $k. known options: $known_opts" dict set opts $k $v
}
default {
error "validate_modulename error: unknown option '$k'. known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_errorprefix [dict get $opts -errorprefix] set opt_errorprefix [dict get $opts -errorprefix]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
@ -264,17 +263,20 @@ namespace eval punk::mix::cli {
return $projectname return $projectname
} }
proc validate_name_not_empty_or_spaced {name args} { proc validate_name_not_empty_or_spaced {name args} {
set defaults [list\ set opts [list\
-errorprefix projectname\ -errorprefix projectname\
] ]
if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"} if {[llength $args] %2 != 0} {error "validate_name_not_empty_or_spaced args must be name-value pairs: received '$args'"}
set known_opts [dict keys $defaults] foreach {k v} $args {
foreach k [dict keys $args] { switch -- $k {
if {$k ni $known_opts} { -errorprefix {
error "validate_modulename error: unknown option $k. known options: $known_opts" dict set opts $k $v
}
default {
error "validate_name_not_empty_or_spaced error: unknown option $k. known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_errorprefix [dict get $opts -errorprefix] set opt_errorprefix [dict get $opts -errorprefix]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
@ -759,10 +761,9 @@ namespace eval punk::mix::cli {
} }
proc kettle_call {calltype args} { proc kettle_call {calltype args} {
variable kettle_reset_bodies variable kettle_reset_bodies
if {$calltype ni [list lib shell]} { switch -- $calltype {
error "deck kettle_call 1st argument must be one of: 'lib' for direct use of kettle module or 'shell' to call as separate process" lib {}
} shell {
if {$calltype eq "shell"} {
set kettleappfile [file dirname [info nameofexecutable]]/kettle set kettleappfile [file dirname [info nameofexecutable]]/kettle
set kettlebatfile [file dirname [info nameofexecutable]]/kettle.bat set kettlebatfile [file dirname [info nameofexecutable]]/kettle.bat
@ -778,6 +779,10 @@ namespace eval punk::mix::cli {
} }
} }
} }
default {
error "deck kettle_call 1st argument must be one of: 'lib' for direct use of kettle module or 'shell' to call as separate process"
}
}
set startdir [pwd] set startdir [pwd]
if {![file exists $startdir/build.tcl]} { if {![file exists $startdir/build.tcl]} {
error "deck kettle must be run from a folder containing build.tcl (cwd: [pwd])" error "deck kettle must be run from a folder containing build.tcl (cwd: [pwd])"
@ -901,7 +906,12 @@ namespace eval punk::mix::cli {
variable default_command help variable default_command help
package require punk::mix::base package require punk::mix::base
package require punk::overlay package require punk::overlay
if {[catch {
punk::overlay::custom_from_base [namespace current] ::punk::mix::base punk::overlay::custom_from_base [namespace current] ::punk::mix::base
} errM]} {
puts stderr "punk::mix::cli load error: Failed to overlay punk::mix::base $errM"
error "punk::mix::cli error: $errM"
}
} }

1
src/bootsupport/modules/punk/mix/commandset/doc-0.1.0.tm

@ -33,6 +33,7 @@ namespace eval punk::mix::commandset::doc {
puts "documentation subsystem" puts "documentation subsystem"
puts "commands: doc.build" puts "commands: doc.build"
puts " build documentation from src/doc to src/embedded using the kettle build tool" puts " build documentation from src/doc to src/embedded using the kettle build tool"
puts "commands: doc.status"
} }
proc build {} { proc build {} {

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

@ -354,10 +354,10 @@ namespace eval punk::mix::commandset::module {
#it is nevertheless useful information - and not the only way developer-machine/build-machine paths can leak #it is nevertheless useful information - and not the only way developer-machine/build-machine paths can leak
#for now the user has the option to override any templates and remove %moduletemplate% if it is a security/privacy concern #for now the user has the option to override any templates and remove %moduletemplate% if it is a security/privacy concern
#Don't put litera %x% in the code for the commandset::module itself - to stop them being seen by layout scanner as replacable tokens #Don't put literal %x% in the code for the commandset::module itself - to stop them being seen by layout scanner as replacable tokens
set tagnames [list moduletemplate $moduletemplate project $projectname pkg $modulename year $year license $opt_license version $infile_version] set tagnames [list moduletemplate $moduletemplate project $projectname pkg $modulename year $year license $opt_license version $infile_version]
set strmap [list] set strmap [list]
dict for {tag val} $tagnames { foreach {tag val} $tagnames {
lappend strmap %$tag% $val lappend strmap %$tag% $val
} }
set template_filedata [string map $strmap $template_filedata] set template_filedata [string map $strmap $template_filedata]

18
src/bootsupport/modules/punk/mix/commandset/project-0.1.0.tm

@ -390,7 +390,7 @@ namespace eval punk::mix::commandset::project {
set tagmap [list [lib::template_tag project] $projectname] set tagmap [list [lib::template_tag project] $projectname]
if {[llength $templatefiles]} { if {[llength $templatefiles]} {
puts stdout "Filling template file placeholders with the following tag map:" puts stdout "Filling template file placeholders with the following tag map:"
dict for {placeholder value} $tagmap { foreach {placeholder value} $tagmap {
puts stdout " $placeholder -> $value" puts stdout " $placeholder -> $value"
} }
} }
@ -586,10 +586,14 @@ namespace eval punk::mix::commandset::project {
set col6_dupids [list] set col6_dupids [list]
set col7_pdescs [list] set col7_pdescs [list]
set codes [dict create] set codes [dict create]
set file_idx 0
foreach dbfile $col1_dbfiles { foreach dbfile $col1_dbfiles {
set project_name "" set project_name ""
set project_code "" set project_code ""
set project_desc "" set project_desc ""
set db_error ""
if {[file exists $dbfile]} {
if {[catch {
sqlite3 dbp $dbfile sqlite3 dbp $dbfile
dbp eval {select name,value from config where name like 'project-%';} r { dbp eval {select name,value from config where name like 'project-%';} r {
if {$r(name) eq "project-name"} { if {$r(name) eq "project-name"} {
@ -600,11 +604,21 @@ namespace eval punk::mix::commandset::project {
set project_desc $r(value) set project_desc $r(value)
} }
} }
dbp close } errM]} {
set db_error $errM
}
catch {dbp close}
} else {
set db_error "fossil file $dbfile missing"
}
lappend col4_pnames $project_name lappend col4_pnames $project_name
lappend col5_pcodes $project_code lappend col5_pcodes $project_code
dict lappend codes $project_code $dbfile dict lappend codes $project_code $dbfile
lappend col7_pdescs $project_desc lappend col7_pdescs $project_desc
if {$db_error ne ""} {
lset col1_dbfiles $file_idx "[a+ web-red]$dbfile[a]"
}
incr file_idx
} }
set setid 1 set setid 1

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

@ -117,18 +117,21 @@ namespace eval punk::mix::commandset::scriptwrap {
} }
set crlf_lf_replacements [list \uFFFF \uFFFE] ;#defaults - if already exist in file - error out with message set crlf_lf_replacements [list \uFFFF \uFFFE] ;#defaults - if already exist in file - error out with message
# -ignore_rems 1 allows testing of alignment state if rems were stripped - todo - lf/crlf-preserving rem strip function # -ignore_rems 1 allows testing of alignment state if rems were stripped - todo - lf/crlf-preserving rem strip function
set defaults [dict create\ set opts [dict create\
-ignore_rems 0\ -ignore_rems 0\
-substitutionmap {}\ -substitutionmap {}\
-crlf_lf_replacements $crlf_lf_replacements\ -crlf_lf_replacements $crlf_lf_replacements\
] ]
set known_opts [dict keys $defaults]
foreach {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
error "checkfile error - unknown option '$k'. Known options: $known_opts" -ignore_rems - -substitutionmap - -crlf_lf_replacements {
dict set opts $k $v
}
default {
error "checkfile error - unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- # -- --- --- --- --- --- ---
set opt_ignore_rems [dict get $opts -ignore_rems] set opt_ignore_rems [dict get $opts -ignore_rems]
set opt_substitutionmap [dict get $opts -substitutionmap] set opt_substitutionmap [dict get $opts -substitutionmap]
@ -756,20 +759,25 @@ namespace eval punk::mix::commandset::scriptwrap {
#specific filepath to just wrap one script at the xxx-pre-launch-suprocess site #specific filepath to just wrap one script at the xxx-pre-launch-suprocess site
#scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf #scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf
proc multishell {filepath_or_scriptset args} { proc multishell {filepath_or_scriptset args} {
set defaults [dict create\ set opts [dict create\
-askme 1\ -askme 1\
-outputfolder "\uFFFF"\ -outputfolder "\uFFFF"\
-template "\uFFFF"\ -template "\uFFFF"\
-returnextra 0\ -returnextra 0\
-force 0\ -force 0\
] ]
set known_opts [dict keys $defaults] #set known_opts [dict keys $defaults]
dict for {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
-askme - -outputfolder - -template - -returnextra - -force {
error "punk::mix::commandset::scriptwrap error. Unrecognized option '$k'. Known-options: $known_opts" dict set opts $k $v
}
default {
error "punk::mix::commandset::multishell error. Unrecognized option '$k'. Known-options: [dict keys $opts]"
}
} }
} }
set usage "" set usage ""
append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n
append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n
@ -779,7 +787,6 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage puts stderr $usage
return false return false
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- ---
set opt_askme [dict get $opts -askme] set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template] set opt_template [dict get $opts -template]
@ -1190,11 +1197,22 @@ namespace eval punk::mix::commandset::scriptwrap {
proc get_wrapper_folders {args} { proc get_wrapper_folders {args} {
set opts [dict get [punk::get_leading_opts_and_values { set argd [punk::args::get_dict {
-scriptpath "" #*** !doctools
} $args -maxvalues 0] opts] #[call [fun get_wrapper_folders] [arg args] ]
#[para] Return list of dicts representing wrapper folders. keys: basefolder sourceinfo
#[para] Arguments:
# [list_begin arguments]
# [arg_def string args] name-value pairs -scriptpath <path>
# [list_end]
*proc -name get_wrapper_folders
*opts -anyopts 0
-scriptpath -default ""
*values -minvalues 0 -maxvalues 0
} $args]
# -- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- ---
set opt_scriptpath [dict get $opts -scriptpath] set opt_scriptpath [dict get $argd opts -scriptpath]
# -- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- ---
set wrapper_template_bases [list] set wrapper_template_bases [list]

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

@ -591,7 +591,7 @@ namespace eval punk::ns {
#REVIEW - ansi codes can be *very* confusing to the user when trying to handle lists etc.. #REVIEW - ansi codes can be *very* confusing to the user when trying to handle lists etc..
proc get_nslist {args} { proc get_nslist {args} {
set known_types [list children commands exported imported aliases procs ensembles ooclasses ooobjects] set known_types [list children commands exported imported aliases procs ensembles ooclasses ooobjects ooprivateobjects ooprivateclasses native coroutines interps zlibstreams]
set defaults [dict create\ set defaults [dict create\
-match ""\ -match ""\
-types $known_types\ -types $known_types\
@ -605,9 +605,9 @@ namespace eval punk::ns {
set types $requested_types set types $requested_types
if {"all" in $requested_types} { if {"all" in $requested_types} {
foreach t $known_types { foreach known $known_types {
if {$t ni $types} { if {$known ni $types} {
lappend types $t lappend types $known
} }
} }
} }
@ -618,13 +618,20 @@ namespace eval punk::ns {
if {"ooobjects" ni $types} { if {"ooobjects" ni $types} {
lappend types "ooobjects" lappend types "ooobjects"
} }
if {"ooprivateobjects" ni $types} {
lappend types "ooprivateobjects"
}
if {"ooprivateclasses" ni $types} {
lappend types "ooprivateclasses"
}
} }
foreach t $types { foreach t $types {
if {$t in [list "oo" "all"]} { switch -- $t {
continue oo - all -
children - commands - exported - imported - aliases - procs - ensembles - ooclasses - ooobjects - ooprivateobjects - ooprivateclasses - native - coroutines - interps - zlibstreams {}
default {
error "Unrecognised namespace member type: $t known types: $known_types oo all"
} }
if {$t ni $known_types} {
error "Unrecognised namespace member type: $t known types: $known_types"
} }
} }
@ -645,6 +652,12 @@ namespace eval punk::ns {
set ensembles [list] set ensembles [list]
set ooclasses [list] set ooclasses [list]
set ooobjects [list] set ooobjects [list]
set ooprivateobjects [list]
set ooprivateclasses [list]
set native [list]
set interps [list]
set coroutines [list]
set zlibstreams [list]
if {$opt_nsdict eq ""} { if {$opt_nsdict eq ""} {
set nsmatches [get_ns_dicts $fq_glob -allbelow 0] set nsmatches [get_ns_dicts $fq_glob -allbelow 0]
@ -678,27 +691,49 @@ namespace eval punk::ns {
} }
if {"commands" in $types} { if {"commands" in $types} {
set commands [dict get $contents commands] set commands [dict get $contents commands]
if {"exported" in $types} { foreach t $types {
switch -- $t {
exported {
set exported [dict get $contents exported] set exported [dict get $contents exported]
} }
if {"imported" in $types} { imported {
set imported [dict get $contents imported] set imported [dict get $contents imported]
} }
if {"aliases" in $types} { aliases {
set aliases [dict get $contents aliases] set aliases [dict get $contents aliases]
} }
if {"procs" in $types} { procs {
set procs [dict get $contents procs] set procs [dict get $contents procs]
} }
if {"ensembles" in $types} { ensembles {
set ensembles [dict get $contents ensembles] set ensembles [dict get $contents ensembles]
} }
if {"ooclasses" in $types} { ooclasses {
set ooclasses [dict get $contents ooclasses] set ooclasses [dict get $contents ooclasses]
} }
if {"ooobjects" in $types} { ooobjects {
set ooobjects [dict get $contents ooobjects] set ooobjects [dict get $contents ooobjects]
} }
ooprivateobjects {
set ooprivateobjects [dict get $contents ooprivateobjects]
}
ooprivateclasses {
set ooprivateclasses [dict get $contents ooprivateclasses]
}
native {
set native [dict get $contents native]
}
interps {
set interps [dict get $contents interps]
}
coroutines {
set coroutines [dict get $contents coroutines]
}
zlibstreams {
set zlibstreams [dict get $contents zlibstreams]
}
}
}
} }
set numchildren [llength $children] set numchildren [llength $children]
@ -719,11 +754,12 @@ namespace eval punk::ns {
set seencmds [list] set seencmds [list]
set masked [list] ;# set masked [list] ;#
set cmdsets [concat $procs $ensembles $ooclasses $ooobjects $ooprivateobjects $ooprivateclasses $native $interps $coroutines $zlibstreams]
foreach a $aliases { foreach a $aliases {
if {[list c $a] in $elements} { if {[list c $a] in $elements} {
#possibly an ordinary alias - or a renamed alias that is masked by a proc/ensemble/oo #possibly an ordinary alias - or a renamed alias that is masked by a proc/ensemble/oo
#we can detect masking by proc/ensemble/oo - but not by a binary extension loaded after the rename: REVIEW #we can detect masking by proc/ensemble/oo - but not by a binary extension loaded after the rename: REVIEW
if {$a in [concat $procs $ensembles $ooclasses $ooobjects]} { if {$a in $cmdsets} {
#we have an alias that is also a known other command-type #we have an alias that is also a known other command-type
lappend elements [list c $a] ;#add in twice so we can display both. lappend elements [list c $a] ;#add in twice so we can display both.
lappend masked $a lappend masked $a
@ -776,10 +812,17 @@ namespace eval punk::ns {
set col3 [string repeat " " [expr {$cmdwidest1 + 8}]] set col3 [string repeat " " [expr {$cmdwidest1 + 8}]]
set col4 [string repeat " " [expr {$cmdwidest2 + 8}]] set col4 [string repeat " " [expr {$cmdwidest2 + 8}]]
set col5 [string repeat " " [expr {$cmdwidest3 + 8}]] set col5 [string repeat " " [expr {$cmdwidest3 + 8}]]
set a [a+ purple bold] set a [a+ bold purple]
set e [a+ yellow bold] set e [a+ bold yellow]
set o [a+ cyan bold] set p [a+ bold white]
set p [a+ white bold] set c_nat [a+ web-gray] ;#native
set c_int [a+ web-orange] ;#interps
set c_cor [a+ web-hotpink] ;#coroutines
set c_ooo [a+ bold cyan] ;#object
set c_ooc [a+ web-aquamarine] ;#class
set c_ooO [a+ web-dodgerblue] ;#privateObject
set c_ooC [a+ web-lightskyblue] ;#privateClass
set c_zst [a+ web-yellow] ;#zlibstreams
set a1 [a][a+ cyan] set a1 [a][a+ cyan]
foreach ch1 $children1 ch2 $children2 cmd1 $elements1 cmd2 $elements2 cmd3 $elements3 cmd4 $elements4 { foreach ch1 $children1 ch2 $children2 cmd1 $elements1 cmd2 $elements2 cmd3 $elements3 cmd4 $elements4 {
@ -804,6 +847,7 @@ namespace eval punk::ns {
if {$cmd in $exported} { if {$cmd in $exported} {
set c [a+ green bold] set c [a+ green bold]
} }
#keep oooobjects below ooclasses, ooprivateclasses, ooprivateobjects
if {$cmd in $aliases && $cmd in $seencmds} { if {$cmd in $aliases && $cmd in $seencmds} {
#masked commandless-alias #masked commandless-alias
#assertion member of masked - but we use seencmds instead to detect. #assertion member of masked - but we use seencmds instead to detect.
@ -812,14 +856,26 @@ namespace eval punk::ns {
set prefix [overtype::right $prefix "-R"] set prefix [overtype::right $prefix "-R"]
} elseif {$cmd in $procs} { } elseif {$cmd in $procs} {
set prefix "${p}prc " set prefix "${p}prc "
} elseif {$cmd in $native} {
set prefix "${c_nat}nat "
} elseif {$cmd in $ensembles} { } elseif {$cmd in $ensembles} {
set prefix "${e}ens " set prefix "${e}ens "
} elseif {$cmd in $ooclasses} { } elseif {$cmd in $ooclasses} {
set prefix "${o}ooc " set prefix "${c_ooc}ooc "
} elseif {$cmd in $ooprivateobjects} {
set prefix "${c_ooO}ooO "
} elseif {$cmd in $ooprivateclasses} {
set prefix "${c_ooC}ooC "
} elseif {$cmd in $ooobjects} { } elseif {$cmd in $ooobjects} {
set prefix "${o}ooo " set prefix "${c_ooo}ooo "
} elseif {$cmd in $aliases} { } elseif {$cmd in $aliases} {
set prefix "${a}als " set prefix "${a}als "
} elseif {$cmd in $interps} {
set prefix "${c_int}int "
} elseif {$cmd in $coroutines} {
set prefix "${c_cor}cor "
} elseif {$cmd in $zlibstreams} {
set prefix "${c_zst}zst "
} else { } else {
} }
if {$cmd in $imported} { if {$cmd in $imported} {
@ -937,6 +993,14 @@ namespace eval punk::ns {
return [get_ns_dicts $ns_absolute {*}$args] return [get_ns_dicts $ns_absolute {*}$args]
} }
#info cmdtype available in 8.7+
proc cmdtype {cmd} {
if {[info commands ::tcl::info::cmdtype] ne ""} {
tailcall info cmdtype $cmd
}
#we could examine namespaces to determine - but would be duplicating work already done/available in get_ns_dicts which is usually the caller
return na
}
#non-contextual - but impure due to state-retrieval from the passed-in namespace part of the fq_glob #non-contextual - but impure due to state-retrieval from the passed-in namespace part of the fq_glob
#returns a list of dicts even if only one ns matched #returns a list of dicts even if only one ns matched
#glob chars at last segment match contents/children of namespaces #glob chars at last segment match contents/children of namespaces
@ -1042,9 +1106,15 @@ namespace eval punk::ns {
#set allprocs [nseval $location {::info procs}] #set allprocs [nseval $location {::info procs}]
set childtails [lmap v $allchildren {nstail $v}] set childtails [lmap v $allchildren {nstail $v}]
set allaliases [list] set allaliases [list]
set allnative [list]
set allensembles [list] set allensembles [list]
set allinterps [list]
set allcoroutines [list]
set allzlibstreams [list]
set allooobjects [list] set allooobjects [list]
set allooclasses [list] set allooclasses [list]
set allooprivateobjects [list]
set allooprivateclasses [list]
set allimported [list] set allimported [list]
set allundetermined [list] set allundetermined [list]
set interp_aliases [interp aliases ""] set interp_aliases [interp aliases ""]
@ -1070,7 +1140,11 @@ namespace eval punk::ns {
# #which_alias hack from wiki relies on trace and executing the command - which we don't want to do. # #which_alias hack from wiki relies on trace and executing the command - which we don't want to do.
# lappend allaliases $cmd # lappend allaliases $cmd
#} #}
set ctype [cmdtype ${location}::$cmd]
switch -- $ctype {
na {
#tcl 8.6 (info cmdtype unavailable)
#todo - use catch tcl::unsupported::corotype to see if coroutine
if {![catch {namespace ensemble configure ${location}::$cmd} ensemble_info]} { if {![catch {namespace ensemble configure ${location}::$cmd} ensemble_info]} {
lappend allensembles $cmd lappend allensembles $cmd
} elseif {[info object isa object ${location}::$cmd]} { } elseif {[info object isa object ${location}::$cmd]} {
@ -1079,7 +1153,6 @@ namespace eval punk::ns {
lappend allooclasses $cmd lappend allooclasses $cmd
} }
} }
if {[catch { if {[catch {
if {$cmd eq ""} { if {$cmd eq ""} {
#empty command was previously marked as "::" - too confusing - nslist updated to properly display empty string. #empty command was previously marked as "::" - too confusing - nslist updated to properly display empty string.
@ -1099,6 +1172,64 @@ namespace eval punk::ns {
} }
} }
} }
default {
if {$ctype eq "imported"} {
set cmdorigin [namespace origin [nsjoin $location $cmd]]
#even if cmd was already imported to another ns and then reimported from there, namespace origin will show the original source
#ie we don't need to follow a chain of 'imported' results.
set mixedtype i-[info cmdtype $cmdorigin]
} else {
set mixedtype $ctype
}
#assert ctype != imported
#review - we don't have a way to mark as both native and ensemble
switch -- $ctype {
i-native - native {
lappend allnative $cmd
}
i-ensemble - ensemble {
lappend allensembles $cmd
}
i-alias - alias {
#review
lappend allaliases $cmd
}
i-object - object {
if {[info object isa object ${location}::$cmd]} {
lappend allooobjects $cmd
if {[info object isa class ${location}::$cmd]} {
lappend allooclasses $cmd
}
}
}
i-privateObject - privateObject {
lappend allooobjects $cmd
lappend allooprivateobjects $cmd
}
i-privateClass - privateClass {
lappend allooobjects $cmd
lappend allooprivateclasses $cmd
}
i-interp - interp {
lappend allinterps $cmd
}
i-coroutine - coroutine {
lappend allcoroutines $cmd
}
i-zlibStream - zlibStream {
lappend allzlibstreams $cmd
}
default {
#there may be other registered types
#(extensible with Tcl_RegisterCommandTypeName)
lappend allothers $cmd
}
}
}
}
}
if {$glob ne "*"} { if {$glob ne "*"} {
set childtailmatches [lsearch -all -inline $childtails $glob] set childtailmatches [lsearch -all -inline $childtails $glob]
#set fqchildren [lmap v $childtailmatches {lindex ${location}::$v}] ;#lindex without indices is fast equivalent of 'val' or string cat #set fqchildren [lmap v $childtailmatches {lindex ${location}::$v}] ;#lindex without indices is fast equivalent of 'val' or string cat
@ -1107,6 +1238,12 @@ namespace eval punk::ns {
set procs [lsearch -all -inline $allprocs $glob] set procs [lsearch -all -inline $allprocs $glob]
#set aliases [lsearch -all -inline $allaliases $glob] #set aliases [lsearch -all -inline $allaliases $glob]
set ensembles [lsearch -all -inline $allensembles $glob] set ensembles [lsearch -all -inline $allensembles $glob]
set native [lsearch -all -inline $allnative $glob]
set coroutines [lsearch -all -inline $allcoroutines $glob]
set interps [lsearch -all -inline $allinterps $glob]
set zlibstreams [lsearch -all -inline $allzlibstreams $glob]
set ooprivateobjects [lsearch -all -inline $allooprivateobjects $glob]
set ooprivateclasses [lsearch -all -inline $allooprivateclasses $glob]
set ooobjects [lsearch -all -inline $allooobjects $glob] set ooobjects [lsearch -all -inline $allooobjects $glob]
set ooclasses [lsearch -all -inline $allooclasses $glob] set ooclasses [lsearch -all -inline $allooclasses $glob]
set imported [lsearch -all -inline $allimported $glob] set imported [lsearch -all -inline $allimported $glob]
@ -1118,8 +1255,14 @@ namespace eval punk::ns {
set procs $allprocs set procs $allprocs
#set aliases $allaliases #set aliases $allaliases
set ensembles $allensembles set ensembles $allensembles
set native $allnative
set coroutines $allcoroutines
set interps $allinterps
set zlibstreams $allzlibstreams
set ooobjects $allooobjects set ooobjects $allooobjects
set ooclasses $allooclasses set ooclasses $allooclasses
set ooprivateobjects $allooprivateobjects
set ooprivateclasses $allooprivateclasses
set imported $allimported set imported $allimported
set undetermined $allundetermined set undetermined $allundetermined
} }
@ -1150,8 +1293,14 @@ namespace eval punk::ns {
imported $imported\ imported $imported\
aliases $aliases\ aliases $aliases\
ensembles $ensembles\ ensembles $ensembles\
native $native\
coroutines $coroutines\
interps $interps\
zlibstreams $zlibstreams\
ooobjects $ooobjects\ ooobjects $ooobjects\
ooclasses $ooclasses\ ooclasses $ooclasses\
ooprivateobjects $ooprivateobjects\
ooprivateclasses $ooprivateclasses\
namespacexport $exportpatterns\ namespacexport $exportpatterns\
undetermined $undetermined\ undetermined $undetermined\
namespacepath $nspathdict\ namespacepath $nspathdict\
@ -1644,9 +1793,10 @@ namespace eval punk::ns {
set argspecs { set argspecs {
-targetnamespace -default "" -optional 1 -targetnamespace -default "" -optional 1
-prefix -default "" -optional 1 -prefix -default "" -optional 1
*values -min 1 -max 1
sourcepattern -type string -optional 0 sourcepattern -type string -optional 0
} }
lassign [punk::args::opts_values $argspecs $args -minvalues 1 -maxvalues 1] _o opts _v values lassign [dict values [punk::args::get_dict $argspecs $args]] opts values
set sourcepattern [dict get $values sourcepattern] set sourcepattern [dict get $values sourcepattern]
set source_ns [namespace qualifiers $sourcepattern] set source_ns [namespace qualifiers $sourcepattern]

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

@ -156,14 +156,17 @@ namespace eval punk::path {
#[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah) #[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah)
#[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter. #[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter.
set defaults [dict create\ set opts [dict create\
-nocase \uFFFF\ -nocase \uFFFF\
] ]
set known_opts [dict keys $defaults] foreach {k v} $args {
set opts [dict merge $defaults $args] switch -- $k {
dict for {k v} $args { -nocase {
if {$k ni $known_opts} { dict set opts $k $v
error "Unrecognised options $k - known options: $known_opts" }
default {
error "Unrecognised option '$k'. Known-options: [dict keys $opts]"
}
} }
} }
# -- --- --- --- --- --- # -- --- --- --- --- ---

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

@ -134,9 +134,13 @@ namespace eval punk::repo {
} }
interp alias "" fossil "" punk::repo::fossil_proxy interp alias "" fossil "" punk::repo::fossil_proxy
#safe interps can't call auto_execok
#At least let them load the package even though much of it may be unusable depending on the safe configuration
catch {
if {[auto_execok fossil] ne ""} { if {[auto_execok fossil] ne ""} {
interp alias "" FOSSIL "" {*}[auto_execok fossil] interp alias "" FOSSIL "" {*}[auto_execok fossil]
} }
}
proc askuser {question} { proc askuser {question} {
if {![catch {package require punk::lib}]} { if {![catch {package require punk::lib}]} {
@ -841,7 +845,7 @@ namespace eval punk::repo {
} }
} }
proc fossil_get_repository_folder_for_project {projectname args} { proc fossil_get_repository_folder_for_project {projectname args} {
set defaults [list\ set opts [list\
-parentfolder \uFFFF\ -parentfolder \uFFFF\
-extrachoices \uFFFF\ -extrachoices \uFFFF\
-askpath 0\ -askpath 0\
@ -852,12 +856,16 @@ namespace eval punk::repo {
if {[llength $args] % 2 != 0} { if {[llength $args] % 2 != 0} {
error "fossil_get_repository_folder requires args to be option-value pairs. Received '$args'" error "fossil_get_repository_folder requires args to be option-value pairs. Received '$args'"
} }
dict for {k v} $args { foreach {k v} $args {
if {$k ni [dict keys $defaults]} { switch -- $k {
error "fossil_get_repository_folder unrecognised option $k. Known options: [dict keys $defaults]" -parentfolder - -extrachoices - -askpath - -ansi - -ansi_prompt - -ansi_warning {
dict set opts $k $v
}
default {
error "fossil_get_repository_folder unrecognised option $k. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_parentfolder [dict get $opts -parentfolder] set opt_parentfolder [dict get $opts -parentfolder]
if {$opt_parentfolder eq "\uFFFF"} { if {$opt_parentfolder eq "\uFFFF"} {

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

@ -1937,7 +1937,7 @@ namespace eval punkcheck {
error "file_record_set_defaults bad file_record: tag not FILEINFO" error "file_record_set_defaults bad file_record: tag not FILEINFO"
} }
set defaults [list -keep_installrecords 3 -keep_skipped 1 -keep_inprogress 2] set defaults [list -keep_installrecords 3 -keep_skipped 1 -keep_inprogress 2]
dict for {k v} $defaults { foreach {k v} $defaults {
if {![dict exists $file_record $k]} { if {![dict exists $file_record $k]} {
dict set file_record $k $v dict set file_record $k $v
} }

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

@ -17,7 +17,6 @@
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements ## Requirements
##e.g package require frobz ##e.g package require frobz
#package require punk
package require punk::args package require punk::args
package require punk::char package require punk::char
package require punk::ansi package require punk::ansi
@ -70,6 +69,23 @@ namespace eval textblock {
-minwidth ""\ -minwidth ""\
-maxwidth ""\ -maxwidth ""\
] ]
variable opts_column_defaults
set opts_column_defaults [dict create\
-headers [list]\
-header_colspans [list]\
-footers [list]\
-defaultvalue ""\
-ansibase ""\
-ansireset "\uFFEF"\
-minwidth ""\
-maxwidth ""\
-blockalign centre\
-textalign left\
]
#initialise -ansireset with replacement char so we can keep in appropriate dict position for initial configure and then treat as read-only
#for 'L' shaped table building pattern (tables bigger than 4x4 will be mostly 'L' patterns) #for 'L' shaped table building pattern (tables bigger than 4x4 will be mostly 'L' patterns)
#ie only vll,blc,hlb used for cells except top row and right column #ie only vll,blc,hlb used for cells except top row and right column
#top right cell uses all 'O' shape, other top cells use 'C' shape (hlt,tlc,vll,blc,hlb) #top right cell uses all 'O' shape, other top cells use 'C' shape (hlt,tlc,vll,blc,hlb)
@ -216,7 +232,17 @@ namespace eval textblock {
# [para] [emph {handler_classes}] # [para] [emph {handler_classes}]
# [list_begin enumerated] # [list_begin enumerated]
oo::class create [namespace current]::table { #this makes new table objects a little faster when multiple opts specified as well as to configure
#as tables are a heavyweight thing, but handy to nest sometimes - we'll take what we can get
set topt_keys [dict keys $::textblock::class::opts_table_defaults]
set switch_keys_valid_topts [punk::lib::lmapflat v $topt_keys {list $v -}]
set switch_keys_valid_topts [lrange $switch_keys_valid_topts 0 end-1] ;#remove last dash
set copt_keys [dict keys $::textblock::class::opts_column_defaults]
set switch_keys_valid_copts [punk::lib::lmapflat v $copt_keys {list $v -}]
set switch_keys_valid_copts [lrange $switch_keys_valid_copts 0 end-1]
oo::class create [namespace current]::table [string map [list %topt_keys% $topt_keys %topt_switchkeys% $switch_keys_valid_topts %copt_keys% $copt_keys %copt_switchkeys% $switch_keys_valid_copts] {
#*** !doctools #*** !doctools
#[enum] CLASS [class interface_caphandler.registry] #[enum] CLASS [class interface_caphandler.registry]
#[list_begin definitions] #[list_begin definitions]
@ -239,26 +265,47 @@ namespace eval textblock {
variable TSUB ;#make configurable so user isn't stopped from using our default PUA-unicode char in content (nerdfonts overlap) variable TSUB ;#make configurable so user isn't stopped from using our default PUA-unicode char in content (nerdfonts overlap)
variable o_calculated_column_widths variable o_calculated_column_widths
variable o_column_width_algorithm variable o_column_width_algorithm
constructor {args} { constructor {args} {
#*** !doctools #*** !doctools
#[call class::table [method constructor] [arg args]] #[call class::table [method constructor] [arg args]]
upvar ::textblock::class::opts_table_defaults tdefaults set o_opts_table_defaults $::textblock::class::opts_table_defaults
set o_opts_table_defaults $tdefaults set o_opts_column_defaults $::textblock::class::opts_column_defaults
if {[llength $args] == 1} { if {[llength $args] == 1} {
set args [list -title [lindex $args 0]] set args [list -title [lindex $args 0]]
} }
if {[llength $args] %2 !=0} { if {[llength $args] %2 !=0} {
error "[namespace current]::table constructor - unexpected argument count. Require single value being title, or name value pairs" error "[namespace current]::table constructor - unexpected argument count. Require single value being title, or name value pairs"
} }
dict for {k v} $args {
if {$k ni [dict keys $o_opts_table_defaults]} { set o_opts_table $o_opts_table_defaults
set o_opts_table_effective $o_opts_table_defaults
##todo - test with punk::lib::show_jump_tables - how?
foreach {k v} $args {
switch -- $k {
%topt_switchkeys% {
dict set o_opts_table $k $v
}
default {
error "[namespace current]::table unrecognised option '$k'. Known values [dict keys $o_opts_table_defaults]" error "[namespace current]::table unrecognised option '$k'. Known values [dict keys $o_opts_table_defaults]"
} }
} }
}
my configure {*}$o_opts_table
#foreach {k v} $args {
# #todo - convert to literal switch using string map so we don't have to define o_opts_table_defaults here.
# if {$k ni [dict keys $o_opts_table_defaults]} {
# error "[namespace current]::table unrecognised option '$k'. Known values [dict keys $o_opts_table_defaults]"
# }
#}
#set o_opts_table [dict merge $o_opts_table_defaults $args] #set o_opts_table [dict merge $o_opts_table_defaults $args]
set o_opts_table $o_opts_table_defaults #my configure {*}[dict merge $o_opts_table_defaults $args]
set o_opts_table_effective $o_opts_table_defaults
my configure {*}[dict merge $o_opts_table_defaults $args]
set o_columndefs [dict create] set o_columndefs [dict create]
set o_columndata [dict create] ;#we store data by column even though it is often added row by row set o_columndata [dict create] ;#we store data by column even though it is often added row by row
set o_columnstates [dict create] ;#store the maxwidthbodyseen etc as we add rows and maxwidthheaderseen etc as we add headers - it is needed often and expensive to calculate repeatedly set o_columnstates [dict create] ;#store the maxwidthbodyseen etc as we add rows and maxwidthheaderseen etc as we add headers - it is needed often and expensive to calculate repeatedly
@ -282,7 +329,7 @@ namespace eval textblock {
return $o_column_width_algorithm return $o_column_width_algorithm
} }
if {$alg ne $o_column_width_algorithm} { if {$alg ne $o_column_width_algorithm} {
#invlidate cached widths #invalidate cached widths
set o_calculated_column_widths [list] set o_calculated_column_widths [list]
} }
set o_column_width_algorithm $alg set o_column_width_algorithm $alg
@ -404,7 +451,7 @@ namespace eval textblock {
return $o_opts_table return $o_opts_table
} }
if {[llength $args] == 1} { if {[llength $args] == 1} {
if {[lindex $args 0] in [dict keys $o_opts_table_defaults]} { if {[lindex $args 0] in [list %topt_keys%]} {
#query single option #query single option
set k [lindex $args 0] set k [lindex $args 0]
set val [dict get $o_opts_table $k] set val [dict get $o_opts_table $k]
@ -428,13 +475,19 @@ namespace eval textblock {
if {[llength $args] %2 != 0} { if {[llength $args] %2 != 0} {
error "[namespace current]::table configure - unexpected argument count. Require name value pairs" error "[namespace current]::table configure - unexpected argument count. Require name value pairs"
} }
dict for {k v} $args { foreach {k v} $args {
if {$k ni [dict keys $o_opts_table_defaults]} { switch -- $k {
%topt_switchkeys% {}
default {
error "[namespace current]::table configure - unrecognised option '$k'. Known values [dict keys $o_opts_table_defaults]" error "[namespace current]::table configure - unrecognised option '$k'. Known values [dict keys $o_opts_table_defaults]"
} }
} }
#if {$k ni [dict keys $o_opts_table_defaults]} {
# error "[namespace current]::table configure - unrecognised option '$k'. Known values [dict keys $o_opts_table_defaults]"
#}
}
set checked_opts [list] set checked_opts [list]
dict for {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-ansibase_header - -ansibase_body - -ansiborder_header - -ansiborder-body - -ansiborder_footer { -ansibase_header - -ansibase_body - -ansiborder_header - -ansiborder-body - -ansiborder_footer {
set parts [punk::ansi::ta::split_codes_single $v] ;#caller may have supplied separated codes eg "[a+ Yellow][a+ red]" set parts [punk::ansi::ta::split_codes_single $v] ;#caller may have supplied separated codes eg "[a+ Yellow][a+ red]"
@ -557,7 +610,7 @@ namespace eval textblock {
#all options checked - ok to update o_opts_table and o_opts_table_effective #all options checked - ok to update o_opts_table and o_opts_table_effective
#set o_opts_table [dict merge $o_opts_table $checked_opts] #set o_opts_table [dict merge $o_opts_table $checked_opts]
dict for {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-framemap_header - -framemap_body { -framemap_header - -framemap_body {
#framemaps don't require setting every key to update. #framemaps don't require setting every key to update.
@ -583,11 +636,12 @@ namespace eval textblock {
switch -- $k { switch -- $k {
-framemap_body - -framemap_header { -framemap_body - -framemap_header {
set existing [dict get $o_opts_table_effective $k] set existing [dict get $o_opts_table_effective $k]
set updated $existing #set updated $existing
dict for {subk subv} $v { #dict for {subk subv} $v {
dict set updated $subk $subv # dict set updated $subk $subv
} #}
dict set o_opts_table_effective $k $updated #dict set o_opts_table_effective $k $updated
dict set o_opts_table_effective $k [dict merge $existing $v]
} }
-framelimits_body - -framelimits_header { -framelimits_body - -framelimits_header {
#my Set_effective_framelimits #my Set_effective_framelimits
@ -641,33 +695,30 @@ namespace eval textblock {
method add_column {args} { method add_column {args} {
#*** !doctools #*** !doctools
#[call class::table [method add_column] [arg args]] #[call class::table [method add_column] [arg args]]
set defaults [dict create\
-headers [list]\
-header_colspans [list]\
-footers [list]\
-defaultvalue ""\
-ansibase ""\
-ansireset "\uFFEF"\
-minwidth ""\
-maxwidth ""\
-blockalign centre\
-textalign left\
]
#initialise -ansireset with replacement char so we can keep in appropriate dict position for initial configure and then treat as read-only
set o_opts_column_defaults $defaults
if {[llength $args] %2 != 0} { if {[llength $args] %2 != 0} {
error "[namespace current]::table::add_column unexpected argument count. Require name value pairs. Known options: [dict keys $defaults]" error "[namespace current]::table::add_column unexpected argument count. Require name value pairs. Known options: %copt_keys%"
}
set opts $o_opts_column_defaults
foreach {k v} $args {
switch -- $k {
%copt_switchkeys% {
dict set opts $k $v
}
default {
error "[namespace current]::table::add_column unknown option '$k'. Known options: %copt_keys%"
} }
dict for {k v} $args {
if {$k ni [dict keys $defaults]} {
error "[namespace current]::table::add_column unknown option '$k'. Known options: [dict keys $defaults]"
} }
} }
set opts [dict merge $defaults $args]
set colcount [dict size $o_columndefs] set colcount [dict size $o_columndefs]
dict set o_columndata $colcount [list] dict set o_columndata $colcount [list]
dict set o_columndefs $colcount $defaults ;#ensure record exists #dict set o_columndefs $colcount $defaults ;#ensure record exists
dict set o_columndefs $colcount $o_opts_column_defaults ;#ensure record exists
dict set o_columnstates $colcount [dict create minwidthbodyseen 0 maxwidthbodyseen 0 maxwidthheaderseen 0] dict set o_columnstates $colcount [dict create minwidthbodyseen 0 maxwidthbodyseen 0 maxwidthheaderseen 0]
set prev_calculated_column_widths $o_calculated_column_widths set prev_calculated_column_widths $o_calculated_column_widths
if {[catch { if {[catch {
@ -707,7 +758,7 @@ namespace eval textblock {
return [dict get $o_columndefs $cidx] return [dict get $o_columndefs $cidx]
} else { } else {
if {[llength $args] == 1} { if {[llength $args] == 1} {
if {[lindex $args 0] in [dict keys $o_opts_column_defaults]} { if {[lindex $args 0] in [list %copt_keys%]} {
#query single option #query single option
set k [lindex $args 0] set k [lindex $args 0]
set val [dict get $o_columndefs $cidx $k] set val [dict get $o_columndefs $cidx $k]
@ -721,23 +772,30 @@ namespace eval textblock {
dict set returndict info $infodict dict set returndict info $infodict
return $returndict return $returndict
} else { } else {
error "textblock::table configure_column - unrecognised option '[lindex $args 0]'. Known values [dict keys $o_opts_column_defaults]" error "textblock::table configure_column - unrecognised option '[lindex $args 0]'. Known values %copt_keys%"
} }
} }
if {[llength $args] %2 != 0} { if {[llength $args] %2 != 0} {
error "textblock::table configure_column unexpected argument count. Require name value pairs. Known options: [dict keys $o_opts_column_defaults]" error "textblock::table configure_column unexpected argument count. Require name value pairs. Known options: %copt_keys%"
} }
dict for {k v} $args { foreach {k v} $args {
if {$k ni [dict keys $o_opts_column_defaults]} { switch -- $k {
error "[namespace current]::table configure_column unknown option '$k'. Known options: [dict keys $o_opts_column_defaults]" %copt_switchkeys% {}
default {
error "[namespace current]::table configure_column unknown option '$k'. Known options: %copt_keys%"
} }
} }
set checked_opts [list] }
set checked_opts [dict get $o_columndefs $cidx] ;#copy of current state
set hstates $o_headerstates ;#operate on a copy set hstates $o_headerstates ;#operate on a copy
set colstate [dict get $o_columnstates $cidx] set colstate [dict get $o_columnstates $cidx]
dict for {k v} $args { set args_got_headers 0
set args_got_header_colspans 0
foreach {k v} $args {
switch -- $k { switch -- $k {
-headers { -headers {
set args_got_headers 1
set i 0 set i 0
set maxseen 0 ;#don't compare with cached colstate maxwidthheaderseen - we have all the headers for the column right here and need to refresh the colstate maxwidthheaderseen values completely. set maxseen 0 ;#don't compare with cached colstate maxwidthheaderseen - we have all the headers for the column right here and need to refresh the colstate maxwidthheaderseen values completely.
foreach hdr $v { foreach hdr $v {
@ -761,9 +819,10 @@ namespace eval textblock {
dict set colstate maxwidthheaderseen $maxseen dict set colstate maxwidthheaderseen $maxseen
#review - we could avoid some recalcs if we check current width range compared to previous #review - we could avoid some recalcs if we check current width range compared to previous
set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed
lappend checked_opts $k $v dict set checked_opts $k $v
} }
-header_colspans { -header_colspans {
set args_got_header_colspans 1
#check columns to left to make sure each new colspan for this column makes sense in the overall context #check columns to left to make sure each new colspan for this column makes sense in the overall context
#user may have to adjust colspans in order left to right to avoid these check errors #user may have to adjust colspans in order left to right to avoid these check errors
#note that 'all' represents span all up to the next non-zero defined colspan. #note that 'all' represents span all up to the next non-zero defined colspan.
@ -835,15 +894,15 @@ namespace eval textblock {
} }
#todo - avoid recalc if no change #todo - avoid recalc if no change
set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed
lappend checked_opts $k $v dict set checked_opts $k $v
} }
-minwidth { -minwidth {
set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed
lappend checked_opts $k $v dict set checked_opts $k $v
} }
-maxwidth { -maxwidth {
set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed set o_calculated_column_widths [list] ;#invalidate cached column widths - a recalc will be forced when needed
lappend checked_opts $k $v dict set checked_opts $k $v
} }
-ansibase { -ansibase {
set parts [punk::ansi::ta::split_codes_single $v] ;#caller may have supplied separated codes eg "[a+ Yellow][a+ red]" set parts [punk::ansi::ta::split_codes_single $v] ;#caller may have supplied separated codes eg "[a+ Yellow][a+ red]"
@ -858,11 +917,11 @@ namespace eval textblock {
} }
} }
set col_ansibase [punk::ansi::codetype::sgr_merge_singles $col_ansibase_items] set col_ansibase [punk::ansi::codetype::sgr_merge_singles $col_ansibase_items]
lappend checked_opts $k $col_ansibase dict set checked_opts $k $col_ansibase
} }
-ansireset { -ansireset {
if {$v eq "\uFFEF"} { if {$v eq "\uFFEF"} {
lappend checked_opts $k "\x1b\[m" ;# [a] dict set checked_opts $k "\x1b\[m" ;# [a]
} else { } else {
error "textblock::table::configure_column -ansireset is read-only. It is present only to prevent unwanted colourised output in configure commands" error "textblock::table::configure_column -ansireset is read-only. It is present only to prevent unwanted colourised output in configure commands"
} }
@ -870,26 +929,25 @@ namespace eval textblock {
-blockalign - -textalign { -blockalign - -textalign {
switch -- $v { switch -- $v {
left - right { left - right {
lappend checked_opts $k $v dict set checked_opts $k $v
} }
centre - centre { centre - centre {
lappend checked_opts $k centre dict set checked_opts $k centre
} }
} }
} }
default { default {
lappend checked_opts $k $v dict set checked_opts $k $v
} }
} }
} }
#args checked - ok to update headerstates and columndefs and columnstates #args checked - ok to update headerstates and columndefs and columnstates
dict set o_columndefs $cidx $checked_opts
set o_headerstates $hstates set o_headerstates $hstates
dict set o_columnstates $cidx $colstate dict set o_columnstates $cidx $colstate
set current_opts [dict get $o_columndefs $cidx] if {$args_got_headers} {
set opts [dict merge $current_opts $checked_opts]
dict set o_columndefs $cidx $opts
if {"-headers" in [dict keys $args]} {
#if the headerlist length for this column has shrunk,and it was the longest - we may now have excess entries in o_headerstates #if the headerlist length for this column has shrunk,and it was the longest - we may now have excess entries in o_headerstates
set zero_heights [list] set zero_heights [list]
dict for {hidx _v} $o_headerstates { dict for {hidx _v} $o_headerstates {
@ -902,7 +960,7 @@ namespace eval textblock {
dict unset o_headerstates $zidx dict unset o_headerstates $zidx
} }
} }
if {"-headers" in [dict keys $args] || "-header_colspans" in [dict keys $args]} { if {$args_got_headers || $args_got_header_colspans} {
#check and adjust header_colspans for all columns #check and adjust header_colspans for all columns
} }
@ -1525,19 +1583,20 @@ namespace eval textblock {
method get_column_by_index {index_expression args} { method get_column_by_index {index_expression args} {
#puts "+++> get_column_by_index $index_expression $args [namespace current]" #puts "+++> get_column_by_index $index_expression $args [namespace current]"
#index_expression may be something like end-1 or 2+2 - we can't directly use it as a lookup for dicts. #index_expression may be something like end-1 or 2+2 - we can't directly use it as a lookup for dicts.
set defaults [dict create\ set opts [dict create\
-position "inner"\ -position "inner"\
-return "string"\ -return "string"\
] ]
dict for {k v} $args { dict for {k v} $args {
switch -- $k { switch -- $k {
-position - -return {} -position - -return {
dict set opts $k $v
}
default { default {
error "[namespace current]::table::get_column_by_index error invalid option '$k'. Known options [dict keys $defaults]" error "[namespace current]::table::get_column_by_index error invalid option '$k'. Known options [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opt_posn [dict get $opts -position] set opt_posn [dict get $opts -position]
set opt_return [dict get $opts -return] set opt_return [dict get $opts -return]
@ -2665,7 +2724,7 @@ namespace eval textblock {
} }
method column_datawidth {index_expression args} { method column_datawidth {index_expression args} {
set defaults [dict create\ set opts [dict create\
-headers 0\ -headers 0\
-footers 0\ -footers 0\
-colspan *\ -colspan *\
@ -2675,13 +2734,14 @@ namespace eval textblock {
#-colspan is relevant to header/footer data only #-colspan is relevant to header/footer data only
dict for {k v} $args { dict for {k v} $args {
switch -- $k { switch -- $k {
-headers - -footers - -colspan - -data - -cached {} -headers - -footers - -colspan - -data - -cached {
dict set opts $k $v
}
default { default {
error "column_datawidth unrecognised flag '$k'. Known flags: [dict keys $defaults]" error "column_datawidth unrecognised flag '$k'. Known flags: [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opt_colspan [dict get $opts -colspan] set opt_colspan [dict get $opts -colspan]
@ -3017,21 +3077,22 @@ namespace eval textblock {
method calculate_column_widths {args} { method calculate_column_widths {args} {
set column_count [dict size $o_columndefs] set column_count [dict size $o_columndefs]
set defaults [dict create\ set opts [dict create\
-algorithm $o_column_width_algorithm\ -algorithm $o_column_width_algorithm\
] ]
dict for {k v} $args { dict for {k v} $args {
switch -- $k { switch -- $k {
-algorithm {} -algorithm {
dict set opts $k $v
}
default { default {
error "Unknown option '$k'. Known options: [dict keys $defaults]" error "Unknown option '$k'. Known options: [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opt_algorithm [dict get $opts -algorithm] set opt_algorithm [dict get $opts -algorithm]
#puts stderr "--- recalculating column widths -algorithm $opt_algorithm" #puts stderr "--- recalculating column widths -algorithm $opt_algorithm"
set known_algorithms [list basic simplistic span] set known_algorithms [list basic simplistic span span2]
switch -- $opt_algorithm { switch -- $opt_algorithm {
basic { basic {
#basic column by column - This allocates extra space to first span/column as they're encountered. #basic column by column - This allocates extra space to first span/column as they're encountered.
@ -3062,7 +3123,7 @@ namespace eval textblock {
set o_calculated_column_widths [dict get $calcresult colwidths] set o_calculated_column_widths [dict get $calcresult colwidths]
} }
default { default {
error "calculate_column_widths unknown algorithm $opt_algorithm" error "calculate_column_widths unknown algorithm $opt_algorithm. Known algorithms: $known_algorithms"
} }
} }
#remember the last algorithm used #remember the last algorithm used
@ -3191,7 +3252,7 @@ namespace eval textblock {
#*** !doctools #*** !doctools
#[list_end] #[list_end]
} }]
#*** !doctools #*** !doctools
# [list_end] [comment {- end enumeration provider_classes }] # [list_end] [comment {- end enumeration provider_classes }]
#[list_end] [comment {- end itemized list textblock::class groupings -}] #[list_end] [comment {- end itemized list textblock::class groupings -}]
@ -3251,20 +3312,21 @@ namespace eval textblock {
#For an impressive interactive terminal app (javascript) #For an impressive interactive terminal app (javascript)
# see: https://github.com/spirometaxas/periodic-table-cli # see: https://github.com/spirometaxas/periodic-table-cli
set defaults [dict create\ set opts [dict create\
-return "string"\ -return "string"\
-compact 1\ -compact 1\
-forcecolour 0\ -forcecolour 0\
] ]
dict for {k v} $args { dict for {k v} $args {
switch -- $k { switch -- $k {
-return - -compact - -forcecolour {} -return - -compact - -forcecolour {
dict set opts $k $v
}
default { default {
"textblock::periodic unknown option '$k'. Known options: [dict keys $defaults]" "textblock::periodic unknown option '$k'. Known options: [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opt_return [dict get $opts -return] set opt_return [dict get $opts -return]
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc forcecolour set fc forcecolour
@ -3291,63 +3353,73 @@ namespace eval textblock {
set ecat [dict create] set ecat [dict create]
set cat_alkaline_earth [list Be Mg Ca Sr Ba Ra] set cat_alkaline_earth [list Be Mg Ca Sr Ba Ra]
set ansi [a+ {*}$fc Web-gold web-black] set ansi [a+ {*}$fc web-black Web-gold]
set val [list ansi $ansi cat alkaline_earth]
foreach e $cat_alkaline_earth { foreach e $cat_alkaline_earth {
dict set ecat $e [list ansi $ansi cat alkaline_earth] dict set ecat $e $val
} }
set cat_reactive_nonmetal [list H C N O F P S Cl Se Br I] set cat_reactive_nonmetal [list H C N O F P S Cl Se Br I]
set ansi [a+ {*}$fc Web-lightgreen web-black] set ansi [a+ {*}$fc web-black Web-lightgreen]
set val [list ansi $ansi cat reactive_nonmetal]
foreach e $cat_reactive_nonmetal { foreach e $cat_reactive_nonmetal {
dict set ecat $e [list ansi $ansi cat reactive_nonmetal] dict set ecat $e $val
} }
set cat [list Li Na K Rb Cs Fr] set cat [list Li Na K Rb Cs Fr]
set ansi [a+ {*}$fc Web-Khaki web-black] set ansi [a+ {*}$fc web-black Web-Khaki]
set val [list ansi $ansi cat alkali_metals]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat alkali_metals] dict set ecat $e $val
} }
set cat [list Sc Ti V Cr Mn Fe Co Ni Cu Zn Y Zr Nb Mo Tc Ru Rh Pd Ag Cd Hf Ta W Re Os Ir Pt Au Hg Rf Db Sg Bh Hs] set cat [list Sc Ti V Cr Mn Fe Co Ni Cu Zn Y Zr Nb Mo Tc Ru Rh Pd Ag Cd Hf Ta W Re Os Ir Pt Au Hg Rf Db Sg Bh Hs]
set ansi [a+ {*}$fc Web-lightsalmon web-black] set ansi [a+ {*}$fc web-black Web-lightsalmon]
set val [list ansi $ansi cat transition_metals]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat transition_metals] dict set ecat $e $val
} }
set cat [list Al Ga In Sn Tl Pb Bi Po] set cat [list Al Ga In Sn Tl Pb Bi Po]
set ansi [a+ {*}$fc Web-lightskyblue web-black] set ansi [a+ {*}$fc web-black Web-lightskyblue]
set val [list ansi $ansi cat post_transition_metals]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat post_transition_metals] dict set ecat $e $val
} }
set cat [list B Si Ge As Sb Te At] set cat [list B Si Ge As Sb Te At]
set ansi [a+ {*}$fc Web-turquoise web-black] set ansi [a+ {*}$fc web-black Web-turquoise]
set val [list ansi $ansi cat metalloids]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat metalloids] dict set ecat $e $val
} }
set cat [list He Ne Ar Kr Xe Rn] set cat [list He Ne Ar Kr Xe Rn]
set ansi [a+ {*}$fc Web-orchid web-black] set ansi [a+ {*}$fc web-black Web-orchid]
set val [list ansi $ansi cat noble_gases]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat noble_gases] dict set ecat $e $val
} }
set cat [list Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr] set cat [list Ac Th Pa U Np Pu Am Cm Bk Cf Es Fm Md No Lr]
set ansi [a+ {*}$fc Web-plum web-black] set ansi [a+ {*}$fc web-black Web-plum]
set val [list ansi $ansi cat actinoids]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat actinoids] dict set ecat $e $val
} }
set cat [list La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu] set cat [list La Ce Pr Nd Pm Sm Eu Gd Tb Dy Ho Er Tm Yb Lu]
set ansi [a+ {*}$fc Web-tan web-black] set ansi [a+ {*}$fc web-black Web-tan]
set val [list ansi $ansi cat lanthanoids]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat lanthanoids] dict set ecat $e $val
} }
set cat [list Mt Ds Rg Cn Nh Fl Mc Lv Ts Og] set cat [list Mt Ds Rg Cn Nh Fl Mc Lv Ts Og]
set ansi [a+ {*}$fc Web-whitesmoke web-black] set ansi [a+ {*}$fc web-black Web-whitesmoke]
set val [list ansi $ansi cat other]
foreach e $cat { foreach e $cat {
dict set ecat $e [list ansi $ansi cat other] dict set ecat $e $val
} }
set elements1 [list] set elements1 [list]
@ -3372,25 +3444,24 @@ namespace eval textblock {
$t configure_column $c -headers [list $h] -minwidth 2 $t configure_column $c -headers [list $h] -minwidth 2
incr c incr c
} }
for {set c 0} {$c < [$t column_count]} {incr c} { set ccount [$t column_count]
for {set c 0} {$c < $ccount} {incr c} {
$t configure_column $c -minwidth 3 $t configure_column $c -minwidth 3
} }
if {[dict get $opts -compact]} { if {[dict get $opts -compact]} {
$t configure -show_hseps 0 $t configure -show_hseps 0 -show_header 0 -show_edge 0
$t configure -show_header 0
$t configure -show_edge 0
} else { } else {
$t configure -show_header 1 $t configure -show_header 1
} }
if {$opt_return eq "string"} { if {$opt_return eq "string"} {
$t configure -frametype_header light $t configure \
$t configure -ansiborder_header [a+ {*}$fc web-white] -frametype_header light\
$t configure -ansibase_header [a+ {*}$fc Web-black] -ansiborder_header [a+ {*}$fc web-white]\
$t configure -ansibase_body [a+ {*}$fc Web-black] -ansibase_header [a+ {*}$fc Web-black]\
$t configure -ansiborder_body [a+ {*}$fc web-black] -ansibase_body [a+ {*}$fc Web-black]\
$t configure -frametype block -ansiborder_body [a+ {*}$fc web-black]\
-frametype block
set output [textblock::frame -ansiborder [a+ {*}$fc Web-black web-cornflowerblue] -type heavy -title "[a+ {*}$fc Web-black] Periodic Table " [$t print]] set output [textblock::frame -ansiborder [a+ {*}$fc Web-black web-cornflowerblue] -type heavy -title "[a+ {*}$fc Web-black] Periodic Table " [$t print]]
return $output return $output
@ -3398,7 +3469,6 @@ namespace eval textblock {
return $t return $t
} }
proc list_as_table {table_or_colcount datalist args} { proc list_as_table {table_or_colcount datalist args} {
set defaults [dict create\ set defaults [dict create\
-return string\ -return string\
@ -3406,15 +3476,17 @@ namespace eval textblock {
-show_edge \uFFEF\ -show_edge \uFFEF\
-show_seps \uFFEF\ -show_seps \uFFEF\
] ]
set opts $defaults
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-return - -show_edge - -show_seps - -frametype {} -return - -show_edge - -show_seps - -frametype {
dict set opts $k $v
}
default { default {
error "unrecognised option '$k'. Known options [dict keys $defaults]" error "unrecognised option '$k'. Known options [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set count [llength $datalist] set count [llength $datalist]
@ -3555,7 +3627,7 @@ namespace eval textblock {
set chars [concat [punk::range 1 9] A B C D E F] set chars [concat [punk::lib::range 1 9] A B C D E F]
set charsubset [lrange $chars 0 $size-1] set charsubset [lrange $chars 0 $size-1]
if {"noreset" in $colour} { if {"noreset" in $colour} {
set RST "" set RST ""
@ -3725,7 +3797,7 @@ namespace eval textblock {
#pipealias ::textblock::padright .= {list $input [string repeat " " $colsize]} |/0,padding/1> punk::lib::lines_as_list -- |> .= {lmap v $data {overtype::left $padding $v}} |> punk::lib::list_as_lines -- <input/0,colsize/1| #pipealias ::textblock::padright .= {list $input [string repeat " " $colsize]} |/0,padding/1> punk::lib::lines_as_list -- |> .= {lmap v $data {overtype::left $padding $v}} |> punk::lib::list_as_lines -- <input/0,colsize/1|
proc ::textblock::pad {block args} { proc ::textblock::pad {block args} {
set defaults [dict create\ set opts [dict create\
-padchar " "\ -padchar " "\
-which "right"\ -which "right"\
-width ""\ -width ""\
@ -3738,13 +3810,14 @@ namespace eval textblock {
set usage "pad ?-padchar <sp>|<character>? ?-which right|left|centre? ?-width auto|<int>? ?-within_ansi 1|0?" set usage "pad ?-padchar <sp>|<character>? ?-which right|left|centre? ?-width auto|<int>? ?-within_ansi 1|0?"
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-padchar - -which - -width - -overflow - -within_ansi {} -padchar - -which - -width - -overflow - -within_ansi {
dict set opts $k $v
}
default { default {
error "textblock::pad unrecognised option '$k'. Usage: $usage" error "textblock::pad unrecognised option '$k'. Usage: $usage"
} }
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- ---
set padchar [dict get $opts -padchar] set padchar [dict get $opts -padchar]
#if padchar width (screen width) > 1 - length calculations will not be correct #if padchar width (screen width) > 1 - length calculations will not be correct
@ -4001,19 +4074,20 @@ namespace eval textblock {
} }
proc pad_test_blocklist {blocklist args} { proc pad_test_blocklist {blocklist args} {
set defaults [dict create\ set opts [dict create\
-description ""\ -description ""\
-blockheaders ""\ -blockheaders ""\
] ]
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-description - -blockheaders {} -description - -blockheaders {
dict set opts $k $v
}
default { default {
error "pad_test_blocklist unrecognised option '$k'. Known options: [dict keys $defaults]" error "pad_test_blocklist unrecognised option '$k'. Known options: [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opt_blockheaders [dict get $opts -blockheaders] set opt_blockheaders [dict get $opts -blockheaders]
set bheaders [dict create] set bheaders [dict create]
if {$opt_blockheaders ne ""} { if {$opt_blockheaders ne ""} {
@ -4148,7 +4222,7 @@ namespace eval textblock {
proc ::textblock::join1 {args} { proc ::textblock::join1 {args} {
lassign [punk::args::opts_values { lassign [punk::args::get_dict {
-ansiresets -default 1 -type integer -ansiresets -default 1 -type integer
blocks -type string -multiple 1 blocks -type string -multiple 1
} $args] _o opts _v values } $args] _o opts _v values
@ -4175,10 +4249,11 @@ namespace eval textblock {
#for joining 'rendered' blocks of plain or ansi text. Being 'rendered' means they are without ansi movement sequences as these have been processed #for joining 'rendered' blocks of plain or ansi text. Being 'rendered' means they are without ansi movement sequences as these have been processed
#they may however still be 'ragged' ie differing line lengths #they may however still be 'ragged' ie differing line lengths
proc ::textblock::join {args} { proc ::textblock::join {args} {
#lassign [punk::lib::opts_values { #set argd [punk::args::get_dict {
# blocks -type string -multiple 1 # blocks -type string -multiple 1
#} $args] _o opts _v values #} $args]
#set blocks [dict get $values blocks] #set opts [dict get $argd opts]
#set blocks [dict get $argd values blocks]
#-ansireplays is always on (if ansi detected) #-ansireplays is always on (if ansi detected)
@ -4212,8 +4287,8 @@ namespace eval textblock {
set fordata [list] set fordata [list]
set colindices [list] set colindices [list]
foreach b $blocks { foreach b $blocks {
set c($idx) [string repeat " " [width $b]]
set w($idx) [width $b] ;#we need the width of a rendered block for per-row renderline calls set w($idx) [width $b] ;#we need the width of a rendered block for per-row renderline calls
#set c($idx) [string repeat " " [set w($idx)]]
#fairly commonly a block may be a vertical list of chars e.g something like 1\n2\n3 or -\n-\n-\n- #fairly commonly a block may be a vertical list of chars e.g something like 1\n2\n3 or -\n-\n-\n-
#for determining a shortcut to avoid unnecessary ta::detect - (e.g width <=1) we can't use result of textblock::width as it strips ansi. #for determining a shortcut to avoid unnecessary ta::detect - (e.g width <=1) we can't use result of textblock::width as it strips ansi.
#testing of any decent size block line by line - even with max_string_length_line is slower than ta::detect anyway. #testing of any decent size block line by line - even with max_string_length_line is slower than ta::detect anyway.
@ -4254,16 +4329,17 @@ namespace eval textblock {
# >} punk::lib::list_as_lines <lhs/0,rhs/1| # >} punk::lib::list_as_lines <lhs/0,rhs/1|
proc example {args} { proc example {args} {
set defaults {-forcecolour 0} set opts [dict create -forcecolour 0]
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-forcecolour {} -forcecolour {
dict set opts $k $v
}
default { default {
error "textblock::example unrecognised option '$k'. Known-options: [dict keys $defaults]" error "textblock::example unrecognised option '$k'. Known-options: [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opt_forcecolour 0 set opt_forcecolour 0
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc forcecolour set fc forcecolour
@ -4381,7 +4457,7 @@ namespace eval textblock {
set is_custom_dict_ok 1 set is_custom_dict_ok 1
if {[llength $f] %2 == 0} { if {[llength $f] %2 == 0} {
#custom dict may leave out keys - but cannot have unknown keys #custom dict may leave out keys - but cannot have unknown keys
dict for {k v} $f { foreach {k v} $f {
switch -- $k { switch -- $k {
hl - hlt - hlb - vl - vll - vlr - tlc - trc - blc - brc {} hl - hlt - hlb - vl - vll - vlr - tlc - trc - blc - brc {}
default { default {
@ -4414,19 +4490,20 @@ namespace eval textblock {
if {[dict exists $framedef_cache $cache_key]} { if {[dict exists $framedef_cache $cache_key]} {
return [dict get $framedef_cache $cache_key] return [dict get $framedef_cache $cache_key]
} }
set defaults [dict create\ set opts [dict create\
-joins ""\ -joins ""\
-boxonly 0\ -boxonly 0\
] ]
dict for {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-joins - -boxonly {} -joins - -boxonly {
dict set opts $k $v
}
default { default {
error "framedef unknown option '$k'. Known options [dict keys $args]" error "framedef unknown option '$k'. Known options [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set joins [dict get $opts -joins] set joins [dict get $opts -joins]
set boxonly [dict get $opts -boxonly] set boxonly [dict get $opts -boxonly]
@ -5639,7 +5716,7 @@ namespace eval textblock {
} }
#todo args -justify left|centre|right (center) #todo args -justify left|centre|right (center)
set defaults [dict create\ set opts [dict create\
-etabs 0\ -etabs 0\
-type light\ -type light\
-boxlimits [list hl vl tlc blc trc brc]\ -boxlimits [list hl vl tlc blc trc brc]\
@ -5659,12 +5736,13 @@ namespace eval textblock {
] ]
#todo -blockalignbias -textalignbias? #todo -blockalignbias -textalignbias?
#use -buildcache 1 with -usecache 0 for debugging cache issues so we can inspect using textblock::frame_cache #use -buildcache 1 with -usecache 0 for debugging cache issues so we can inspect using textblock::frame_cache
set opts [dict merge $defaults $arglist] foreach {k v} $arglist {
foreach {k v} $opts {
switch -- $k { switch -- $k {
-etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache {} -etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache {
dict set opts $k $v
}
default { default {
error "frame option '$k' not understood. Valid options are [dict keys $defaults]" error "frame option '$k' not understood. Valid options are [dict keys $opts]"
} }
} }
} }
@ -5856,7 +5934,7 @@ namespace eval textblock {
#set cache_key [concat $arglist $frame_inner_width $frame_inner_height] #set cache_key [concat $arglist $frame_inner_width $frame_inner_height]
set hashables [concat $arglist $frame_inner_width $frame_inner_height] set hashables [concat $arglist $frame_inner_width $frame_inner_height]
package require md5 package require md5
set hash [md5::md5 -hex $hashables] set hash [md5::md5 -hex $hashables] ;#need fast and unique to content - not cryptographic - review
set cache_key "$hash-$frame_inner_width-$frame_inner_height-actualcontentwidth:$actual_contentwidth" set cache_key "$hash-$frame_inner_width-$frame_inner_height-actualcontentwidth:$actual_contentwidth"
#should be in a unicode private range different to that used in table construction #should be in a unicode private range different to that used in table construction
#e.g BMP PUA U+E000 -> U+F8FF - although this is commonly used for example by nerdfonts #e.g BMP PUA U+E000 -> U+F8FF - although this is commonly used for example by nerdfonts
@ -5875,13 +5953,13 @@ namespace eval textblock {
#this occurs commonly in table building with colspans - review #this occurs commonly in table building with colspans - review
if {$actual_contentwidth > $frame_inner_width || $actual_contentheight != $frame_inner_height} { if {($actual_contentwidth > $frame_inner_width) || ($actual_contentheight != $frame_inner_height)} {
set usecache 0 set usecache 0
#set buildcache 0 ;#comment out for debug/analysis so we can see #set buildcache 0 ;#comment out for debug/analysis so we can see
#puts "--->> frame_inner_width:$frame_inner_width actual_contentwidth:$actual_contentwidth contents: '$contents'" #puts "--->> frame_inner_width:$frame_inner_width actual_contentwidth:$actual_contentwidth contents: '$contents'"
set cache_key [a+ Web-red web-white]$cache_key[a] set cache_key [a+ Web-red web-white]$cache_key[a]
} }
if {$buildcache && $actual_contentwidth < $frame_inner_width} { if {$buildcache && ($actual_contentwidth < $frame_inner_width)} {
#colourise cache_key to warn #colourise cache_key to warn
if {$actual_contentwidth == 0} { if {$actual_contentwidth == 0} {
#we can still substitute with right length #we can still substitute with right length
@ -5891,7 +5969,7 @@ namespace eval textblock {
if {[dict exists $frame_cache $cache_key]} { if {[dict exists $frame_cache $cache_key]} {
set cache_patternwidth [dict get $frame_cache $cache_key patternwidth] set cache_patternwidth [dict get $frame_cache $cache_key patternwidth]
} else { } else {
set cache_patternwidth [$actual_contentwidth] set cache_patternwidth $actual_contentwidth
} }
if {$actual_contentwidth < $cache_patternwidth} { if {$actual_contentwidth < $cache_patternwidth} {
set usecache 0 set usecache 0

318
src/embedded/man/files/_module_argparsingtest-0.1.0.tm.n

@ -0,0 +1,318 @@
'\"
'\" Generated from file '_module_argparsingtest-0\&.1\&.0\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2024
'\"
.TH "shellspy_module_argparsingtest" 0 0\&.1\&.0 doc "-"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\" Start paragraph describing an argument to a library procedure.
.\" type is type of argument (int, etc.), in/out is either "in", "out",
.\" or "in/out" to describe whether procedure reads or modifies arg,
.\" and indent is equivalent to second arg of .IP (shouldn't ever be
.\" needed; use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\" Give maximum sizes of arguments for setting tab stops. Type and
.\" name are examples of largest possible arguments that will be passed
.\" to .AP later. If args are omitted, default tab stops are used.
.\"
.\" .BS
.\" Start box enclosure. From here until next .BE, everything will be
.\" enclosed in one large box.
.\"
.\" .BE
.\" End of box enclosure.
.\"
.\" .CS
.\" Begin code excerpt.
.\"
.\" .CE
.\" End code excerpt.
.\"
.\" .VS ?version? ?br?
.\" Begin vertical sidebar, for use in marking newly-changed parts
.\" of man pages. The first argument is ignored and used for recording
.\" the version when the .VS was added, so that the sidebars can be
.\" found and removed when they reach a certain age. If another argument
.\" is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\" End of vertical sidebar.
.\"
.\" .DS
.\" Begin an indented unfilled display.
.\"
.\" .DE
.\" End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\" Start of list of standard options for a Tk widget. The manpage
.\" argument defines where to look up the standard options; if
.\" omitted, defaults to "options". The options follow on successive
.\" lines, in three columns separated by tabs.
.\"
.\" .SE
.\" End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\" Start of description of a specific option. cmdName gives the
.\" option's name as specified in the class command, dbName gives
.\" the option's name in the option database, and dbClass gives
.\" the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\" Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\" Print an open parenthesis, arg1 in quotes, then arg2 normally
.\" (for trailing punctuation) and then a closing parenthesis.
.\"
.\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
. ie !"\\$2"" .TP \\n()Cu
. el .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1 \\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\" # define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # VS - start vertical sidebar
.\" # ^Y = starting y location
.\" # ^v = 1 (for troff; for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\" # VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\" # Special macro to handle page bottom: finish off current
.\" # box/sidebar if in box/sidebar mode, then invoked standard
.\" # page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\" Draw three-sided box if this is the box's first page,
.\" draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\" # DS - begin display
.de DS
.RS
.nf
.sp
..
.\" # DE - end display
.de DE
.fi
.RE
.sp
..
.\" # SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\" # SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\" # OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name: \\fB\\$1\\fR
Database Name: \\fB\\$2\\fR
Database Class: \\fB\\$3\\fR
.fi
.IP
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.\" # UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\" # QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\" # PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\" # QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\" # MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
shellspy_module_argparsingtest \- Module API
.SH SYNOPSIS
package require \fBargparsingtest \fR
.sp
.BE
.SH DESCRIPTION
.PP
-
.SH OVERVIEW
.PP
overview of argparsingtest
.SS CONCEPTS
.PP
-
.SS DEPENDENCIES
.PP
packages used by argparsingtest
.IP \(bu
\fBTcl 8\&.6\fR
.PP
.SH API
.SS "NAMESPACE ARGPARSINGTEST::CLASS"
.PP
class definitions
.PP
.SS "NAMESPACE ARGPARSINGTEST"
.PP
Core API functions for argparsingtest
.PP
.SS "NAMESPACE ARGPARSINGTEST::LIB"
.PP
Secondary functions that are part of the API
.PP
.SH INTERNAL
.SS "NAMESPACE ARGPARSINGTEST::SYSTEM"
.PP
Internal functions that are not part of the API
.SH KEYWORDS
module
.SH COPYRIGHT
.nf
Copyright (c) 2024
.fi

354
src/embedded/man/files/_module_overtype-1.6.3.tm.n

@ -0,0 +1,354 @@
'\"
'\" Generated from file '_module_overtype-1\&.6\&.3\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2024
'\"
.TH "overtype_module_overtype" 0 1\&.6\&.3 doc "overtype text layout"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\" Start paragraph describing an argument to a library procedure.
.\" type is type of argument (int, etc.), in/out is either "in", "out",
.\" or "in/out" to describe whether procedure reads or modifies arg,
.\" and indent is equivalent to second arg of .IP (shouldn't ever be
.\" needed; use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\" Give maximum sizes of arguments for setting tab stops. Type and
.\" name are examples of largest possible arguments that will be passed
.\" to .AP later. If args are omitted, default tab stops are used.
.\"
.\" .BS
.\" Start box enclosure. From here until next .BE, everything will be
.\" enclosed in one large box.
.\"
.\" .BE
.\" End of box enclosure.
.\"
.\" .CS
.\" Begin code excerpt.
.\"
.\" .CE
.\" End code excerpt.
.\"
.\" .VS ?version? ?br?
.\" Begin vertical sidebar, for use in marking newly-changed parts
.\" of man pages. The first argument is ignored and used for recording
.\" the version when the .VS was added, so that the sidebars can be
.\" found and removed when they reach a certain age. If another argument
.\" is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\" End of vertical sidebar.
.\"
.\" .DS
.\" Begin an indented unfilled display.
.\"
.\" .DE
.\" End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\" Start of list of standard options for a Tk widget. The manpage
.\" argument defines where to look up the standard options; if
.\" omitted, defaults to "options". The options follow on successive
.\" lines, in three columns separated by tabs.
.\"
.\" .SE
.\" End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\" Start of description of a specific option. cmdName gives the
.\" option's name as specified in the class command, dbName gives
.\" the option's name in the option database, and dbClass gives
.\" the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\" Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\" Print an open parenthesis, arg1 in quotes, then arg2 normally
.\" (for trailing punctuation) and then a closing parenthesis.
.\"
.\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
. ie !"\\$2"" .TP \\n()Cu
. el .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1 \\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\" # define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # VS - start vertical sidebar
.\" # ^Y = starting y location
.\" # ^v = 1 (for troff; for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\" # VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\" # Special macro to handle page bottom: finish off current
.\" # box/sidebar if in box/sidebar mode, then invoked standard
.\" # page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\" Draw three-sided box if this is the box's first page,
.\" draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\" # DS - begin display
.de DS
.RS
.nf
.sp
..
.\" # DE - end display
.de DE
.fi
.RE
.sp
..
.\" # SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\" # SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\" # OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name: \\fB\\$1\\fR
Database Name: \\fB\\$2\\fR
Database Class: \\fB\\$3\\fR
.fi
.IP
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.\" # UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\" # QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\" # PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\" # QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\" # MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
overtype_module_overtype \- overtype text layout - ansi aware
.SH SYNOPSIS
package require \fBovertype \fR
.sp
\fBovertype::renderspace\fR \fIargs\fR
.sp
\fBovertype::renderline\fR \fIargs\fR
.sp
.BE
.SH DESCRIPTION
.PP
-
.SH OVERVIEW
.PP
overview of overtype
.SS CONCEPTS
.PP
-
.SS DEPENDENCIES
.PP
packages used by overtype
.IP \(bu
\fBTcl 8\&.6\fR
.IP \(bu
\fBtextutil\fR
.IP \(bu
\fBpunk::ansi\fR
.sp
- required to detect, split, strip and calculate lengths of text possibly containing ansi codes
.IP \(bu
\fBpunk::char\fR
.sp
- box drawing - and also unicode character width determination for proper layout of text with double-column-width chars
.PP
.SH API
.SS "NAMESPACE OVERTYPE"
.PP
Core API functions for overtype
.TP
\fBovertype::renderspace\fR \fIargs\fR
.sp
usage: ?-transparent [0|1]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext \&.\&.\&.? undertext overtext
.TP
\fBovertype::renderline\fR \fIargs\fR
.sp
renderline is the core engine for overtype string processing (frames & textblocks), and the raw mode commandline repl for the Tcl Punk Shell
.sp
It is also a central part of an ansi (micro) virtual terminal-emulator of sorts
.sp
This system does a half decent job at rendering 90's ANSI art to manipulable colour text blocks that can be joined & framed for layout display within a unix or windows terminal
.sp
Renderline helps maintain ANSI text styling reset/replay codes so that the styling of one block doesn't affect another\&.
.sp
Calling on the punk::ansi library - it can coalesce codes to keep the size down\&.
.sp
It is a giant mess of doing exactly what common wisdom says not to do\&.\&.\&. lots at once\&.
.sp
renderline is part of the Unicode and ANSI aware Overtype system which 'renders' a block of text onto a static underlay
.sp
The underlay is generally expected to be an ordered set of lines or a rectangular text block analogous to a terminal screen - but it can also be ragged in line length, or just blank\&.
.sp
The overlay couuld be similar - in which case it may often be used to overwrite a column or section of the underlay\&.
.sp
The overlay could however be a sequence of ANSI-laden text that jumps all over the place\&.
.sp
renderline itself only deals with a single line - or sometimes a single character\&. It is generally called from a loop that does further terminal-like or textblock processing\&.
.sp
By suppyling the -info 1 option - it can return various fields indicating the state of the render\&.
.sp
The main 3 are the result, overflow_right, and unapplied\&.
.sp
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\&.
.PP
.SH KEYWORDS
ansi, module, text
.SH COPYRIGHT
.nf
Copyright (c) 2024
.fi

318
src/embedded/man/files/punk/_module_aliascore-0.1.0.tm.n

@ -0,0 +1,318 @@
'\"
'\" Generated from file '_module_aliascore-0\&.1\&.0\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2024
'\"
.TH "shellspy_module_punk::aliascore" 0 0\&.1\&.0 doc "-"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\" Start paragraph describing an argument to a library procedure.
.\" type is type of argument (int, etc.), in/out is either "in", "out",
.\" or "in/out" to describe whether procedure reads or modifies arg,
.\" and indent is equivalent to second arg of .IP (shouldn't ever be
.\" needed; use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\" Give maximum sizes of arguments for setting tab stops. Type and
.\" name are examples of largest possible arguments that will be passed
.\" to .AP later. If args are omitted, default tab stops are used.
.\"
.\" .BS
.\" Start box enclosure. From here until next .BE, everything will be
.\" enclosed in one large box.
.\"
.\" .BE
.\" End of box enclosure.
.\"
.\" .CS
.\" Begin code excerpt.
.\"
.\" .CE
.\" End code excerpt.
.\"
.\" .VS ?version? ?br?
.\" Begin vertical sidebar, for use in marking newly-changed parts
.\" of man pages. The first argument is ignored and used for recording
.\" the version when the .VS was added, so that the sidebars can be
.\" found and removed when they reach a certain age. If another argument
.\" is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\" End of vertical sidebar.
.\"
.\" .DS
.\" Begin an indented unfilled display.
.\"
.\" .DE
.\" End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\" Start of list of standard options for a Tk widget. The manpage
.\" argument defines where to look up the standard options; if
.\" omitted, defaults to "options". The options follow on successive
.\" lines, in three columns separated by tabs.
.\"
.\" .SE
.\" End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\" Start of description of a specific option. cmdName gives the
.\" option's name as specified in the class command, dbName gives
.\" the option's name in the option database, and dbClass gives
.\" the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\" Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\" Print an open parenthesis, arg1 in quotes, then arg2 normally
.\" (for trailing punctuation) and then a closing parenthesis.
.\"
.\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
. ie !"\\$2"" .TP \\n()Cu
. el .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1 \\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\" # define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # VS - start vertical sidebar
.\" # ^Y = starting y location
.\" # ^v = 1 (for troff; for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\" # VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\" # Special macro to handle page bottom: finish off current
.\" # box/sidebar if in box/sidebar mode, then invoked standard
.\" # page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\" Draw three-sided box if this is the box's first page,
.\" draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\" # DS - begin display
.de DS
.RS
.nf
.sp
..
.\" # DE - end display
.de DE
.fi
.RE
.sp
..
.\" # SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\" # SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\" # OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name: \\fB\\$1\\fR
Database Name: \\fB\\$2\\fR
Database Class: \\fB\\$3\\fR
.fi
.IP
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.\" # UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\" # QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\" # PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\" # QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\" # MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
shellspy_module_punk::aliascore \- Module API
.SH SYNOPSIS
package require \fBpunk::aliascore \fR
.sp
.BE
.SH DESCRIPTION
.PP
-
.SH OVERVIEW
.PP
overview of punk::aliascore
.SS CONCEPTS
.PP
-
.SS DEPENDENCIES
.PP
packages used by punk::aliascore
.IP \(bu
\fBTcl 8\&.6\fR
.PP
.SH API
.SS "NAMESPACE PUNK::ALIASCORE::CLASS"
.PP
class definitions
.PP
.SS "NAMESPACE PUNK::ALIASCORE"
.PP
Core API functions for punk::aliascore
.PP
.SS "NAMESPACE PUNK::ALIASCORE::LIB"
.PP
Secondary functions that are part of the API
.PP
.SH INTERNAL
.SS "NAMESPACE PUNK::ALIASCORE::SYSTEM"
.PP
Internal functions that are not part of the API
.SH KEYWORDS
module
.SH COPYRIGHT
.nf
Copyright (c) 2024
.fi

25
src/embedded/man/files/punk/_module_ansi-0.1.1.tm.n

@ -286,8 +286,6 @@ package require \fBpunk::ansi \fR
.sp .sp
\fBa\fR ?ansicode\&.\&.\&.? \fBa\fR ?ansicode\&.\&.\&.?
.sp .sp
\fBa\fR ?ansicode\&.\&.\&.?
.sp
\fBget_code_name\fR \fIcode\fR \fBget_code_name\fR \fIcode\fR
.sp .sp
\fBreset\fR \fBreset\fR
@ -430,6 +428,13 @@ Return a string with ansi codes stripped out
Alternate graphics modes will be stripped - exposing the raw characters as they appear without graphics mode\&. Alternate graphics modes will be stripped - exposing the raw characters as they appear without graphics mode\&.
.sp .sp
ie instead of a horizontal line you may see: qqqqqq ie instead of a horizontal line you may see: qqqqqq
e\&.g who is to know that 'Rabbit Paws', 'Forbidden Thrill' and 'Tarsier' refer to a particular shade of pinky-red? (code 95)
Perhaps it's an indication that colour naming once we get to 256 colours or more is a fool's errand anyway\&.
The xterm names are boringly unimaginative - and also have some oddities such as:
DarkSlateGray1 which looks much more like cyan\&.\&.
The greyxx names are spelt with an e - but the darkslategrayX variants use an a\&. Perhaps that's because they are more cyan than grey and the a is a hint?
there is no gold or gold2 - but there is gold1 and gold3
but in general the names bear some resemblance to the colours and are at least somewhat intuitive\&.
.TP .TP
\fBa?\fR ?ansicode\&.\&.\&.? \fBa?\fR ?ansicode\&.\&.\&.?
.sp .sp
@ -465,22 +470,6 @@ punk::ansi::a Red
.sp .sp
see \fBpunk::ansi::a?\fR to display a list of codes see \fBpunk::ansi::a?\fR to display a list of codes
.TP .TP
\fBa\fR ?ansicode\&.\&.\&.?
.sp
Returns the ansi code to reset any current settings and apply those from the supplied list
.sp
by calling punk::ansi::a with no arguments - the result is a reset to plain text
.sp
e\&.g to set foreground red and bold
.sp
punk::ansi::a red bold
.sp
to set background red
.sp
punk::ansi::a Red
.sp
see \fBpunk::ansi::a?\fR to display a list of codes
.TP
\fBget_code_name\fR \fIcode\fR \fBget_code_name\fR \fIcode\fR
.sp .sp
for example for example

156
src/embedded/man/files/punk/_module_args-0.1.0.tm.n

@ -276,7 +276,7 @@ punkshell_module_punk::args \- args parsing
.SH SYNOPSIS .SH SYNOPSIS
package require \fBpunk::args \fR package require \fBpunk::args \fR
.sp .sp
\fBopts_values\fR \fIoptionspecs\fR \fIrawargs\fR ?option value\&.\&.\&.? \fBget_dict\fR \fIoptionspecs\fR \fIrawargs\fR ?option value\&.\&.\&.?
.sp .sp
.BE .BE
.SH DESCRIPTION .SH DESCRIPTION
@ -290,13 +290,15 @@ overview of punk::args
There are 2 main conventions for parsing a proc args list There are 2 main conventions for parsing a proc args list
.IP [1] .IP [1]
.sp .sp
leading option-value pairs followed by a list of values (Tk style) leading option-value pairs followed by a list of values (Tcl style)
.IP [2] .IP [2]
.sp .sp
leading list of values followed by option-value pairs (Tcl style) leading list of values followed by option-value pairs (Tk style)
.PP .PP
.PP .PP
punk::args is focused on the 1st convention (Tk style): parsing of args in leading option-value pair style - even for non-Tk usage\&. There are exceptions in both Tcl and Tk commands regarding this ordering
.PP
punk::args is focused on the 1st convention (Tcl style): parsing of the 'args' variable in leading option-value pair style
.PP .PP
The proc can still contain some leading required values e\&.g The proc can still contain some leading required values e\&.g
.CS .CS
@ -304,7 +306,8 @@ The proc can still contain some leading required values e\&.g
proc dostuff {arg1 arg2 args} {\&.\&.\&.}} proc dostuff {arg1 arg2 args} {\&.\&.\&.}}
.CE .CE
.PP .PP
but having the core values elements at the end of args is more generally useful - especially in cases where the number of trailing values is unknown and/or the proc is to be called in a functional 'pipeline' style\&. but having the core values elements at the end of args is arguably more generally useful - especially in cases where the number of trailing values is unknown and/or the proc is to be called in a functional 'pipeline' style\&.
.PP
.PP .PP
The basic principle is that a call to punk::args::opts_vals is made near the beginning of the proc e\&.g The basic principle is that a call to punk::args::opts_vals is made near the beginning of the proc e\&.g
.CS .CS
@ -312,8 +315,14 @@ The basic principle is that a call to punk::args::opts_vals is made near the beg
proc dofilestuff {args} { proc dofilestuff {args} {
lassign [dict values [punk::args { lassign [dict values [punk::args {
*proc -help "do some stuff with files e\&.g dofilestuff <file1> <file2> <file3>"
*opts -type string
#comment lines ok
-directory -default "" -directory -default ""
-translation -default binary -translation -default binary
#setting -type none indicates a flag that doesn't take a value (solo flag)
-nocomplain -type none
*values -min 1 -max -1
} $args]] opts values } $args]] opts values
puts "translation is [dict get $opts -translation]" puts "translation is [dict get $opts -translation]"
@ -322,18 +331,124 @@ The basic principle is that a call to punk::args::opts_vals is made near the beg
} }
} }
.CE
.PP
The lines beginning with * are optional in most cases and can be used to set defaults and some extra controls
.PP
- the above example would work just fine with only the -<optionname> lines, but would allow zero filenames to be supplied as no -min value is set for *values
.PP
valid * lines being with *proc *opts *values
.PP
lines beginning with a dash define options - a name can optionally be given to each trailing positional argument\&.
.PP
If no names are defined for positional arguments, they will end up in the values key of the dict with numerical keys starting at zero\&.
.PP
e\&.g the result from the punk::args call above may be something like:
.PP
opts {-translation binary -directory "" -nocomplain 0} values {0 file1\&.txt 1 file2\&.txt 2 file3\&.txt}
.PP
Here is an example that requires the number of values supplied to be exactly 2 and names the positional arguments
.PP
It also demonstrates an inital argument 'category' that is outside of the scope for punk::args processing - allowing leading and trailing positional arguments
.CS
proc dofilestuff {category args} {
lassign [dict values [punk::args {
-directory -default ""
-translation -default binary
-nocomplain -type none
*values -min 2 -max 2
fileA -existingfile 1
fileB -existingfile 1
} $args]] opts values
puts "$category fileA: [dict get $values fileA]"
puts "$category fileB: [dict get $values fileB]"
}
.CE
.PP
By using standard tcl proc named arguments prior to args, and setting *values -min 0 -max 0
.PP
a Tk-style ordering can be acheived, where punk::args is only handling the trailing flags and the values element of the returned dict can be ignored
.PP
This use of leading positional arguments means the type validation features can't be applied to them\&. It can be done manually as usual,
.PP
or an additional call could be made to punk::args e\&.g
.CS
punk::args {
category -choices {cat1 cat2 cat3}
another_leading_arg -type boolean
} [list $category $another_leading_arg]
.CE .CE
.SS NOTES .SS NOTES
.PP .PP
There are alternative args parsing packages such as: For internal functions not requiring features such as solo flags, prefix matching, type checking etc - a well crafted switch statement will be the fastest pure-tcl solution\&.
.PP
When functions are called often and/or in inner loops, a switch based solution generally makes the most sense\&.
For functions that are part of an API a package may be more suitable\&.
.PP
The following example shows a switch-based solution that is highly performant (sub microsecond for the no-args case)
.CS
proc test1_switch {args} {
set opts [dict create\\
-return "object"\\
-frametype "heavy"\\
-show_edge 1\\
-show_seps 0\\
-x a\\
-y b\\
-z c\\
-1 1\\
-2 2\\
-3 3\\
]
foreach {k v} $args {
switch -- $k {
-return - -show_edge - -show_seps - -frametype - -x - -y - -z - -1 - -2 - -3 {
dict set opts $k $v
}
default {
error "unrecognised option '$k'\&. Known options [dict keys $opts]"
}
}
}
return $opts
}
.CE
.PP
Note that the switch statement uses literals so that the compiler produces a jump-table for best performance\&.
.PP
Attempting to build the switch branch using the values from dict keys $opts will stop the jump table being built\&.
To create the faster switch statement without repeating the key names, the proc body would need to be built using string map\&.
.PP
use punk::lib::show_jump_tables <procname> to verify that a jump table exists\&.
.PP
There are many alternative args parsing packages a few of which are listed here\&.
.IP [1] .IP [1]
argp argp (pure tcl)
.IP [2] .IP [2]
The tcllib set of TEPAM modules parse_args (c implementation)
.IP [3]
argparse (pure tcl *)
.IP [4]
cmdline (pure tcl)
.IP [5]
opt (pure tcl) distributed with Tcl but considered deprecated
.IP [6]
The tcllib set of TEPAM modules (pure tcl)
.sp .sp
TEPAM requires an alternative procedure declaration syntax instead of proc - but has support for Tk and documentation generation\&. TEPAM requires an alternative procedure declaration syntax instead of proc - but has support for Tk and documentation generation\&.
.PP .PP
.PP .PP
(* c implementation planned/proposed)
.PP
punk::args was designed initially without specific reference to TEPAM - and to handle some edge cases in specific projects where TEPAM wasn't suitable\&. punk::args was designed initially without specific reference to TEPAM - and to handle some edge cases in specific projects where TEPAM wasn't suitable\&.
.PP .PP
In subsequent revisions of punk::args - some features were made to operate in a way that is similar to TEPAM - to avoid gratuitous differences where possible, but of course there are differences In subsequent revisions of punk::args - some features were made to operate in a way that is similar to TEPAM - to avoid gratuitous differences where possible, but of course there are differences
@ -342,7 +457,11 @@ and those used TEPAM or mixing TEPAM and punk::args should take care to assess t
.PP .PP
TEPAM is a mature solution and is widely available as it is included in tcllib\&. TEPAM is a mature solution and is widely available as it is included in tcllib\&.
.PP .PP
Serious consideration should be given to using TEPAM if suitable for your project\&. Serious consideration should be given to using TEPAM or one of the other packages, if suitable for your project\&.
.PP
punk::args is relatively performant for a pure-tcl solution - with the parsing of the argument specification block occuring only on the first run - after which a cached version of the spec is used\&.
.PP
punk::args is not limited to procs\&. It can be used in apply or coroutine situations for example\&.
.SS DEPENDENCIES .SS DEPENDENCIES
.PP .PP
packages used by punk::args packages used by punk::args
@ -358,7 +477,7 @@ class definitions
.PP .PP
Core API functions for punk::args Core API functions for punk::args
.TP .TP
\fBopts_values\fR \fIoptionspecs\fR \fIrawargs\fR ?option value\&.\&.\&.? \fBget_dict\fR \fIoptionspecs\fR \fIrawargs\fR ?option value\&.\&.\&.?
.sp .sp
Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values
.sp .sp
@ -373,15 +492,28 @@ This a block of text with records delimited by newlines (lf or crlf) - but with
.sp .sp
\'info complete' is used to determine if a record spans multiple lines due to multiline values \'info complete' is used to determine if a record spans multiple lines due to multiline values
.sp .sp
Each optionspec line must be of the form: Each optionspec line defining a flag must be of the form:
.sp .sp
-optionname -key val -key2 val2\&.\&.\&. -optionname -key val -key2 val2\&.\&.\&.
.sp .sp
where the valid keys for each option specification are: -default -type -range -choices -optional where the valid keys for each option specification are: -default -type -range -choices -optional
.sp
Each optionspec line defining a positional argument is of the form:
.sp
argumentname -key val -ky2 val2\&.\&.\&.
.sp
where the valid keys for each option specification are: -default -type -range -choices
.sp
comment lines begining with # are ignored and can be placed anywhere except within a multiline value where it would become part of that value
.sp
lines beginning with *proc *opts or *values also take -key val pairs and can be used to set defaults and control settings\&.
.sp
*opts or *values lines can appear multiple times with defaults affecting flags/values that follow\&.
.TP .TP
list \fIrawargs\fR list \fIrawargs\fR
.sp .sp
This is a list of the arguments to parse\&. Usually it will be the \\$args value from the containing proc This is a list of the arguments to parse\&. Usually it will be the $args value from the containing proc,
but it could be a manually constructed list of values made for example from positional args defined in the proc\&.
.RE .RE
.sp .sp
.PP .PP

490
src/embedded/man/files/punk/_module_island-0.1.0.tm.n

@ -0,0 +1,490 @@
'\"
'\" Generated from file '_module_island-0\&.1\&.0\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2024
'\"
.TH "shellspy_module_punk::island" 0 0\&.1\&.0 doc "punk::island for safe interps"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\" Start paragraph describing an argument to a library procedure.
.\" type is type of argument (int, etc.), in/out is either "in", "out",
.\" or "in/out" to describe whether procedure reads or modifies arg,
.\" and indent is equivalent to second arg of .IP (shouldn't ever be
.\" needed; use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\" Give maximum sizes of arguments for setting tab stops. Type and
.\" name are examples of largest possible arguments that will be passed
.\" to .AP later. If args are omitted, default tab stops are used.
.\"
.\" .BS
.\" Start box enclosure. From here until next .BE, everything will be
.\" enclosed in one large box.
.\"
.\" .BE
.\" End of box enclosure.
.\"
.\" .CS
.\" Begin code excerpt.
.\"
.\" .CE
.\" End code excerpt.
.\"
.\" .VS ?version? ?br?
.\" Begin vertical sidebar, for use in marking newly-changed parts
.\" of man pages. The first argument is ignored and used for recording
.\" the version when the .VS was added, so that the sidebars can be
.\" found and removed when they reach a certain age. If another argument
.\" is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\" End of vertical sidebar.
.\"
.\" .DS
.\" Begin an indented unfilled display.
.\"
.\" .DE
.\" End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\" Start of list of standard options for a Tk widget. The manpage
.\" argument defines where to look up the standard options; if
.\" omitted, defaults to "options". The options follow on successive
.\" lines, in three columns separated by tabs.
.\"
.\" .SE
.\" End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\" Start of description of a specific option. cmdName gives the
.\" option's name as specified in the class command, dbName gives
.\" the option's name in the option database, and dbClass gives
.\" the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\" Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\" Print an open parenthesis, arg1 in quotes, then arg2 normally
.\" (for trailing punctuation) and then a closing parenthesis.
.\"
.\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
. ie !"\\$2"" .TP \\n()Cu
. el .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1 \\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\" # define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # VS - start vertical sidebar
.\" # ^Y = starting y location
.\" # ^v = 1 (for troff; for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\" # VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\" # Special macro to handle page bottom: finish off current
.\" # box/sidebar if in box/sidebar mode, then invoked standard
.\" # page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\" Draw three-sided box if this is the box's first page,
.\" draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\" # DS - begin display
.de DS
.RS
.nf
.sp
..
.\" # DE - end display
.de DE
.fi
.RE
.sp
..
.\" # SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\" # SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\" # OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name: \\fB\\$1\\fR
Database Name: \\fB\\$2\\fR
Database Class: \\fB\\$3\\fR
.fi
.IP
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.\" # UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\" # QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\" # PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\" # QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\" # MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
shellspy_module_punk::island \- filesystem islands for safe interps
.SH SYNOPSIS
package require \fBpunk::island \fR
.sp
\fBadd\fR \fIchild\fR \fIpath\fR
.sp
\fBreset\fR \fIchild\fR
.sp
\fBAllowed\fR \fIchild\fR \fIfname\fR
.sp
\fBFile\fR \fIchild\fR \fIcmd\fR \fIargs\fR
.sp
\fBOpen\fR \fIchild\fR \fIargs\fR
.sp
\fBExpose\fR \fIchild\fR \fIcmd\fR \fIargs\fR
.sp
\fBGlob\fR \fIchild\fR \fIargs\fR
.sp
\fBInit\fR \fIchild\fR
.sp
.BE
.SH DESCRIPTION
.PP
Package to a allow a safe interpreter to access islands of the
.PP
filesystem only, i\&.e\&. restricted directory trees within the
.PP
filesystem\&. The package brings back file, open and glob to the child interp
.PP
interpreter, though in a restricted manner\&.
.PP
JN Warning:
.PP
This mechanism can have interactions with package loading from auto_path - needs review\&.
.SH OVERVIEW
.PP
overview of punk::island
.SS CONCEPTS
.PP
-
.SS DEPENDENCIES
.PP
packages used by punk::island
.IP \(bu
\fBTcl 8\&.6\fR
.PP
.SH API
.SS "NAMESPACE PUNK::ISLAND::CLASS"
.PP
class definitions
.PP
.SS "NAMESPACE PUNK::ISLAND::INTERPS"
.PP
hosts information for interpreters
.PP
.SS "NAMESPACE PUNK::ISLAND"
.PP
Core API functions for punk::island
.TP
\fBadd\fR \fIchild\fR \fIpath\fR
.sp
Add a path to the list of paths that are explicitely allowed for access
.sp
to a child interpreter\&. Access to any path that has not been explicitely
.sp
allowed will be denied\&. Paths that are added to the list of allowed
.sp
islands are always fully normalized\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter to control
.RE
.TP
\fBreset\fR \fIchild\fR
.sp
Remove all access path allowance and arrange for the interpreter to be
.sp
able to return to the regular safe state\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter
.RE
.PP
.SS "NAMESPACE PUNK::ISLAND::LIB"
.PP
Secondary functions that are part of the API
.PP
.SH INTERNAL
.SS "NAMESPACE PUNK::ISLAND::SYSTEM"
.PP
Internal functions that are not part of the API
.TP
\fBAllowed\fR \fIchild\fR \fIfname\fR
.sp
Check that the file name passed as an argument is within the islands of
.sp
the filesystem that have been registered through the add command for a
.sp
given (safe) interpreter\&. The path is fully normalized before testing
.sp
against the islands, which themselves are fully normalized\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter
.TP
string \fIfname\fR
(relative) path to the file to test
.RE
.TP
\fBFile\fR \fIchild\fR \fIcmd\fR \fIargs\fR
.sp
Parses the options and arguments to the file command to discover which
.sp
paths it tries to access and only return the results of its execution
.sp
when these path are within the allowed islands of the filesystem\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter
.TP
string \fIcmd\fR
Subcommand of the file command
.TP
string \fIargs\fR
Arguments to the file subcommand
.RE
.TP
\fBOpen\fR \fIchild\fR \fIargs\fR
.sp
Parses the options and arguments to the open command to discover which
.sp
paths it tries to access and only return the results of its execution
.sp
when these path are within the allowed islands of the filesystem\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter
.TP
string \fIargs\fR
Arguments to the open subcommand
.RE
.TP
\fBExpose\fR \fIchild\fR \fIcmd\fR \fIargs\fR
.sp
This procedure allows to callback a command that would typically have
.sp
been hidden from a child interpreter\&. It does not "interp expose" but
.sp
rather calls the hidden command, so we can easily revert back\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter
.TP
string \fIcmd\fR
Hidden command to call
.TP
string \fIargs\fR
Arguments to the command
.RE
.TP
\fBGlob\fR \fIchild\fR \fIargs\fR
.sp
Parses the options and arguments to the glob command to discover which
.sp
paths it tries to access and only return the results of its execution
.sp
when these path are within the allowed islands of the filesystem\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter
.TP
string \fIargs\fR
Arguments to the glob command
.RE
.TP
\fBInit\fR \fIchild\fR
.sp
Initialise child interpreter so that it will be able to perform some
.sp
file operations, but only within some islands of the filesystem\&.
.sp
Arguments:
.RS
.TP
string \fIchild\fR
Identifier of the child interpreter
.RE
.PP
.SH KEYWORDS
filesystem, interp, module
.SH COPYRIGHT
.nf
Copyright (c) 2024
.fi

31
src/embedded/man/files/punk/_module_lib-0.1.1.tm.n

@ -330,8 +330,6 @@ package require \fBpunk::lib \fR
.sp .sp
\fBlines_as_list\fR ?option value \&.\&.\&.? \fItext\fR \fBlines_as_list\fR ?option value \&.\&.\&.? \fItext\fR
.sp .sp
\fBopts_values\fR ?option value\&.\&.\&.? \fIoptionspecs\fR \fIrawargs\fR
.sp
.BE .BE
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
@ -395,7 +393,7 @@ lindex_resolve will parse the index expression and return -1 if the supplied ind
.sp .sp
Otherwise it will return an integer corresponding to the position in the list\&. Otherwise it will return an integer corresponding to the position in the list\&.
.sp .sp
Like Tcl list commands - it will produce an error if the form of the Like Tcl list commands - it will produce an error if the form of the index is not acceptable
.TP .TP
\fBK\fR \fIx\fR \fIy\fR \fBK\fR \fIx\fR \fIy\fR
.sp .sp
@ -625,33 +623,6 @@ Returns a list of possibly trimmed lines depeding on options
The concept of lines is raw lines from splitting on newline after crlf is mapped to lf The concept of lines is raw lines from splitting on newline after crlf is mapped to lf
.sp .sp
- not console lines which may be entirely different due to control characters such as vertical tabs or ANSI movements - not console lines which may be entirely different due to control characters such as vertical tabs or ANSI movements
.TP
\fBopts_values\fR ?option value\&.\&.\&.? \fIoptionspecs\fR \fIrawargs\fR
.sp
Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values
.sp
Returns a dict of the form: opts <options_dict> values <values_dict>
.sp
ARGUMENTS:
.RS
.TP
multiline-string \fIoptionspecs\fR
.sp
This a block of text with records delimited by newlines (lf or crlf) - but with multiline values allowed if properly quoted/braced
.sp
\'info complete' is used to determine if a record spans multiple lines due to multiline values
.sp
Each optionspec line must be of the form:
.sp
-optionname -key val -key2 val2\&.\&.\&.
.sp
where the valid keys for each option specification are: -default -type -range -choices -optional
.TP
list \fIrawargs\fR
.sp
This is a list of the arguments to parse\&. Usually it will be the \\$args value from the containing proc
.RE
.sp
.PP .PP
.SH INTERNAL .SH INTERNAL
.SS "NAMESPACE PUNK::LIB::SYSTEM" .SS "NAMESPACE PUNK::LIB::SYSTEM"

318
src/embedded/man/files/punk/repl/_module_codethread-0.1.0.tm.n

@ -0,0 +1,318 @@
'\"
'\" Generated from file '_module_codethread-0\&.1\&.0\&.tm\&.man' by tcllib/doctools with format 'nroff'
'\" Copyright (c) 2024
'\"
.TH "shellspy_module_punk::repl::codethread" 0 0\&.1\&.0 doc "-"
.\" The -*- nroff -*- definitions below are for supplemental macros used
.\" in Tcl/Tk manual entries.
.\"
.\" .AP type name in/out ?indent?
.\" Start paragraph describing an argument to a library procedure.
.\" type is type of argument (int, etc.), in/out is either "in", "out",
.\" or "in/out" to describe whether procedure reads or modifies arg,
.\" and indent is equivalent to second arg of .IP (shouldn't ever be
.\" needed; use .AS below instead)
.\"
.\" .AS ?type? ?name?
.\" Give maximum sizes of arguments for setting tab stops. Type and
.\" name are examples of largest possible arguments that will be passed
.\" to .AP later. If args are omitted, default tab stops are used.
.\"
.\" .BS
.\" Start box enclosure. From here until next .BE, everything will be
.\" enclosed in one large box.
.\"
.\" .BE
.\" End of box enclosure.
.\"
.\" .CS
.\" Begin code excerpt.
.\"
.\" .CE
.\" End code excerpt.
.\"
.\" .VS ?version? ?br?
.\" Begin vertical sidebar, for use in marking newly-changed parts
.\" of man pages. The first argument is ignored and used for recording
.\" the version when the .VS was added, so that the sidebars can be
.\" found and removed when they reach a certain age. If another argument
.\" is present, then a line break is forced before starting the sidebar.
.\"
.\" .VE
.\" End of vertical sidebar.
.\"
.\" .DS
.\" Begin an indented unfilled display.
.\"
.\" .DE
.\" End of indented unfilled display.
.\"
.\" .SO ?manpage?
.\" Start of list of standard options for a Tk widget. The manpage
.\" argument defines where to look up the standard options; if
.\" omitted, defaults to "options". The options follow on successive
.\" lines, in three columns separated by tabs.
.\"
.\" .SE
.\" End of list of standard options for a Tk widget.
.\"
.\" .OP cmdName dbName dbClass
.\" Start of description of a specific option. cmdName gives the
.\" option's name as specified in the class command, dbName gives
.\" the option's name in the option database, and dbClass gives
.\" the option's class in the option database.
.\"
.\" .UL arg1 arg2
.\" Print arg1 underlined, then print arg2 normally.
.\"
.\" .QW arg1 ?arg2?
.\" Print arg1 in quotes, then arg2 normally (for trailing punctuation).
.\"
.\" .PQ arg1 ?arg2?
.\" Print an open parenthesis, arg1 in quotes, then arg2 normally
.\" (for trailing punctuation) and then a closing parenthesis.
.\"
.\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages.
.if t .wh -1.3i ^B
.nr ^l \n(.l
.ad b
.\" # Start an argument description
.de AP
.ie !"\\$4"" .TP \\$4
.el \{\
. ie !"\\$2"" .TP \\n()Cu
. el .TP 15
.\}
.ta \\n()Au \\n()Bu
.ie !"\\$3"" \{\
\&\\$1 \\fI\\$2\\fP (\\$3)
.\".b
.\}
.el \{\
.br
.ie !"\\$2"" \{\
\&\\$1 \\fI\\$2\\fP
.\}
.el \{\
\&\\fI\\$1\\fP
.\}
.\}
..
.\" # define tabbing values for .AP
.de AS
.nr )A 10n
.if !"\\$1"" .nr )A \\w'\\$1'u+3n
.nr )B \\n()Au+15n
.\"
.if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n
.nr )C \\n()Bu+\\w'(in/out)'u+2n
..
.AS Tcl_Interp Tcl_CreateInterp in/out
.\" # BS - start boxed text
.\" # ^y = starting y location
.\" # ^b = 1
.de BS
.br
.mk ^y
.nr ^b 1u
.if n .nf
.if n .ti 0
.if n \l'\\n(.lu\(ul'
.if n .fi
..
.\" # BE - end boxed text (draw box now)
.de BE
.nf
.ti 0
.mk ^t
.ie n \l'\\n(^lu\(ul'
.el \{\
.\" Draw four-sided box normally, but don't draw top of
.\" box if the box started on an earlier page.
.ie !\\n(^b-1 \{\
\h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.el \}\
\h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul'
.\}
.\}
.fi
.br
.nr ^b 0
..
.\" # VS - start vertical sidebar
.\" # ^Y = starting y location
.\" # ^v = 1 (for troff; for nroff this doesn't matter)
.de VS
.if !"\\$2"" .br
.mk ^Y
.ie n 'mc \s12\(br\s0
.el .nr ^v 1u
..
.\" # VE - end of vertical sidebar
.de VE
.ie n 'mc
.el \{\
.ev 2
.nf
.ti 0
.mk ^t
\h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n'
.sp -1
.fi
.ev
.\}
.nr ^v 0
..
.\" # Special macro to handle page bottom: finish off current
.\" # box/sidebar if in box/sidebar mode, then invoked standard
.\" # page bottom macro.
.de ^B
.ev 2
'ti 0
'nf
.mk ^t
.if \\n(^b \{\
.\" Draw three-sided box if this is the box's first page,
.\" draw two sides but no top otherwise.
.ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c
.\}
.if \\n(^v \{\
.nr ^x \\n(^tu+1v-\\n(^Yu
\kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c
.\}
.bp
'fi
.ev
.if \\n(^b \{\
.mk ^y
.nr ^b 2
.\}
.if \\n(^v \{\
.mk ^Y
.\}
..
.\" # DS - begin display
.de DS
.RS
.nf
.sp
..
.\" # DE - end display
.de DE
.fi
.RE
.sp
..
.\" # SO - start of list of standard options
.de SO
'ie '\\$1'' .ds So \\fBoptions\\fR
'el .ds So \\fB\\$1\\fR
.SH "STANDARD OPTIONS"
.LP
.nf
.ta 5.5c 11c
.ft B
..
.\" # SE - end of list of standard options
.de SE
.fi
.ft R
.LP
See the \\*(So manual entry for details on the standard options.
..
.\" # OP - start of full description for a single option
.de OP
.LP
.nf
.ta 4c
Command-Line Name: \\fB\\$1\\fR
Database Name: \\fB\\$2\\fR
Database Class: \\fB\\$3\\fR
.fi
.IP
..
.\" # CS - begin code excerpt
.de CS
.RS
.nf
.ta .25i .5i .75i 1i
..
.\" # CE - end code excerpt
.de CE
.fi
.RE
..
.\" # UL - underline word
.de UL
\\$1\l'|0\(ul'\\$2
..
.\" # QW - apply quotation marks to word
.de QW
.ie '\\*(lq'"' ``\\$1''\\$2
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\$2
..
.\" # PQ - apply parens and quotation marks to word
.de PQ
.ie '\\*(lq'"' (``\\$1''\\$2)\\$3
.\"" fix emacs highlighting
.el (\\*(lq\\$1\\*(rq\\$2)\\$3
..
.\" # QR - quoted range
.de QR
.ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3
.\"" fix emacs highlighting
.el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3
..
.\" # MT - "empty" string
.de MT
.QW ""
..
.BS
.SH NAME
shellspy_module_punk::repl::codethread \- Module API
.SH SYNOPSIS
package require \fBpunk::repl::codethread \fR
.sp
.BE
.SH DESCRIPTION
.PP
-
.SH OVERVIEW
.PP
overview of punk::repl::codethread
.SS CONCEPTS
.PP
-
.SS DEPENDENCIES
.PP
packages used by punk::repl::codethread
.IP \(bu
\fBTcl 8\&.6\fR
.PP
.SH API
.SS "NAMESPACE PUNK::REPL::CODETHREAD::CLASS"
.PP
class definitions
.PP
.SS "NAMESPACE PUNK::REPL::CODETHREAD"
.PP
Core API functions for punk::repl::codethread
.PP
.SS "NAMESPACE PUNK::REPL::CODETHREAD::LIB"
.PP
Secondary functions that are part of the API
.PP
.SH INTERNAL
.SS "NAMESPACE PUNK::REPL::CODETHREAD::SYSTEM"
.PP
Internal functions that are not part of the API
.SH KEYWORDS
module
.SH COPYRIGHT
.nf
Copyright (c) 2024
.fi

30
src/embedded/man/index.n

@ -284,6 +284,9 @@ ansi
\fBfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR \fBfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR
overtype_module_overtype overtype_module_overtype
.TP .TP
\fBfiles/_module_overtype-1\&.6\&.3\&.tm\&.n\fR
overtype_module_overtype
.TP
\fBfiles/punk/_module_ansi-0\&.1\&.1\&.tm\&.n\fR \fBfiles/punk/_module_ansi-0\&.1\&.1\&.tm\&.n\fR
punkshell_module_punk::ansi punkshell_module_punk::ansi
.RE .RE
@ -367,6 +370,15 @@ filesystem
.TP .TP
\fBfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR \fBfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::path punkshell_module_punk::path
.TP
\fBfiles/punk/_module_island-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::island
.RE
interp
.RS
.TP
\fBfiles/punk/_module_island-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::island
.RE .RE
lib lib
.RS .RS
@ -380,6 +392,9 @@ module
\fBfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR \fBfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR
overtype_module_overtype overtype_module_overtype
.TP .TP
\fBfiles/_module_overtype-1\&.6\&.3\&.tm\&.n\fR
overtype_module_overtype
.TP
\fBfiles/punk/_module_ansi-0\&.1\&.1\&.tm\&.n\fR \fBfiles/punk/_module_ansi-0\&.1\&.1\&.tm\&.n\fR
punkshell_module_punk::ansi punkshell_module_punk::ansi
.TP .TP
@ -407,12 +422,24 @@ punkshell_module_punk::lib
\fBfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR \fBfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::path punkshell_module_punk::path
.TP .TP
\fBfiles/_module_argparsingtest-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_argparsingtest
.TP
\fBfiles/punk/_module_aliascore-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::aliascore
.TP
\fBfiles/punk/_module_assertion-0\&.1\&.0\&.tm\&.n\fR \fBfiles/punk/_module_assertion-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::assertion shellspy_module_punk::assertion
.TP .TP
\fBfiles/punk/_module_basictelnet-0\&.1\&.0\&.tm\&.n\fR \fBfiles/punk/_module_basictelnet-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::basictelnet shellspy_module_punk::basictelnet
.TP .TP
\fBfiles/punk/_module_island-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::island
.TP
\fBfiles/punk/repl/_module_codethread-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::repl::codethread
.TP
\fBfiles/punk/_module_sshrun-0\&.1\&.0\&.tm\&.n\fR \fBfiles/punk/_module_sshrun-0\&.1\&.0\&.tm\&.n\fR
shellspy_module_punk::sshrun shellspy_module_punk::sshrun
.TP .TP
@ -506,6 +533,9 @@ text
\fBfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR \fBfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR
overtype_module_overtype overtype_module_overtype
.TP .TP
\fBfiles/_module_overtype-1\&.6\&.3\&.tm\&.n\fR
overtype_module_overtype
.TP
\fBfiles/punk/_module_fileline-0\&.1\&.0\&.tm\&.n\fR \fBfiles/punk/_module_fileline-0\&.1\&.0\&.tm\&.n\fR
punkshell_module_punk::fileline punkshell_module_punk::fileline
.RE .RE

15
src/embedded/man/toc.n

@ -276,6 +276,9 @@ doc
\fBovertype_module_overtype\fR \fBovertype_module_overtype\fR
\fIfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR: overtype text layout - ansi aware \fIfiles/_module_overtype-1\&.6\&.2\&.tm\&.n\fR: overtype text layout - ansi aware
.TP .TP
\fBovertype_module_overtype\fR
\fIfiles/_module_overtype-1\&.6\&.3\&.tm\&.n\fR: overtype text layout - ansi aware
.TP
\fBpunkshell\fR \fBpunkshell\fR
\fIfiles/main\&.n\fR: punkshell - Core \fIfiles/main\&.n\fR: punkshell - Core
.TP .TP
@ -315,12 +318,24 @@ doc
\fBpunkshell_module_punk::path\fR \fBpunkshell_module_punk::path\fR
\fIfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR: Filesystem path utilities \fIfiles/punk/_module_path-0\&.1\&.0\&.tm\&.n\fR: Filesystem path utilities
.TP .TP
\fBshellspy_module_argparsingtest\fR
\fIfiles/_module_argparsingtest-0\&.1\&.0\&.tm\&.n\fR: Module API
.TP
\fBshellspy_module_punk::aliascore\fR
\fIfiles/punk/_module_aliascore-0\&.1\&.0\&.tm\&.n\fR: Module API
.TP
\fBshellspy_module_punk::assertion\fR \fBshellspy_module_punk::assertion\fR
\fIfiles/punk/_module_assertion-0\&.1\&.0\&.tm\&.n\fR: assertion alternative to control::assert \fIfiles/punk/_module_assertion-0\&.1\&.0\&.tm\&.n\fR: assertion alternative to control::assert
.TP .TP
\fBshellspy_module_punk::basictelnet\fR \fBshellspy_module_punk::basictelnet\fR
\fIfiles/punk/_module_basictelnet-0\&.1\&.0\&.tm\&.n\fR: basic telnet client - DKF/Wiki \fIfiles/punk/_module_basictelnet-0\&.1\&.0\&.tm\&.n\fR: basic telnet client - DKF/Wiki
.TP .TP
\fBshellspy_module_punk::island\fR
\fIfiles/punk/_module_island-0\&.1\&.0\&.tm\&.n\fR: filesystem islands for safe interps
.TP
\fBshellspy_module_punk::repl::codethread\fR
\fIfiles/punk/repl/_module_codethread-0\&.1\&.0\&.tm\&.n\fR: Module API
.TP
\fBshellspy_module_punk::sshrun\fR \fBshellspy_module_punk::sshrun\fR
\fIfiles/punk/_module_sshrun-0\&.1\&.0\&.tm\&.n\fR: Tcl procedures to execute tcl scripts in remote hosts \fIfiles/punk/_module_sshrun-0\&.1\&.0\&.tm\&.n\fR: Tcl procedures to execute tcl scripts in remote hosts
.TP .TP

5
src/embedded/md/.doc/tocdoc

@ -1,5 +1,6 @@
[toc_begin {Table Of Contents} doc] [toc_begin {Table Of Contents} doc]
[item doc/files/_module_overtype-1.6.2.tm.md overtype_module_overtype {overtype text layout - ansi aware}] [item doc/files/_module_overtype-1.6.2.tm.md overtype_module_overtype {overtype text layout - ansi aware}]
[item doc/files/_module_overtype-1.6.3.tm.md overtype_module_overtype {overtype text layout - ansi aware}]
[item doc/files/main.md punkshell {punkshell - Core}] [item doc/files/main.md punkshell {punkshell - Core}]
[item doc/files/project_changes.md punkshell__project_changes {punkshell Changes}] [item doc/files/project_changes.md punkshell__project_changes {punkshell Changes}]
[item doc/files/project_intro.md punkshell__project_intro {Introduction to punkshell}] [item doc/files/project_intro.md punkshell__project_intro {Introduction to punkshell}]
@ -13,8 +14,12 @@
[item doc/files/punk/_module_lib-0.1.1.tm.md punkshell_module_punk::lib {punk general utility functions}] [item doc/files/punk/_module_lib-0.1.1.tm.md punkshell_module_punk::lib {punk general utility functions}]
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punkshell_module_punk::mix::commandset::project {dec commandset - project}] [item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punkshell_module_punk::mix::commandset::project {dec commandset - project}]
[item doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path {Filesystem path utilities}] [item doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path {Filesystem path utilities}]
[item doc/files/_module_argparsingtest-0.1.0.tm.md shellspy_module_argparsingtest {Module API}]
[item doc/files/punk/_module_aliascore-0.1.0.tm.md shellspy_module_punk::aliascore {Module API}]
[item doc/files/punk/_module_assertion-0.1.0.tm.md shellspy_module_punk::assertion {assertion alternative to control::assert}] [item doc/files/punk/_module_assertion-0.1.0.tm.md shellspy_module_punk::assertion {assertion alternative to control::assert}]
[item doc/files/punk/_module_basictelnet-0.1.0.tm.md shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}] [item doc/files/punk/_module_basictelnet-0.1.0.tm.md shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}]
[item doc/files/punk/_module_island-0.1.0.tm.md shellspy_module_punk::island {filesystem islands for safe interps}]
[item doc/files/punk/repl/_module_codethread-0.1.0.tm.md shellspy_module_punk::repl::codethread {Module API}]
[item doc/files/punk/_module_sshrun-0.1.0.tm.md shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}] [item doc/files/punk/_module_sshrun-0.1.0.tm.md shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}]
[item doc/files/punk/_module_uc-0.1.0.tm.md shellspy_module_punk::uc {Module API}] [item doc/files/punk/_module_uc-0.1.0.tm.md shellspy_module_punk::uc {Module API}]
[toc_end] [toc_end]

2
src/embedded/md/.idx

File diff suppressed because one or more lines are too long

2
src/embedded/md/.toc

@ -1 +1 @@
doc {doc/toc {{doc/files/punk/_module_uc-0.1.0.tm.md shellspy_module_punk::uc {Module API}} {doc/files/punk/_module_lib-0.1.1.tm.md punkshell_module_punk::lib {punk general utility functions}} {doc/files/punk/_module_assertion-0.1.0.tm.md shellspy_module_punk::assertion {assertion alternative to control::assert}} {doc/files/project_intro.md punkshell__project_intro {Introduction to punkshell}} {doc/files/_module_overtype-1.6.2.tm.md overtype_module_overtype {overtype text layout - ansi aware}} {doc/files/punk/_module_sshrun-0.1.0.tm.md shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}} {doc/files/main.md punkshell {punkshell - Core}} {doc/files/punk/_module_flib-0.1.0.tm.md punkshell_module_punk::flib {flib experimental}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punkshell_module_punk::mix::commandset::project {dec commandset - project}} {doc/files/punk/_module_basictelnet-0.1.0.tm.md shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}} {doc/files/punk/_module_fileline-0.1.0.tm.md punkshell_module_punk::fileline {file line-handling utilities}} {doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_ansi-0.1.1.tm.md punkshell_module_punk::ansi {Ansi string functions}} {doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path {Filesystem path utilities}} {doc/files/punk/_module_args-0.1.0.tm.md punkshell_module_punk::args {args parsing}} {doc/files/project_changes.md punkshell__project_changes {punkshell Changes}} {doc/files/punk/_module_encmime-0.1.0.tm.md punkshell_module_punk::encmime {mime encodings related subset of tcllib mime}} {doc/files/punk/_module_char-0.1.0.tm.md punkshell_module_punk::char {character-set and unicode utilities}}}} doc {doc/toc {{doc/files/punk/_module_uc-0.1.0.tm.md shellspy_module_punk::uc {Module API}} {doc/files/punk/_module_lib-0.1.1.tm.md punkshell_module_punk::lib {punk general utility functions}} {doc/files/punk/_module_assertion-0.1.0.tm.md shellspy_module_punk::assertion {assertion alternative to control::assert}} {doc/files/project_intro.md punkshell__project_intro {Introduction to punkshell}} {doc/files/_module_overtype-1.6.2.tm.md overtype_module_overtype {overtype text layout - ansi aware}} {doc/files/_module_argparsingtest-0.1.0.tm.md shellspy_module_argparsingtest {Module API}} {doc/files/_module_overtype-1.6.3.tm.md overtype_module_overtype {overtype text layout - ansi aware}} {doc/files/punk/_module_sshrun-0.1.0.tm.md shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}} {doc/files/punk/_module_island-0.1.0.tm.md shellspy_module_punk::island {filesystem islands for safe interps}} {doc/files/punk/_module_aliascore-0.1.0.tm.md shellspy_module_punk::aliascore {Module API}} {doc/files/main.md punkshell {punkshell - Core}} {doc/files/punk/_module_flib-0.1.0.tm.md punkshell_module_punk::flib {flib experimental}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.md punkshell_module_punk::mix::commandset::project {dec commandset - project}} {doc/files/punk/_module_basictelnet-0.1.0.tm.md shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}} {doc/files/punk/_module_fileline-0.1.0.tm.md punkshell_module_punk::fileline {file line-handling utilities}} {doc/files/punk/_module_cap-0.1.0.tm.md punkshell_module_punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_ansi-0.1.1.tm.md punkshell_module_punk::ansi {Ansi string functions}} {doc/files/punk/repl/_module_codethread-0.1.0.tm.md shellspy_module_punk::repl::codethread {Module API}} {doc/files/punk/_module_path-0.1.0.tm.md punkshell_module_punk::path {Filesystem path utilities}} {doc/files/punk/_module_args-0.1.0.tm.md punkshell_module_punk::args {args parsing}} {doc/files/project_changes.md punkshell__project_changes {punkshell Changes}} {doc/files/punk/_module_encmime-0.1.0.tm.md punkshell_module_punk::encmime {mime encodings related subset of tcllib mime}} {doc/files/punk/_module_char-0.1.0.tm.md punkshell_module_punk::char {character-set and unicode utilities}}}}

2
src/embedded/md/.xrf

File diff suppressed because one or more lines are too long

87
src/embedded/md/doc/files/_module_argparsingtest-0.1.0.tm.md

@ -0,0 +1,87 @@
[//000000001]: # (shellspy\_module\_argparsingtest \- \-)
[//000000002]: # (Generated from file '\_module\_argparsingtest\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2024)
[//000000004]: # (shellspy\_module\_argparsingtest\(0\) 0\.1\.0 doc "\-")
<hr> [ <a href="../../toc.md">Main Table Of Contents</a> &#124; <a
href="../toc.md">Table Of Contents</a> &#124; <a
href="../../index.md">Keyword Index</a> ] <hr>
# NAME
shellspy\_module\_argparsingtest \- Module API
# <a name='toc'></a>Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [Overview](#section2)
- [Concepts](#subsection1)
- [dependencies](#subsection2)
- [API](#section3)
- [Namespace argparsingtest::class](#subsection3)
- [Namespace argparsingtest](#subsection4)
- [Namespace argparsingtest::lib](#subsection5)
- [Internal](#section4)
- [Namespace argparsingtest::system](#subsection6)
- [Keywords](#keywords)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
package require argparsingtest
# <a name='description'></a>DESCRIPTION
\-
# <a name='section2'></a>Overview
overview of argparsingtest
## <a name='subsection1'></a>Concepts
\-
## <a name='subsection2'></a>dependencies
packages used by argparsingtest
- __Tcl 8\.6__
# <a name='section3'></a>API
## <a name='subsection3'></a>Namespace argparsingtest::class
class definitions
## <a name='subsection4'></a>Namespace argparsingtest
## <a name='subsection5'></a>Namespace argparsingtest::lib
# <a name='section4'></a>Internal
## <a name='subsection6'></a>Namespace argparsingtest::system
# <a name='keywords'></a>KEYWORDS
[module](\.\./\.\./index\.md\#module)
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2024

139
src/embedded/md/doc/files/_module_overtype-1.6.3.tm.md

@ -0,0 +1,139 @@
[//000000001]: # (overtype\_module\_overtype \- overtype text layout)
[//000000002]: # (Generated from file '\_module\_overtype\-1\.6\.3\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2024)
[//000000004]: # (overtype\_module\_overtype\(0\) 1\.6\.3 doc "overtype text layout")
<hr> [ <a href="../../toc.md">Main Table Of Contents</a> &#124; <a
href="../toc.md">Table Of Contents</a> &#124; <a
href="../../index.md">Keyword Index</a> ] <hr>
# NAME
overtype\_module\_overtype \- overtype text layout \- ansi aware
# <a name='toc'></a>Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [Overview](#section2)
- [Concepts](#subsection1)
- [dependencies](#subsection2)
- [API](#section3)
- [Namespace overtype](#subsection3)
- [Keywords](#keywords)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
package require overtype
[__overtype::renderspace__ *args*](#1)
[__overtype::renderline__ *args*](#2)
# <a name='description'></a>DESCRIPTION
\-
# <a name='section2'></a>Overview
overview of overtype
## <a name='subsection1'></a>Concepts
\-
## <a name='subsection2'></a>dependencies
packages used by overtype
- __Tcl 8\.6__
- __textutil__
- __punk::ansi__
\- required to detect, split, strip and calculate lengths of text possibly
containing ansi codes
- __punk::char__
\- box drawing \- and also unicode character width determination for proper
layout of text with double\-column\-width chars
# <a name='section3'></a>API
## <a name='subsection3'></a>Namespace overtype
Core API functions for overtype
- <a name='1'></a>__overtype::renderspace__ *args*
usage: ?\-transparent \[0&#124;1\]? ?\-overflow \[1&#124;0\]? ?\-ellipsis \[1&#124;0\]?
?\-ellipsistext \.\.\.? undertext overtext
- <a name='2'></a>__overtype::renderline__ *args*
renderline is the core engine for overtype string processing \(frames &
textblocks\), and the raw mode commandline repl for the Tcl Punk Shell
It is also a central part of an ansi \(micro\) virtual terminal\-emulator of
sorts
This system does a half decent job at rendering 90's ANSI art to manipulable
colour text blocks that can be joined & framed for layout display within a
unix or windows terminal
Renderline helps maintain ANSI text styling reset/replay codes so that the
styling of one block doesn't affect another\.
Calling on the punk::ansi library \- it can coalesce codes to keep the size
down\.
It is a giant mess of doing exactly what common wisdom says not to do\.\.\.
lots at once\.
renderline is part of the Unicode and ANSI aware Overtype system which
'renders' a block of text onto a static underlay
The underlay is generally expected to be an ordered set of lines or a
rectangular text block analogous to a terminal screen \- but it can also be
ragged in line length, or just blank\.
The overlay couuld be similar \- in which case it may often be used to
overwrite a column or section of the underlay\.
The overlay could however be a sequence of ANSI\-laden text that jumps all
over the place\.
renderline itself only deals with a single line \- or sometimes a single
character\. It is generally called from a loop that does further
terminal\-like or textblock processing\.
By suppyling the \-info 1 option \- it can return various fields indicating
the state of the render\.
The main 3 are the result, overflow\_right, and unapplied\.
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\.
# <a name='keywords'></a>KEYWORDS
[ansi](\.\./\.\./index\.md\#ansi), [module](\.\./\.\./index\.md\#module),
[text](\.\./\.\./index\.md\#text)
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2024

87
src/embedded/md/doc/files/punk/_module_aliascore-0.1.0.tm.md

@ -0,0 +1,87 @@
[//000000001]: # (shellspy\_module\_punk::aliascore \- \-)
[//000000002]: # (Generated from file '\_module\_aliascore\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2024)
[//000000004]: # (shellspy\_module\_punk::aliascore\(0\) 0\.1\.0 doc "\-")
<hr> [ <a href="../../../toc.md">Main Table Of Contents</a> &#124; <a
href="../../toc.md">Table Of Contents</a> &#124; <a
href="../../../index.md">Keyword Index</a> ] <hr>
# NAME
shellspy\_module\_punk::aliascore \- Module API
# <a name='toc'></a>Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [Overview](#section2)
- [Concepts](#subsection1)
- [dependencies](#subsection2)
- [API](#section3)
- [Namespace punk::aliascore::class](#subsection3)
- [Namespace punk::aliascore](#subsection4)
- [Namespace punk::aliascore::lib](#subsection5)
- [Internal](#section4)
- [Namespace punk::aliascore::system](#subsection6)
- [Keywords](#keywords)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
package require punk::aliascore
# <a name='description'></a>DESCRIPTION
\-
# <a name='section2'></a>Overview
overview of punk::aliascore
## <a name='subsection1'></a>Concepts
\-
## <a name='subsection2'></a>dependencies
packages used by punk::aliascore
- __Tcl 8\.6__
# <a name='section3'></a>API
## <a name='subsection3'></a>Namespace punk::aliascore::class
class definitions
## <a name='subsection4'></a>Namespace punk::aliascore
## <a name='subsection5'></a>Namespace punk::aliascore::lib
# <a name='section4'></a>Internal
## <a name='subsection6'></a>Namespace punk::aliascore::system
# <a name='keywords'></a>KEYWORDS
[module](\.\./\.\./\.\./index\.md\#module)
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2024

222
src/embedded/md/doc/files/punk/_module_ansi-0.1.1.tm.md

@ -49,55 +49,54 @@ package require punk::ansi
[__a?__ ?ansicode\.\.\.?](#3) [__a?__ ?ansicode\.\.\.?](#3)
[__a\+__ ?ansicode\.\.\.?](#4) [__a\+__ ?ansicode\.\.\.?](#4)
[__a__ ?ansicode\.\.\.?](#5) [__a__ ?ansicode\.\.\.?](#5)
[__a__ ?ansicode\.\.\.?](#6) [__get\_code\_name__ *code*](#6)
[__get\_code\_name__ *code*](#7) [__reset__](#7)
[__reset__](#8) [__reset\_soft__](#8)
[__reset\_soft__](#9) [__reset\_colour__](#9)
[__reset\_colour__](#10) [__clear__](#10)
[__clear__](#11) [__clear\_above__](#11)
[__clear\_above__](#12) [__clear\_below__](#12)
[__clear\_below__](#13) [__cursor\_on__](#13)
[__cursor\_on__](#14) [__cursor\_off__](#14)
[__cursor\_off__](#15) [__move__ *row* *col*](#15)
[__move__ *row* *col*](#16) [__move\_emit__ *row* *col* *data* ?row col data\.\.\.?](#16)
[__move\_emit__ *row* *col* *data* ?row col data\.\.\.?](#17) [__move\_forward__ *n*](#17)
[__move\_forward__ *n*](#18) [__move\_back__ *n*](#18)
[__move\_back__ *n*](#19) [__move\_up__ *n*](#19)
[__move\_up__ *n*](#20) [__move\_down__ *n*](#20)
[__move\_down__ *n*](#21) [__move\_column__ *col*](#21)
[__move\_column__ *col*](#22) [__move\_row__ *row*](#22)
[__move\_row__ *row*](#23) [__cursor\_save__](#23)
[__cursor\_save__](#24) [__cursor\_restore__](#24)
[__cursor\_restore__](#25) [__cursor\_save\_dec__](#25)
[__cursor\_save\_dec__](#26) [__cursor\_restore\_attributes__](#26)
[__cursor\_restore\_attributes__](#27) [__enable\_line\_wrap__](#27)
[__enable\_line\_wrap__](#28) [__disable\_line\_wrap__](#28)
[__disable\_line\_wrap__](#29) [__query\_mode\_line\_wrap__](#29)
[__query\_mode\_line\_wrap__](#30) [__erase\_line__](#30)
[__erase\_line__](#31) [__erase\_sol__](#31)
[__erase\_sol__](#32) [__erase\_eol__](#32)
[__erase\_eol__](#33) [__scroll\_up__ *n*](#33)
[__scroll\_up__ *n*](#34) [__scroll\_down__ *n*](#34)
[__scroll\_down__ *n*](#35) [__insert\_spaces__ *count*](#35)
[__insert\_spaces__ *count*](#36) [__delete\_characters__ *count*](#36)
[__delete\_characters__ *count*](#37) [__erase\_characters__ *count*](#37)
[__erase\_characters__ *count*](#38) [__insert\_lines__ *count*](#38)
[__insert\_lines__ *count*](#39) [__delete\_lines__ *count*](#39)
[__delete\_lines__ *count*](#40) [__cursor\_pos__](#40)
[__cursor\_pos__](#41) [__request\_cursor\_information__](#41)
[__request\_cursor\_information__](#42) [__request\_tabstops__](#42)
[__request\_tabstops__](#43) [__titleset__ *windowtitles*](#43)
[__titleset__ *windowtitles*](#44) [__is\_sgr\_reset__ *code*](#44)
[__is\_sgr\_reset__ *code*](#45) [__has\_sgr\_leadingreset__ *code*](#45)
[__has\_sgr\_leadingreset__ *code*](#46) [__detect__ *text*](#46)
[__detect__ *text*](#47) [__detect\_csi__ *text*](#47)
[__detect\_csi__ *text*](#48) [__detect\_sgr__ *text*](#48)
[__detect\_sgr__ *text*](#49) [__strip__ *text*](#49)
[__strip__ *text*](#50) [__length__ *text*](#50)
[__length__ *text*](#51) [__VIEW__ *string*](#51)
[__VIEW__ *string*](#52) [__COUNT__ *string*](#52)
[__COUNT__ *string*](#53) [__index__ *string* *index*](#53)
[__index__ *string* *index*](#54)
# <a name='description'></a>DESCRIPTION # <a name='description'></a>DESCRIPTION
@ -154,7 +153,16 @@ Core API functions for punk::ansi
Alternate graphics modes will be stripped \- exposing the raw characters as Alternate graphics modes will be stripped \- exposing the raw characters as
they appear without graphics mode\. they appear without graphics mode\.
ie instead of a horizontal line you may see: qqqqqq ie instead of a horizontal line you may see: qqqqqq e\.g who is to know that
'Rabbit Paws', 'Forbidden Thrill' and 'Tarsier' refer to a particular shade
of pinky\-red? \(code 95\) Perhaps it's an indication that colour naming once
we get to 256 colours or more is a fool's errand anyway\. The xterm names are
boringly unimaginative \- and also have some oddities such as: DarkSlateGray1
which looks much more like cyan\.\. The greyxx names are spelt with an e \- but
the darkslategrayX variants use an a\. Perhaps that's because they are more
cyan than grey and the a is a hint? there is no gold or gold2 \- but there is
gold1 and gold3 but in general the names bear some resemblance to the
colours and are at least somewhat intuitive\.
- <a name='3'></a>__a?__ ?ansicode\.\.\.? - <a name='3'></a>__a?__ ?ansicode\.\.\.?
@ -194,25 +202,7 @@ Core API functions for punk::ansi
see __punk::ansi::a?__ to display a list of codes see __punk::ansi::a?__ to display a list of codes
- <a name='6'></a>__a__ ?ansicode\.\.\.? - <a name='6'></a>__get\_code\_name__ *code*
Returns the ansi code to reset any current settings and apply those from the
supplied list
by calling punk::ansi::a with no arguments \- the result is a reset to plain
text
e\.g to set foreground red and bold
punk::ansi::a red bold
to set background red
punk::ansi::a Red
see __punk::ansi::a?__ to display a list of codes
- <a name='7'></a>__get\_code\_name__ *code*
for example for example
@ -220,33 +210,33 @@ Core API functions for punk::ansi
get\_code\_name 31 will return red get\_code\_name 31 will return red
- <a name='8'></a>__reset__ - <a name='7'></a>__reset__
reset console reset console
- <a name='9'></a>__reset\_soft__ - <a name='8'></a>__reset\_soft__
- <a name='10'></a>__reset\_colour__ - <a name='9'></a>__reset\_colour__
reset colour only reset colour only
- <a name='11'></a>__clear__ - <a name='10'></a>__clear__
- <a name='12'></a>__clear\_above__ - <a name='11'></a>__clear\_above__
- <a name='13'></a>__clear\_below__ - <a name='12'></a>__clear\_below__
- <a name='14'></a>__cursor\_on__ - <a name='13'></a>__cursor\_on__
- <a name='15'></a>__cursor\_off__ - <a name='14'></a>__cursor\_off__
- <a name='16'></a>__move__ *row* *col* - <a name='15'></a>__move__ *row* *col*
Return an ansi sequence to move to row,col Return an ansi sequence to move to row,col
aka cursor home aka cursor home
- <a name='17'></a>__move\_emit__ *row* *col* *data* ?row col data\.\.\.? - <a name='16'></a>__move\_emit__ *row* *col* *data* ?row col data\.\.\.?
Return an ansi string representing a move to row col with data appended Return an ansi string representing a move to row col with data appended
@ -282,21 +272,21 @@ Core API functions for punk::ansi
an intuitive manner compared to other punk::ansi move functions \- so is an intuitive manner compared to other punk::ansi move functions \- so is
deliberately omitted\. deliberately omitted\.
- <a name='18'></a>__move\_forward__ *n* - <a name='17'></a>__move\_forward__ *n*
- <a name='19'></a>__move\_back__ *n* - <a name='18'></a>__move\_back__ *n*
- <a name='20'></a>__move\_up__ *n* - <a name='19'></a>__move\_up__ *n*
- <a name='21'></a>__move\_down__ *n* - <a name='20'></a>__move\_down__ *n*
- <a name='22'></a>__move\_column__ *col* - <a name='21'></a>__move\_column__ *col*
- <a name='23'></a>__move\_row__ *row* - <a name='22'></a>__move\_row__ *row*
VPA \- Vertical Line Position Absolute VPA \- Vertical Line Position Absolute
- <a name='24'></a>__cursor\_save__ - <a name='23'></a>__cursor\_save__
equivalent term::ansi::code::ctrl::sc equivalent term::ansi::code::ctrl::sc
@ -305,25 +295,25 @@ Core API functions for punk::ansi
On many terminals either will work \- but cursor\_save\_dec is shorter and On many terminals either will work \- but cursor\_save\_dec is shorter and
perhaps more widely supported perhaps more widely supported
- <a name='25'></a>__cursor\_restore__ - <a name='24'></a>__cursor\_restore__
equivalent term::ansi::code::ctrl::rc equivalent term::ansi::code::ctrl::rc
ANSI/SCO \- see also cursor\_restore\_dec for the DECRC version ANSI/SCO \- see also cursor\_restore\_dec for the DECRC version
- <a name='26'></a>__cursor\_save\_dec__ - <a name='25'></a>__cursor\_save\_dec__
equivalent term::ansi::code::ctrl::sca equivalent term::ansi::code::ctrl::sca
DECSC DECSC
- <a name='27'></a>__cursor\_restore\_attributes__ - <a name='26'></a>__cursor\_restore\_attributes__
equivalent term::ansi::code::ctrl::rca equivalent term::ansi::code::ctrl::rca
DECRC DECRC
- <a name='28'></a>__enable\_line\_wrap__ - <a name='27'></a>__enable\_line\_wrap__
enable automatic line wrapping when characters entered beyond rightmost enable automatic line wrapping when characters entered beyond rightmost
column column
@ -332,41 +322,41 @@ Core API functions for punk::ansi
This is DECAWM \- and is the same sequence output by 'tput smam' This is DECAWM \- and is the same sequence output by 'tput smam'
- <a name='29'></a>__disable\_line\_wrap__ - <a name='28'></a>__disable\_line\_wrap__
disable automatic line wrapping disable automatic line wrapping
reset DECAWM \- same sequence output by 'tput rmam' tput rmam reset DECAWM \- same sequence output by 'tput rmam' tput rmam
- <a name='30'></a>__query\_mode\_line\_wrap__ - <a name='29'></a>__query\_mode\_line\_wrap__
DECRQM to query line\-wrap state DECRQM to query line\-wrap state
The punk::ansi::query\_mode\_ functions just emit the ansi query sequence\. The punk::ansi::query\_mode\_ functions just emit the ansi query sequence\.
- <a name='31'></a>__erase\_line__ - <a name='30'></a>__erase\_line__
- <a name='32'></a>__erase\_sol__ - <a name='31'></a>__erase\_sol__
Erase to start of line, leaving cursor position alone\. Erase to start of line, leaving cursor position alone\.
- <a name='33'></a>__erase\_eol__ - <a name='32'></a>__erase\_eol__
- <a name='34'></a>__scroll\_up__ *n* - <a name='33'></a>__scroll\_up__ *n*
- <a name='35'></a>__scroll\_down__ *n* - <a name='34'></a>__scroll\_down__ *n*
- <a name='36'></a>__insert\_spaces__ *count* - <a name='35'></a>__insert\_spaces__ *count*
- <a name='37'></a>__delete\_characters__ *count* - <a name='36'></a>__delete\_characters__ *count*
- <a name='38'></a>__erase\_characters__ *count* - <a name='37'></a>__erase\_characters__ *count*
- <a name='39'></a>__insert\_lines__ *count* - <a name='38'></a>__insert\_lines__ *count*
- <a name='40'></a>__delete\_lines__ *count* - <a name='39'></a>__delete\_lines__ *count*
- <a name='41'></a>__cursor\_pos__ - <a name='40'></a>__cursor\_pos__
cursor\_pos unlikely to be useful on it's own like this as when written to cursor\_pos unlikely to be useful on it's own like this as when written to
the terminal, this sequence causes the terminal to emit the row;col sequence the terminal, this sequence causes the terminal to emit the row;col sequence
@ -384,7 +374,7 @@ Core API functions for punk::ansi
The punk::ansi::cursor\_pos function is used by punk::console::get\_cursor\_pos The punk::ansi::cursor\_pos function is used by punk::console::get\_cursor\_pos
and punk::console::get\_cursor\_pos\_list and punk::console::get\_cursor\_pos\_list
- <a name='42'></a>__request\_cursor\_information__ - <a name='41'></a>__request\_cursor\_information__
DECRQPSR \(DEC Request Presentation State Report\) for DECCCIR Cursor DECRQPSR \(DEC Request Presentation State Report\) for DECCCIR Cursor
Information report Information report
@ -394,7 +384,7 @@ Core API functions for punk::ansi
A stdin readloop will need to be in place to read this information A stdin readloop will need to be in place to read this information
- <a name='43'></a>__request\_tabstops__ - <a name='42'></a>__request\_tabstops__
DECRQPSR \(DEC Request Presentation State Report\) for DECTABSR Tab stop DECRQPSR \(DEC Request Presentation State Report\) for DECTABSR Tab stop
report report
@ -402,7 +392,7 @@ Core API functions for punk::ansi
When written to the terminal, this sequence causes the terminal to emit When written to the terminal, this sequence causes the terminal to emit
tabstop information to stdin tabstop information to stdin
- <a name='44'></a>__titleset__ *windowtitles* - <a name='43'></a>__titleset__ *windowtitles*
Returns the code to set the title of the terminal window to windowtitle Returns the code to set the title of the terminal window to windowtitle
@ -414,7 +404,7 @@ API functions for punk::ansi::codetype
Utility functions for processing ansi code sequences Utility functions for processing ansi code sequences
- <a name='45'></a>__is\_sgr\_reset__ *code* - <a name='44'></a>__is\_sgr\_reset__ *code*
Return a boolean indicating whether this string has a trailing pure SGR Return a boolean indicating whether this string has a trailing pure SGR
reset reset
@ -425,7 +415,7 @@ Utility functions for processing ansi code sequences
This is primarily intended for testing a single ansi code sequence, but code This is primarily intended for testing a single ansi code sequence, but code
can be any string where the trailing SGR code is to be tested\. can be any string where the trailing SGR code is to be tested\.
- <a name='46'></a>__has\_sgr\_leadingreset__ *code* - <a name='45'></a>__has\_sgr\_leadingreset__ *code*
The reset must be the very first item in code to be detected\. Trailing The reset must be the very first item in code to be detected\. Trailing
strings/codes ignored\. strings/codes ignored\.
@ -438,11 +428,11 @@ based on but not identical to the Perl Text Ansi module:
https://github\.com/perlancar/perl\-Text\-ANSI\-Util/blob/master/lib/Text/ANSI/BaseUtil\.pm https://github\.com/perlancar/perl\-Text\-ANSI\-Util/blob/master/lib/Text/ANSI/BaseUtil\.pm
- <a name='47'></a>__detect__ *text* - <a name='46'></a>__detect__ *text*
Return a boolean indicating whether Ansi codes were detected in text Return a boolean indicating whether Ansi codes were detected in text
- <a name='48'></a>__detect\_csi__ *text* - <a name='47'></a>__detect\_csi__ *text*
Return a boolean indicating whether an Ansi Control Sequence Introducer Return a boolean indicating whether an Ansi Control Sequence Introducer
\(CSI\) was detected in text \(CSI\) was detected in text
@ -459,7 +449,7 @@ https://github\.com/perlancar/perl\-Text\-ANSI\-Util/blob/master/lib/Text/ANSI/B
\(This function is not in perl ta\) \(This function is not in perl ta\)
- <a name='49'></a>__detect\_sgr__ *text* - <a name='48'></a>__detect\_sgr__ *text*
Return a boolean indicating whether an ansi Select Graphics Rendition code Return a boolean indicating whether an ansi Select Graphics Rendition code
was detected\. was detected\.
@ -474,13 +464,13 @@ https://github\.com/perlancar/perl\-Text\-ANSI\-Util/blob/master/lib/Text/ANSI/B
\(This function is not in perl ta\) \(This function is not in perl ta\)
- <a name='50'></a>__strip__ *text* - <a name='49'></a>__strip__ *text*
Return text stripped of Ansi codes Return text stripped of Ansi codes
This is a tailcall to punk::ansi::stripansi This is a tailcall to punk::ansi::stripansi
- <a name='51'></a>__length__ *text* - <a name='50'></a>__length__ *text*
Return the character length after stripping ansi codes \- not the printing Return the character length after stripping ansi codes \- not the printing
length length
@ -495,7 +485,7 @@ codes is always going to be significantly slower than working with plain strings
Just as working with other forms of markup such as HTML \- you simply need to be Just as working with other forms of markup such as HTML \- you simply need to be
aware of the tradeoffs and design accordingly\. aware of the tradeoffs and design accordingly\.
- <a name='52'></a>__VIEW__ *string* - <a name='51'></a>__VIEW__ *string*
Return a string with specific ANSI control characters substituted with Return a string with specific ANSI control characters substituted with
visual equivalents frome the appropriate unicode C0 and C1 visualisation visual equivalents frome the appropriate unicode C0 and C1 visualisation
@ -512,7 +502,7 @@ aware of the tradeoffs and design accordingly\.
As punkshell uses linefeed where possible in preference to crlf even on As punkshell uses linefeed where possible in preference to crlf even on
windows, cr is mapped to \\\\U240D '\\U240D' \- but lf is left as is\. windows, cr is mapped to \\\\U240D '\\U240D' \- but lf is left as is\.
- <a name='53'></a>__COUNT__ *string* - <a name='52'></a>__COUNT__ *string*
Returns the count of visible graphemes and non\-ansi control characters Returns the count of visible graphemes and non\-ansi control characters
@ -534,7 +524,7 @@ aware of the tradeoffs and design accordingly\.
To get the width, use punk::ansi::printing\_length instead, which is also To get the width, use punk::ansi::printing\_length instead, which is also
ansi aware\. ansi aware\.
- <a name='54'></a>__index__ *string* *index* - <a name='53'></a>__index__ *string* *index*
Takes a string that possibly contains ansi codes such as colour,underline Takes a string that possibly contains ansi codes such as colour,underline
etc \(SGR codes\) etc \(SGR codes\)

177
src/embedded/md/doc/files/punk/_module_args-0.1.0.tm.md

@ -48,7 +48,7 @@ punkshell\_module\_punk::args \- args parsing
package require punk::args package require punk::args
[__opts\_values__ *optionspecs* *rawargs* ?option value\.\.\.?](#1) [__get\_dict__ *optionspecs* *rawargs* ?option value\.\.\.?](#1)
# <a name='description'></a>DESCRIPTION # <a name='description'></a>DESCRIPTION
@ -62,28 +62,36 @@ overview of punk::args
There are 2 main conventions for parsing a proc args list There are 2 main conventions for parsing a proc args list
1. leading option\-value pairs followed by a list of values \(Tk style\) 1. leading option\-value pairs followed by a list of values \(Tcl style\)
1. leading list of values followed by option\-value pairs \(Tcl style\) 1. leading list of values followed by option\-value pairs \(Tk style\)
punk::args is focused on the 1st convention \(Tk style\): parsing of args in There are exceptions in both Tcl and Tk commands regarding this ordering
leading option\-value pair style \- even for non\-Tk usage\.
punk::args is focused on the 1st convention \(Tcl style\): parsing of the 'args'
variable in leading option\-value pair style
The proc can still contain some leading required values e\.g The proc can still contain some leading required values e\.g
proc dostuff {arg1 arg2 args} {...}} proc dostuff {arg1 arg2 args} {...}}
but having the core values elements at the end of args is more generally useful but having the core values elements at the end of args is arguably more
\- especially in cases where the number of trailing values is unknown and/or the generally useful \- especially in cases where the number of trailing values is
proc is to be called in a functional 'pipeline' style\. unknown and/or the proc is to be called in a functional 'pipeline' style\.
The basic principle is that a call to punk::args::opts\_vals is made near the The basic principle is that a call to punk::args::opts\_vals is made near the
beginning of the proc e\.g beginning of the proc e\.g
proc dofilestuff {args} { proc dofilestuff {args} {
lassign [dict values [punk::args { lassign [dict values [punk::args {
*proc -help "do some stuff with files e.g dofilestuff <file1> <file2> <file3>"
*opts -type string
#comment lines ok
-directory -default "" -directory -default ""
-translation -default binary -translation -default binary
#setting -type none indicates a flag that doesn't take a value (solo flag)
-nocomplain -type none
*values -min 1 -max -1
} $args]] opts values } $args]] opts values
puts "translation is [dict get $opts -translation]" puts "translation is [dict get $opts -translation]"
@ -92,17 +100,127 @@ beginning of the proc e\.g
} }
} }
The lines beginning with \* are optional in most cases and can be used to set
defaults and some extra controls
\- the above example would work just fine with only the \-<optionname> lines, but
would allow zero filenames to be supplied as no \-min value is set for \*values
valid \* lines being with \*proc \*opts \*values
lines beginning with a dash define options \- a name can optionally be given to
each trailing positional argument\.
If no names are defined for positional arguments, they will end up in the values
key of the dict with numerical keys starting at zero\.
e\.g the result from the punk::args call above may be something like:
opts \{\-translation binary \-directory "" \-nocomplain 0\} values \{0 file1\.txt 1
file2\.txt 2 file3\.txt\}
Here is an example that requires the number of values supplied to be exactly 2
and names the positional arguments
It also demonstrates an inital argument 'category' that is outside of the scope
for punk::args processing \- allowing leading and trailing positional arguments
proc dofilestuff {category args} {
lassign [dict values [punk::args {
-directory -default ""
-translation -default binary
-nocomplain -type none
*values -min 2 -max 2
fileA -existingfile 1
fileB -existingfile 1
} $args]] opts values
puts "$category fileA: [dict get $values fileA]"
puts "$category fileB: [dict get $values fileB]"
}
By using standard tcl proc named arguments prior to args, and setting \*values
\-min 0 \-max 0
a Tk\-style ordering can be acheived, where punk::args is only handling the
trailing flags and the values element of the returned dict can be ignored
This use of leading positional arguments means the type validation features
can't be applied to them\. It can be done manually as usual,
or an additional call could be made to punk::args e\.g
punk::args {
category -choices {cat1 cat2 cat3}
another_leading_arg -type boolean
} [list $category $another_leading_arg]
## <a name='subsection2'></a>Notes ## <a name='subsection2'></a>Notes
There are alternative args parsing packages such as: For internal functions not requiring features such as solo flags, prefix
matching, type checking etc \- a well crafted switch statement will be the
fastest pure\-tcl solution\.
When functions are called often and/or in inner loops, a switch based solution
generally makes the most sense\. For functions that are part of an API a package
may be more suitable\.
The following example shows a switch\-based solution that is highly performant
\(sub microsecond for the no\-args case\)
proc test1_switch {args} {
set opts [dict create\
-return "object"\
-frametype "heavy"\
-show_edge 1\
-show_seps 0\
-x a\
-y b\
-z c\
-1 1\
-2 2\
-3 3\
]
foreach {k v} $args {
switch -- $k {
-return - -show_edge - -show_seps - -frametype - -x - -y - -z - -1 - -2 - -3 {
dict set opts $k $v
}
default {
error "unrecognised option '$k'. Known options [dict keys $opts]"
}
}
}
return $opts
}
Note that the switch statement uses literals so that the compiler produces a
jump\-table for best performance\.
Attempting to build the switch branch using the values from dict keys $opts will
stop the jump table being built\. To create the faster switch statement without
repeating the key names, the proc body would need to be built using string map\.
use punk::lib::show\_jump\_tables <procname> to verify that a jump table exists\.
There are many alternative args parsing packages a few of which are listed here\.
1. argp \(pure tcl\)
1. parse\_args \(c implementation\)
1. argparse \(pure tcl \*\)
1. argp 1. cmdline \(pure tcl\)
1. The tcllib set of TEPAM modules 1. opt \(pure tcl\) distributed with Tcl but considered deprecated
1. The tcllib set of TEPAM modules \(pure tcl\)
TEPAM requires an alternative procedure declaration syntax instead of proc TEPAM requires an alternative procedure declaration syntax instead of proc
\- but has support for Tk and documentation generation\. \- but has support for Tk and documentation generation\.
\(\* c implementation planned/proposed\)
punk::args was designed initially without specific reference to TEPAM \- and to punk::args was designed initially without specific reference to TEPAM \- and to
handle some edge cases in specific projects where TEPAM wasn't suitable\. handle some edge cases in specific projects where TEPAM wasn't suitable\.
@ -115,8 +233,15 @@ the differences\.
TEPAM is a mature solution and is widely available as it is included in tcllib\. TEPAM is a mature solution and is widely available as it is included in tcllib\.
Serious consideration should be given to using TEPAM if suitable for your Serious consideration should be given to using TEPAM or one of the other
project\. packages, if suitable for your project\.
punk::args is relatively performant for a pure\-tcl solution \- with the parsing
of the argument specification block occuring only on the first run \- after which
a cached version of the spec is used\.
punk::args is not limited to procs\. It can be used in apply or coroutine
situations for example\.
## <a name='subsection3'></a>dependencies ## <a name='subsection3'></a>dependencies
@ -132,7 +257,7 @@ class definitions
## <a name='subsection5'></a>Namespace punk::args ## <a name='subsection5'></a>Namespace punk::args
- <a name='1'></a>__opts\_values__ *optionspecs* *rawargs* ?option value\.\.\.? - <a name='1'></a>__get\_dict__ *optionspecs* *rawargs* ?option value\.\.\.?
Parse rawargs as a sequence of zero or more option\-value pairs followed by Parse rawargs as a sequence of zero or more option\-value pairs followed by
zero or more values zero or more values
@ -149,17 +274,35 @@ class definitions
'info complete' is used to determine if a record spans multiple lines 'info complete' is used to determine if a record spans multiple lines
due to multiline values due to multiline values
Each optionspec line must be of the form: Each optionspec line defining a flag must be of the form:
\-optionname \-key val \-key2 val2\.\.\. \-optionname \-key val \-key2 val2\.\.\.
where the valid keys for each option specification are: \-default \-type where the valid keys for each option specification are: \-default \-type
\-range \-choices \-optional \-range \-choices \-optional
Each optionspec line defining a positional argument is of the form:
argumentname \-key val \-ky2 val2\.\.\.
where the valid keys for each option specification are: \-default \-type
\-range \-choices
comment lines begining with \# are ignored and can be placed anywhere
except within a multiline value where it would become part of that value
lines beginning with \*proc \*opts or \*values also take \-key val pairs and
can be used to set defaults and control settings\.
\*opts or \*values lines can appear multiple times with defaults affecting
flags/values that follow\.
* list *rawargs* * list *rawargs*
This is a list of the arguments to parse\. Usually it will be the \\$args This is a list of the arguments to parse\. Usually it will be the $args
value from the containing proc value from the containing proc, but it could be a manually constructed
list of values made for example from positional args defined in the
proc\.
## <a name='subsection6'></a>Namespace punk::args::lib ## <a name='subsection6'></a>Namespace punk::args::lib

254
src/embedded/md/doc/files/punk/_module_island-0.1.0.tm.md

@ -0,0 +1,254 @@
[//000000001]: # (shellspy\_module\_punk::island \- punk::island for safe interps)
[//000000002]: # (Generated from file '\_module\_island\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2024)
[//000000004]: # (shellspy\_module\_punk::island\(0\) 0\.1\.0 doc "punk::island for safe interps")
<hr> [ <a href="../../../toc.md">Main Table Of Contents</a> &#124; <a
href="../../toc.md">Table Of Contents</a> &#124; <a
href="../../../index.md">Keyword Index</a> ] <hr>
# NAME
shellspy\_module\_punk::island \- filesystem islands for safe interps
# <a name='toc'></a>Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [Overview](#section2)
- [Concepts](#subsection1)
- [dependencies](#subsection2)
- [API](#section3)
- [Namespace punk::island::class](#subsection3)
- [Namespace punk::island::interps](#subsection4)
- [Namespace punk::island](#subsection5)
- [Namespace punk::island::lib](#subsection6)
- [Internal](#section4)
- [Namespace punk::island::system](#subsection7)
- [Keywords](#keywords)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
package require punk::island
[__add__ *child* *path*](#1)
[__reset__ *child*](#2)
[__Allowed__ *child* *fname*](#3)
[__File__ *child* *cmd* *args*](#4)
[__Open__ *child* *args*](#5)
[__Expose__ *child* *cmd* *args*](#6)
[__Glob__ *child* *args*](#7)
[__Init__ *child*](#8)
# <a name='description'></a>DESCRIPTION
Package to a allow a safe interpreter to access islands of the
filesystem only, i\.e\. restricted directory trees within the
filesystem\. The package brings back file, open and glob to the child interp
interpreter, though in a restricted manner\.
JN Warning:
This mechanism can have interactions with package loading from auto\_path \- needs
review\.
# <a name='section2'></a>Overview
overview of punk::island
## <a name='subsection1'></a>Concepts
\-
## <a name='subsection2'></a>dependencies
packages used by punk::island
- __Tcl 8\.6__
# <a name='section3'></a>API
## <a name='subsection3'></a>Namespace punk::island::class
class definitions
## <a name='subsection4'></a>Namespace punk::island::interps
## <a name='subsection5'></a>Namespace punk::island
- <a name='1'></a>__add__ *child* *path*
Add a path to the list of paths that are explicitely allowed for access
to a child interpreter\. Access to any path that has not been explicitely
allowed will be denied\. Paths that are added to the list of allowed
islands are always fully normalized\.
Arguments:
* string *child*
Identifier of the child interpreter to control
- <a name='2'></a>__reset__ *child*
Remove all access path allowance and arrange for the interpreter to be
able to return to the regular safe state\.
Arguments:
* string *child*
Identifier of the child interpreter
## <a name='subsection6'></a>Namespace punk::island::lib
Secondary functions that are part of the API
# <a name='section4'></a>Internal
## <a name='subsection7'></a>Namespace punk::island::system
- <a name='3'></a>__Allowed__ *child* *fname*
Check that the file name passed as an argument is within the islands of
the filesystem that have been registered through the add command for a
given \(safe\) interpreter\. The path is fully normalized before testing
against the islands, which themselves are fully normalized\.
Arguments:
* string *child*
Identifier of the child interpreter
* string *fname*
\(relative\) path to the file to test
- <a name='4'></a>__File__ *child* *cmd* *args*
Parses the options and arguments to the file command to discover which
paths it tries to access and only return the results of its execution
when these path are within the allowed islands of the filesystem\.
Arguments:
* string *child*
Identifier of the child interpreter
* string *cmd*
Subcommand of the file command
* string *args*
Arguments to the file subcommand
- <a name='5'></a>__Open__ *child* *args*
Parses the options and arguments to the open command to discover which
paths it tries to access and only return the results of its execution
when these path are within the allowed islands of the filesystem\.
Arguments:
* string *child*
Identifier of the child interpreter
* string *args*
Arguments to the open subcommand
- <a name='6'></a>__Expose__ *child* *cmd* *args*
This procedure allows to callback a command that would typically have
been hidden from a child interpreter\. It does not "interp expose" but
rather calls the hidden command, so we can easily revert back\.
Arguments:
* string *child*
Identifier of the child interpreter
* string *cmd*
Hidden command to call
* string *args*
Arguments to the command
- <a name='7'></a>__Glob__ *child* *args*
Parses the options and arguments to the glob command to discover which
paths it tries to access and only return the results of its execution
when these path are within the allowed islands of the filesystem\.
Arguments:
* string *child*
Identifier of the child interpreter
* string *args*
Arguments to the glob command
- <a name='8'></a>__Init__ *child*
Initialise child interpreter so that it will be able to perform some
file operations, but only within some islands of the filesystem\.
Arguments:
* string *child*
Identifier of the child interpreter
# <a name='keywords'></a>KEYWORDS
[filesystem](\.\./\.\./\.\./index\.md\#filesystem),
[interp](\.\./\.\./\.\./index\.md\#interp), [module](\.\./\.\./\.\./index\.md\#module)
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2024

33
src/embedded/md/doc/files/punk/_module_lib-0.1.1.tm.md

@ -73,7 +73,6 @@ package require punk::lib
[__linesort__ ?sortoption ?val?\.\.\.? *textblock*](#25) [__linesort__ ?sortoption ?val?\.\.\.? *textblock*](#25)
[__list\_as\_lines__ ?\-joinchar char? *linelist*](#26) [__list\_as\_lines__ ?\-joinchar char? *linelist*](#26)
[__lines\_as\_list__ ?option value \.\.\.? *text*](#27) [__lines\_as\_list__ ?option value \.\.\.? *text*](#27)
[__opts\_values__ ?option value\.\.\.? *optionspecs* *rawargs*](#28)
# <a name='description'></a>DESCRIPTION # <a name='description'></a>DESCRIPTION
@ -146,7 +145,8 @@ Core API functions for punk::lib
Otherwise it will return an integer corresponding to the position in the Otherwise it will return an integer corresponding to the position in the
list\. list\.
Like Tcl list commands \- it will produce an error if the form of the Like Tcl list commands \- it will produce an error if the form of the index
is not acceptable
- <a name='4'></a>__K__ *x* *y* - <a name='4'></a>__K__ *x* *y*
@ -425,35 +425,6 @@ Core API functions for punk::lib
\- not console lines which may be entirely different due to control \- not console lines which may be entirely different due to control
characters such as vertical tabs or ANSI movements characters such as vertical tabs or ANSI movements
- <a name='28'></a>__opts\_values__ ?option value\.\.\.? *optionspecs* *rawargs*
Parse rawargs as a sequence of zero or more option\-value pairs followed by
zero or more values
Returns a dict of the form: opts <options\_dict> values <values\_dict>
ARGUMENTS:
* multiline\-string *optionspecs*
This a block of text with records delimited by newlines \(lf or crlf\) \-
but with multiline values allowed if properly quoted/braced
'info complete' is used to determine if a record spans multiple lines
due to multiline values
Each optionspec line must be of the form:
\-optionname \-key val \-key2 val2\.\.\.
where the valid keys for each option specification are: \-default \-type
\-range \-choices \-optional
* list *rawargs*
This is a list of the arguments to parse\. Usually it will be the \\$args
value from the containing proc
# <a name='section4'></a>Internal # <a name='section4'></a>Internal
## <a name='subsection6'></a>Namespace punk::lib::system ## <a name='subsection6'></a>Namespace punk::lib::system

87
src/embedded/md/doc/files/punk/repl/_module_codethread-0.1.0.tm.md

@ -0,0 +1,87 @@
[//000000001]: # (shellspy\_module\_punk::repl::codethread \- \-)
[//000000002]: # (Generated from file '\_module\_codethread\-0\.1\.0\.tm\.man' by tcllib/doctools with format 'markdown')
[//000000003]: # (Copyright &copy; 2024)
[//000000004]: # (shellspy\_module\_punk::repl::codethread\(0\) 0\.1\.0 doc "\-")
<hr> [ <a href="../../../../toc.md">Main Table Of Contents</a> &#124; <a
href="../../../toc.md">Table Of Contents</a> &#124; <a
href="../../../../index.md">Keyword Index</a> ] <hr>
# NAME
shellspy\_module\_punk::repl::codethread \- Module API
# <a name='toc'></a>Table Of Contents
- [Table Of Contents](#toc)
- [Synopsis](#synopsis)
- [Description](#section1)
- [Overview](#section2)
- [Concepts](#subsection1)
- [dependencies](#subsection2)
- [API](#section3)
- [Namespace punk::repl::codethread::class](#subsection3)
- [Namespace punk::repl::codethread](#subsection4)
- [Namespace punk::repl::codethread::lib](#subsection5)
- [Internal](#section4)
- [Namespace punk::repl::codethread::system](#subsection6)
- [Keywords](#keywords)
- [Copyright](#copyright)
# <a name='synopsis'></a>SYNOPSIS
package require punk::repl::codethread
# <a name='description'></a>DESCRIPTION
\-
# <a name='section2'></a>Overview
overview of punk::repl::codethread
## <a name='subsection1'></a>Concepts
\-
## <a name='subsection2'></a>dependencies
packages used by punk::repl::codethread
- __Tcl 8\.6__
# <a name='section3'></a>API
## <a name='subsection3'></a>Namespace punk::repl::codethread::class
class definitions
## <a name='subsection4'></a>Namespace punk::repl::codethread
## <a name='subsection5'></a>Namespace punk::repl::codethread::lib
# <a name='section4'></a>Internal
## <a name='subsection6'></a>Namespace punk::repl::codethread::system
# <a name='keywords'></a>KEYWORDS
[module](\.\./\.\./\.\./\.\./index\.md\#module)
# <a name='copyright'></a>COPYRIGHT
Copyright &copy; 2024

10
src/embedded/md/doc/toc.md

@ -5,6 +5,8 @@
- [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) overtype text layout \- ansi aware - [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) overtype text layout \- ansi aware
- [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.3\.tm\.md) overtype text layout \- ansi aware
- [punkshell](doc/files/main\.md) punkshell \- Core - [punkshell](doc/files/main\.md) punkshell \- Core
- [punkshell\_\_project\_changes](doc/files/project\_changes\.md) punkshell Changes - [punkshell\_\_project\_changes](doc/files/project\_changes\.md) punkshell Changes
@ -31,10 +33,18 @@
- [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities - [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities
- [shellspy\_module\_argparsingtest](doc/files/\_module\_argparsingtest\-0\.1\.0\.tm\.md) Module API
- [shellspy\_module\_punk::aliascore](doc/files/punk/\_module\_aliascore\-0\.1\.0\.tm\.md) Module API
- [shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md) assertion alternative to control::assert - [shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md) assertion alternative to control::assert
- [shellspy\_module\_punk::basictelnet](doc/files/punk/\_module\_basictelnet\-0\.1\.0\.tm\.md) basic telnet client \- DKF/Wiki - [shellspy\_module\_punk::basictelnet](doc/files/punk/\_module\_basictelnet\-0\.1\.0\.tm\.md) basic telnet client \- DKF/Wiki
- [shellspy\_module\_punk::island](doc/files/punk/\_module\_island\-0\.1\.0\.tm\.md) filesystem islands for safe interps
- [shellspy\_module\_punk::repl::codethread](doc/files/punk/repl/\_module\_codethread\-0\.1\.0\.tm\.md) Module API
- [shellspy\_module\_punk::sshrun](doc/files/punk/\_module\_sshrun\-0\.1\.0\.tm\.md) Tcl procedures to execute tcl scripts in remote hosts - [shellspy\_module\_punk::sshrun](doc/files/punk/\_module\_sshrun\-0\.1\.0\.tm\.md) Tcl procedures to execute tcl scripts in remote hosts
- [shellspy\_module\_punk::uc](doc/files/punk/\_module\_uc\-0\.1\.0\.tm\.md) Module API - [shellspy\_module\_punk::uc](doc/files/punk/\_module\_uc\-0\.1\.0\.tm\.md) Module API

17
src/embedded/md/index.md

@ -5,7 +5,7 @@
---- ----
[A](#cA) &#183; [B](#cB) &#183; [C](#cC) &#183; [D](#cD) &#183; [E](#cE) &#183; [F](#cF) &#183; [L](#cL) &#183; [M](#cM) &#183; [P](#cP) &#183; [R](#cR) &#183; [S](#cS) &#183; [T](#cT) &#183; [U](#cU) [A](#cA) &#183; [B](#cB) &#183; [C](#cC) &#183; [D](#cD) &#183; [E](#cE) &#183; [F](#cF) &#183; [I](#cI) &#183; [L](#cL) &#183; [M](#cM) &#183; [P](#cP) &#183; [R](#cR) &#183; [S](#cS) &#183; [T](#cT) &#183; [U](#cU)
---- ----
@ -13,7 +13,7 @@
||| |||
|---|---| |---|---|
|<a name='ansi'></a>ansi|[overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) &#183; [punkshell\_module\_punk::ansi](doc/files/punk/\_module\_ansi\-0\.1\.1\.tm\.md)| |<a name='ansi'></a>ansi|[overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) &#183; [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.3\.tm\.md) &#183; [punkshell\_module\_punk::ansi](doc/files/punk/\_module\_ansi\-0\.1\.1\.tm\.md)|
|<a name='args'></a>args|[punkshell\_module\_punk::args](doc/files/punk/\_module\_args\-0\.1\.0\.tm\.md)| |<a name='args'></a>args|[punkshell\_module\_punk::args](doc/files/punk/\_module\_args\-0\.1\.0\.tm\.md)|
|<a name='arguments'></a>arguments|[punkshell\_module\_punk::args](doc/files/punk/\_module\_args\-0\.1\.0\.tm\.md)| |<a name='arguments'></a>arguments|[punkshell\_module\_punk::args](doc/files/punk/\_module\_args\-0\.1\.0\.tm\.md)|
|<a name='assert'></a>assert|[shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md)| |<a name='assert'></a>assert|[shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md)|
@ -57,7 +57,14 @@
||| |||
|---|---| |---|---|
|<a name='file'></a>file|[punkshell\_module\_punk::fileline](doc/files/punk/\_module\_fileline\-0\.1\.0\.tm\.md)| |<a name='file'></a>file|[punkshell\_module\_punk::fileline](doc/files/punk/\_module\_fileline\-0\.1\.0\.tm\.md)|
|<a name='filesystem'></a>filesystem|[punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md)| |<a name='filesystem'></a>filesystem|[punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::island](doc/files/punk/\_module\_island\-0\.1\.0\.tm\.md)|
#### <a name='cI'></a>Keywords: I
|||
|---|---|
|<a name='interp'></a>interp|[shellspy\_module\_punk::island](doc/files/punk/\_module\_island\-0\.1\.0\.tm\.md)|
#### <a name='cL'></a>Keywords: L #### <a name='cL'></a>Keywords: L
@ -71,7 +78,7 @@
||| |||
|---|---| |---|---|
|<a name='module'></a>module|[overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) &#183; [punkshell\_module\_punk::ansi](doc/files/punk/\_module\_ansi\-0\.1\.1\.tm\.md) &#183; [punkshell\_module\_punk::args](doc/files/punk/\_module\_args\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::char](doc/files/punk/\_module\_char\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::encmime](doc/files/punk/\_module\_encmime\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::fileline](doc/files/punk/\_module\_fileline\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::flib](doc/files/punk/\_module\_flib\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::lib](doc/files/punk/\_module\_lib\-0\.1\.1\.tm\.md) &#183; [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::basictelnet](doc/files/punk/\_module\_basictelnet\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::sshrun](doc/files/punk/\_module\_sshrun\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::uc](doc/files/punk/\_module\_uc\-0\.1\.0\.tm\.md)| |<a name='module'></a>module|[overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) &#183; [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.3\.tm\.md) &#183; [punkshell\_module\_punk::ansi](doc/files/punk/\_module\_ansi\-0\.1\.1\.tm\.md) &#183; [punkshell\_module\_punk::args](doc/files/punk/\_module\_args\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::cap](doc/files/punk/\_module\_cap\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::char](doc/files/punk/\_module\_char\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::encmime](doc/files/punk/\_module\_encmime\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::fileline](doc/files/punk/\_module\_fileline\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::flib](doc/files/punk/\_module\_flib\-0\.1\.0\.tm\.md) &#183; [punkshell\_module\_punk::lib](doc/files/punk/\_module\_lib\-0\.1\.1\.tm\.md) &#183; [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_argparsingtest](doc/files/\_module\_argparsingtest\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::aliascore](doc/files/punk/\_module\_aliascore\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::basictelnet](doc/files/punk/\_module\_basictelnet\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::island](doc/files/punk/\_module\_island\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::repl::codethread](doc/files/punk/repl/\_module\_codethread\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::sshrun](doc/files/punk/\_module\_sshrun\-0\.1\.0\.tm\.md) &#183; [shellspy\_module\_punk::uc](doc/files/punk/\_module\_uc\-0\.1\.0\.tm\.md)|
#### <a name='cP'></a>Keywords: P #### <a name='cP'></a>Keywords: P
@ -106,7 +113,7 @@
||| |||
|---|---| |---|---|
|<a name='terminal'></a>terminal|[punkshell\_module\_punk::ansi](doc/files/punk/\_module\_ansi\-0\.1\.1\.tm\.md)| |<a name='terminal'></a>terminal|[punkshell\_module\_punk::ansi](doc/files/punk/\_module\_ansi\-0\.1\.1\.tm\.md)|
|<a name='text'></a>text|[overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) &#183; [punkshell\_module\_punk::fileline](doc/files/punk/\_module\_fileline\-0\.1\.0\.tm\.md)| |<a name='text'></a>text|[overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) &#183; [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.3\.tm\.md) &#183; [punkshell\_module\_punk::fileline](doc/files/punk/\_module\_fileline\-0\.1\.0\.tm\.md)|
#### <a name='cU'></a>Keywords: U #### <a name='cU'></a>Keywords: U

10
src/embedded/md/toc.md

@ -5,6 +5,8 @@
- [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) overtype text layout \- ansi aware - [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.2\.tm\.md) overtype text layout \- ansi aware
- [overtype\_module\_overtype](doc/files/\_module\_overtype\-1\.6\.3\.tm\.md) overtype text layout \- ansi aware
- [punkshell](doc/files/main\.md) punkshell \- Core - [punkshell](doc/files/main\.md) punkshell \- Core
- [punkshell\_\_project\_changes](doc/files/project\_changes\.md) punkshell Changes - [punkshell\_\_project\_changes](doc/files/project\_changes\.md) punkshell Changes
@ -31,10 +33,18 @@
- [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities - [punkshell\_module\_punk::path](doc/files/punk/\_module\_path\-0\.1\.0\.tm\.md) Filesystem path utilities
- [shellspy\_module\_argparsingtest](doc/files/\_module\_argparsingtest\-0\.1\.0\.tm\.md) Module API
- [shellspy\_module\_punk::aliascore](doc/files/punk/\_module\_aliascore\-0\.1\.0\.tm\.md) Module API
- [shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md) assertion alternative to control::assert - [shellspy\_module\_punk::assertion](doc/files/punk/\_module\_assertion\-0\.1\.0\.tm\.md) assertion alternative to control::assert
- [shellspy\_module\_punk::basictelnet](doc/files/punk/\_module\_basictelnet\-0\.1\.0\.tm\.md) basic telnet client \- DKF/Wiki - [shellspy\_module\_punk::basictelnet](doc/files/punk/\_module\_basictelnet\-0\.1\.0\.tm\.md) basic telnet client \- DKF/Wiki
- [shellspy\_module\_punk::island](doc/files/punk/\_module\_island\-0\.1\.0\.tm\.md) filesystem islands for safe interps
- [shellspy\_module\_punk::repl::codethread](doc/files/punk/repl/\_module\_codethread\-0\.1\.0\.tm\.md) Module API
- [shellspy\_module\_punk::sshrun](doc/files/punk/\_module\_sshrun\-0\.1\.0\.tm\.md) Tcl procedures to execute tcl scripts in remote hosts - [shellspy\_module\_punk::sshrun](doc/files/punk/\_module\_sshrun\-0\.1\.0\.tm\.md) Tcl procedures to execute tcl scripts in remote hosts
- [shellspy\_module\_punk::uc](doc/files/punk/\_module\_uc\-0\.1\.0\.tm\.md) Module API - [shellspy\_module\_punk::uc](doc/files/punk/\_module\_uc\-0\.1\.0\.tm\.md) Module API

5
src/embedded/www/.doc/tocdoc

@ -1,5 +1,6 @@
[toc_begin {Table Of Contents} doc] [toc_begin {Table Of Contents} doc]
[item doc/files/_module_overtype-1.6.2.tm.html overtype_module_overtype {overtype text layout - ansi aware}] [item doc/files/_module_overtype-1.6.2.tm.html overtype_module_overtype {overtype text layout - ansi aware}]
[item doc/files/_module_overtype-1.6.3.tm.html overtype_module_overtype {overtype text layout - ansi aware}]
[item doc/files/main.html punkshell {punkshell - Core}] [item doc/files/main.html punkshell {punkshell - Core}]
[item doc/files/project_changes.html punkshell__project_changes {punkshell Changes}] [item doc/files/project_changes.html punkshell__project_changes {punkshell Changes}]
[item doc/files/project_intro.html punkshell__project_intro {Introduction to punkshell}] [item doc/files/project_intro.html punkshell__project_intro {Introduction to punkshell}]
@ -13,8 +14,12 @@
[item doc/files/punk/_module_lib-0.1.1.tm.html punkshell_module_punk::lib {punk general utility functions}] [item doc/files/punk/_module_lib-0.1.1.tm.html punkshell_module_punk::lib {punk general utility functions}]
[item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punkshell_module_punk::mix::commandset::project {dec commandset - project}] [item doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punkshell_module_punk::mix::commandset::project {dec commandset - project}]
[item doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path {Filesystem path utilities}] [item doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path {Filesystem path utilities}]
[item doc/files/_module_argparsingtest-0.1.0.tm.html shellspy_module_argparsingtest {Module API}]
[item doc/files/punk/_module_aliascore-0.1.0.tm.html shellspy_module_punk::aliascore {Module API}]
[item doc/files/punk/_module_assertion-0.1.0.tm.html shellspy_module_punk::assertion {assertion alternative to control::assert}] [item doc/files/punk/_module_assertion-0.1.0.tm.html shellspy_module_punk::assertion {assertion alternative to control::assert}]
[item doc/files/punk/_module_basictelnet-0.1.0.tm.html shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}] [item doc/files/punk/_module_basictelnet-0.1.0.tm.html shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}]
[item doc/files/punk/_module_island-0.1.0.tm.html shellspy_module_punk::island {filesystem islands for safe interps}]
[item doc/files/punk/repl/_module_codethread-0.1.0.tm.html shellspy_module_punk::repl::codethread {Module API}]
[item doc/files/punk/_module_sshrun-0.1.0.tm.html shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}] [item doc/files/punk/_module_sshrun-0.1.0.tm.html shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}]
[item doc/files/punk/_module_uc-0.1.0.tm.html shellspy_module_punk::uc {Module API}] [item doc/files/punk/_module_uc-0.1.0.tm.html shellspy_module_punk::uc {Module API}]
[toc_end] [toc_end]

2
src/embedded/www/.idx

File diff suppressed because one or more lines are too long

2
src/embedded/www/.toc

@ -1 +1 @@
doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_ansi-0.1.1.tm.html punkshell_module_punk::ansi {Ansi string functions}} {doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path {Filesystem path utilities}} {doc/files/punk/_module_args-0.1.0.tm.html punkshell_module_punk::args {args parsing}} {doc/files/project_changes.html punkshell__project_changes {punkshell Changes}} {doc/files/punk/_module_encmime-0.1.0.tm.html punkshell_module_punk::encmime {mime encodings related subset of tcllib mime}} {doc/files/punk/_module_char-0.1.0.tm.html punkshell_module_punk::char {character-set and unicode utilities}} {doc/files/punk/_module_uc-0.1.0.tm.html shellspy_module_punk::uc {Module API}} {doc/files/punk/_module_lib-0.1.1.tm.html punkshell_module_punk::lib {punk general utility functions}} {doc/files/punk/_module_assertion-0.1.0.tm.html shellspy_module_punk::assertion {assertion alternative to control::assert}} {doc/files/project_intro.html punkshell__project_intro {Introduction to punkshell}} {doc/files/_module_overtype-1.6.2.tm.html overtype_module_overtype {overtype text layout - ansi aware}} {doc/files/punk/_module_sshrun-0.1.0.tm.html shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}} {doc/files/main.html punkshell {punkshell - Core}} {doc/files/punk/_module_flib-0.1.0.tm.html punkshell_module_punk::flib {flib experimental}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punkshell_module_punk::mix::commandset::project {dec commandset - project}} {doc/files/punk/_module_basictelnet-0.1.0.tm.html shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}} {doc/files/punk/_module_fileline-0.1.0.tm.html punkshell_module_punk::fileline {file line-handling utilities}}}} doc {doc/toc {{doc/files/punk/_module_cap-0.1.0.tm.html punkshell_module_punk::cap {capability provider and handler plugin system}} {doc/files/punk/_module_ansi-0.1.1.tm.html punkshell_module_punk::ansi {Ansi string functions}} {doc/files/punk/repl/_module_codethread-0.1.0.tm.html shellspy_module_punk::repl::codethread {Module API}} {doc/files/punk/_module_path-0.1.0.tm.html punkshell_module_punk::path {Filesystem path utilities}} {doc/files/punk/_module_args-0.1.0.tm.html punkshell_module_punk::args {args parsing}} {doc/files/project_changes.html punkshell__project_changes {punkshell Changes}} {doc/files/punk/_module_encmime-0.1.0.tm.html punkshell_module_punk::encmime {mime encodings related subset of tcllib mime}} {doc/files/punk/_module_char-0.1.0.tm.html punkshell_module_punk::char {character-set and unicode utilities}} {doc/files/punk/_module_uc-0.1.0.tm.html shellspy_module_punk::uc {Module API}} {doc/files/punk/_module_lib-0.1.1.tm.html punkshell_module_punk::lib {punk general utility functions}} {doc/files/punk/_module_assertion-0.1.0.tm.html shellspy_module_punk::assertion {assertion alternative to control::assert}} {doc/files/project_intro.html punkshell__project_intro {Introduction to punkshell}} {doc/files/_module_overtype-1.6.2.tm.html overtype_module_overtype {overtype text layout - ansi aware}} {doc/files/_module_argparsingtest-0.1.0.tm.html shellspy_module_argparsingtest {Module API}} {doc/files/_module_overtype-1.6.3.tm.html overtype_module_overtype {overtype text layout - ansi aware}} {doc/files/punk/_module_sshrun-0.1.0.tm.html shellspy_module_punk::sshrun {Tcl procedures to execute tcl scripts in remote hosts}} {doc/files/punk/_module_island-0.1.0.tm.html shellspy_module_punk::island {filesystem islands for safe interps}} {doc/files/punk/_module_aliascore-0.1.0.tm.html shellspy_module_punk::aliascore {Module API}} {doc/files/main.html punkshell {punkshell - Core}} {doc/files/punk/_module_flib-0.1.0.tm.html punkshell_module_punk::flib {flib experimental}} {doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html punkshell_module_punk::mix::commandset::project {dec commandset - project}} {doc/files/punk/_module_basictelnet-0.1.0.tm.html shellspy_module_punk::basictelnet {basic telnet client - DKF/Wiki}} {doc/files/punk/_module_fileline-0.1.0.tm.html punkshell_module_punk::fileline {file line-handling utilities}}}}

2
src/embedded/www/.xrf

File diff suppressed because one or more lines are too long

187
src/embedded/www/doc/files/_module_argparsingtest-0.1.0.tm.html

@ -0,0 +1,187 @@
<!DOCTYPE html><html><head>
<title>shellspy_module_argparsingtest - -</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
color: black;
}
BODY {
background: #FFFFFF;
color: black;
}
DIV.doctools {
margin-left: 10%;
margin-right: 10%;
}
DIV.doctools H1,DIV.doctools H2 {
margin-left: -5%;
}
H1, H2, H3, H4 {
margin-top: 1em;
font-family: sans-serif;
font-size: large;
color: #005A9C;
background: transparent;
text-align: left;
}
H1.doctools_title {
text-align: center;
}
UL,OL {
margin-right: 0em;
margin-top: 3pt;
margin-bottom: 3pt;
}
UL LI {
list-style: disc;
}
OL LI {
list-style: decimal;
}
DT {
padding-top: 1ex;
}
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
font: normal 12pt/14pt sans-serif;
list-style: none;
}
LI.doctools_section, LI.doctools_subsection {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
PRE {
display: block;
font-family: monospace;
white-space: pre;
margin: 0%;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
padding-left: 1ex;
padding-right: 1ex;
width: 100%;
}
PRE.doctools_example {
color: black;
background: #f5dcb3;
border: 1px solid black;
}
UL.doctools_requirements LI, UL.doctools_syntax LI {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
DIV.doctools_synopsis {
color: black;
background: #80ffff;
border: 1px solid black;
font-family: serif;
margin-top: 1em;
margin-bottom: 1em;
}
UL.doctools_syntax {
margin-top: 1em;
border-top: 1px solid black;
}
UL.doctools_requirements {
margin-bottom: 1em;
border-bottom: 1px solid black;
}
--></style>
</head>
<!-- Generated from file '_module_argparsingtest-0.1.0.tm.man' by tcllib/doctools with format 'html'
-->
<!-- Copyright &amp;copy; 2024
-->
<!-- shellspy_module_argparsingtest.0
-->
<body><hr> [
<a href="../../toc.html">Main Table Of Contents</a>
&#124; <a href="../toc.html">Table Of Contents</a>
&#124; <a href="../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">shellspy_module_argparsingtest(0) 0.1.0 doc &quot;-&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>shellspy_module_argparsingtest - Module API</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">Overview</a>
<ul>
<li class="doctools_subsection"><a href="#subsection1">Concepts</a></li>
<li class="doctools_subsection"><a href="#subsection2">dependencies</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section3">API</a>
<ul>
<li class="doctools_subsection"><a href="#subsection3">Namespace argparsingtest::class</a></li>
<li class="doctools_subsection"><a href="#subsection4">Namespace argparsingtest</a></li>
<li class="doctools_subsection"><a href="#subsection5">Namespace argparsingtest::lib</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section4">Internal</a>
<ul>
<li class="doctools_subsection"><a href="#subsection6">Namespace argparsingtest::system</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">argparsingtest</b></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>-</p>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2>
<p>overview of argparsingtest</p>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>-</p>
</div>
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">dependencies</a></h3>
<p>packages used by argparsingtest</p>
<ul class="doctools_itemized">
<li><p><b class="package">Tcl 8.6</b></p></li>
</ul>
</div>
</div>
<div id="section3" class="doctools_section"><h2><a name="section3">API</a></h2>
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Namespace argparsingtest::class</a></h3>
<p>class definitions</p>
<ol class="doctools_enumerated">
</ol>
</div>
<div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Namespace argparsingtest</a></h3>
<p>Core API functions for argparsingtest</p>
<dl class="doctools_definitions">
</dl>
</div>
<div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace argparsingtest::lib</a></h3>
<p>Secondary functions that are part of the API</p>
<dl class="doctools_definitions">
</dl>
</div>
</div>
<div id="section4" class="doctools_section"><h2><a name="section4">Internal</a></h2>
<div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Namespace argparsingtest::system</a></h3>
<p>Internal functions that are not part of the API</p>
</div>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../index.html#module">module</a></p>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2024</p>
</div>
</div></body></html>

191
src/embedded/www/doc/files/_module_overtype-1.6.3.tm.html

@ -0,0 +1,191 @@
<!DOCTYPE html><html><head>
<title>overtype_module_overtype - overtype text layout</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
color: black;
}
BODY {
background: #FFFFFF;
color: black;
}
DIV.doctools {
margin-left: 10%;
margin-right: 10%;
}
DIV.doctools H1,DIV.doctools H2 {
margin-left: -5%;
}
H1, H2, H3, H4 {
margin-top: 1em;
font-family: sans-serif;
font-size: large;
color: #005A9C;
background: transparent;
text-align: left;
}
H1.doctools_title {
text-align: center;
}
UL,OL {
margin-right: 0em;
margin-top: 3pt;
margin-bottom: 3pt;
}
UL LI {
list-style: disc;
}
OL LI {
list-style: decimal;
}
DT {
padding-top: 1ex;
}
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
font: normal 12pt/14pt sans-serif;
list-style: none;
}
LI.doctools_section, LI.doctools_subsection {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
PRE {
display: block;
font-family: monospace;
white-space: pre;
margin: 0%;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
padding-left: 1ex;
padding-right: 1ex;
width: 100%;
}
PRE.doctools_example {
color: black;
background: #f5dcb3;
border: 1px solid black;
}
UL.doctools_requirements LI, UL.doctools_syntax LI {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
DIV.doctools_synopsis {
color: black;
background: #80ffff;
border: 1px solid black;
font-family: serif;
margin-top: 1em;
margin-bottom: 1em;
}
UL.doctools_syntax {
margin-top: 1em;
border-top: 1px solid black;
}
UL.doctools_requirements {
margin-bottom: 1em;
border-bottom: 1px solid black;
}
--></style>
</head>
<!-- Generated from file '_module_overtype-1.6.3.tm.man' by tcllib/doctools with format 'html'
-->
<!-- Copyright &amp;copy; 2024
-->
<!-- overtype_module_overtype.0
-->
<body><hr> [
<a href="../../toc.html">Main Table Of Contents</a>
&#124; <a href="../toc.html">Table Of Contents</a>
&#124; <a href="../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">overtype_module_overtype(0) 1.6.3 doc &quot;overtype text layout&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>overtype_module_overtype - overtype text layout - ansi aware</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">Overview</a>
<ul>
<li class="doctools_subsection"><a href="#subsection1">Concepts</a></li>
<li class="doctools_subsection"><a href="#subsection2">dependencies</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section3">API</a>
<ul>
<li class="doctools_subsection"><a href="#subsection3">Namespace overtype</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">overtype</b></li>
</ul>
<ul class="doctools_syntax">
<li><a href="#1"><b class="function">overtype::renderspace</b> <i class="arg">args</i></a></li>
<li><a href="#2"><b class="function">overtype::renderline</b> <i class="arg">args</i></a></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>-</p>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2>
<p>overview of overtype</p>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>-</p>
</div>
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">dependencies</a></h3>
<p>packages used by overtype</p>
<ul class="doctools_itemized">
<li><p><b class="package">Tcl 8.6</b></p></li>
<li><p><b class="package">textutil</b></p></li>
<li><p><b class="package">punk::ansi</b></p>
<p>- required to detect, split, strip and calculate lengths of text possibly containing ansi codes</p></li>
<li><p><b class="package">punk::char</b></p>
<p>- box drawing - and also unicode character width determination for proper layout of text with double-column-width chars</p></li>
</ul>
</div>
</div>
<div id="section3" class="doctools_section"><h2><a name="section3">API</a></h2>
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Namespace overtype</a></h3>
<p>Core API functions for overtype</p>
<dl class="doctools_definitions">
<dt><a name="1"><b class="function">overtype::renderspace</b> <i class="arg">args</i></a></dt>
<dd><p>usage: ?-transparent [0|1]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext</p></dd>
<dt><a name="2"><b class="function">overtype::renderline</b> <i class="arg">args</i></a></dt>
<dd><p>renderline is the core engine for overtype string processing (frames &amp; textblocks), and the raw mode commandline repl for the Tcl Punk Shell</p>
<p>It is also a central part of an ansi (micro) virtual terminal-emulator of sorts</p>
<p>This system does a half decent job at rendering 90's ANSI art to manipulable colour text blocks that can be joined &amp; framed for layout display within a unix or windows terminal</p>
<p>Renderline helps maintain ANSI text styling reset/replay codes so that the styling of one block doesn't affect another.</p>
<p>Calling on the punk::ansi library - it can coalesce codes to keep the size down.</p>
<p>It is a giant mess of doing exactly what common wisdom says not to do... lots at once.</p>
<p>renderline is part of the Unicode and ANSI aware Overtype system which 'renders' a block of text onto a static underlay</p>
<p>The underlay is generally expected to be an ordered set of lines or a rectangular text block analogous to a terminal screen - but it can also be ragged in line length, or just blank.</p>
<p>The overlay couuld be similar - in which case it may often be used to overwrite a column or section of the underlay.</p>
<p>The overlay could however be a sequence of ANSI-laden text that jumps all over the place.</p>
<p>renderline itself only deals with a single line - or sometimes a single character. It is generally called from a loop that does further terminal-like or textblock processing.</p>
<p>By suppyling the -info 1 option - it can return various fields indicating the state of the render.</p>
<p>The main 3 are the result, overflow_right, and unapplied.</p>
<p>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.</p></dd>
</dl>
</div>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../index.html#ansi">ansi</a>, <a href="../../index.html#module">module</a>, <a href="../../index.html#text">text</a></p>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2024</p>
</div>
</div></body></html>

187
src/embedded/www/doc/files/punk/_module_aliascore-0.1.0.tm.html

@ -0,0 +1,187 @@
<!DOCTYPE html><html><head>
<title>shellspy_module_punk::aliascore - -</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
color: black;
}
BODY {
background: #FFFFFF;
color: black;
}
DIV.doctools {
margin-left: 10%;
margin-right: 10%;
}
DIV.doctools H1,DIV.doctools H2 {
margin-left: -5%;
}
H1, H2, H3, H4 {
margin-top: 1em;
font-family: sans-serif;
font-size: large;
color: #005A9C;
background: transparent;
text-align: left;
}
H1.doctools_title {
text-align: center;
}
UL,OL {
margin-right: 0em;
margin-top: 3pt;
margin-bottom: 3pt;
}
UL LI {
list-style: disc;
}
OL LI {
list-style: decimal;
}
DT {
padding-top: 1ex;
}
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
font: normal 12pt/14pt sans-serif;
list-style: none;
}
LI.doctools_section, LI.doctools_subsection {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
PRE {
display: block;
font-family: monospace;
white-space: pre;
margin: 0%;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
padding-left: 1ex;
padding-right: 1ex;
width: 100%;
}
PRE.doctools_example {
color: black;
background: #f5dcb3;
border: 1px solid black;
}
UL.doctools_requirements LI, UL.doctools_syntax LI {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
DIV.doctools_synopsis {
color: black;
background: #80ffff;
border: 1px solid black;
font-family: serif;
margin-top: 1em;
margin-bottom: 1em;
}
UL.doctools_syntax {
margin-top: 1em;
border-top: 1px solid black;
}
UL.doctools_requirements {
margin-bottom: 1em;
border-bottom: 1px solid black;
}
--></style>
</head>
<!-- Generated from file '_module_aliascore-0.1.0.tm.man' by tcllib/doctools with format 'html'
-->
<!-- Copyright &amp;copy; 2024
-->
<!-- shellspy_module_punk::aliascore.0
-->
<body><hr> [
<a href="../../../toc.html">Main Table Of Contents</a>
&#124; <a href="../../toc.html">Table Of Contents</a>
&#124; <a href="../../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">shellspy_module_punk::aliascore(0) 0.1.0 doc &quot;-&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>shellspy_module_punk::aliascore - Module API</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">Overview</a>
<ul>
<li class="doctools_subsection"><a href="#subsection1">Concepts</a></li>
<li class="doctools_subsection"><a href="#subsection2">dependencies</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section3">API</a>
<ul>
<li class="doctools_subsection"><a href="#subsection3">Namespace punk::aliascore::class</a></li>
<li class="doctools_subsection"><a href="#subsection4">Namespace punk::aliascore</a></li>
<li class="doctools_subsection"><a href="#subsection5">Namespace punk::aliascore::lib</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section4">Internal</a>
<ul>
<li class="doctools_subsection"><a href="#subsection6">Namespace punk::aliascore::system</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">punk::aliascore</b></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>-</p>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2>
<p>overview of punk::aliascore</p>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>-</p>
</div>
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">dependencies</a></h3>
<p>packages used by punk::aliascore</p>
<ul class="doctools_itemized">
<li><p><b class="package">Tcl 8.6</b></p></li>
</ul>
</div>
</div>
<div id="section3" class="doctools_section"><h2><a name="section3">API</a></h2>
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Namespace punk::aliascore::class</a></h3>
<p>class definitions</p>
<ol class="doctools_enumerated">
</ol>
</div>
<div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Namespace punk::aliascore</a></h3>
<p>Core API functions for punk::aliascore</p>
<dl class="doctools_definitions">
</dl>
</div>
<div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::aliascore::lib</a></h3>
<p>Secondary functions that are part of the API</p>
<dl class="doctools_definitions">
</dl>
</div>
</div>
<div id="section4" class="doctools_section"><h2><a name="section4">Internal</a></h2>
<div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Namespace punk::aliascore::system</a></h3>
<p>Internal functions that are not part of the API</p>
</div>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../../index.html#module">module</a></p>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2024</p>
</div>
</div></body></html>

210
src/embedded/www/doc/files/punk/_module_ansi-0.1.1.tm.html

@ -141,55 +141,54 @@
<li><a href="#3"><b class="function">a?</b> <span class="opt">?ansicode...?</span></a></li> <li><a href="#3"><b class="function">a?</b> <span class="opt">?ansicode...?</span></a></li>
<li><a href="#4"><b class="function">a+</b> <span class="opt">?ansicode...?</span></a></li> <li><a href="#4"><b class="function">a+</b> <span class="opt">?ansicode...?</span></a></li>
<li><a href="#5"><b class="function">a</b> <span class="opt">?ansicode...?</span></a></li> <li><a href="#5"><b class="function">a</b> <span class="opt">?ansicode...?</span></a></li>
<li><a href="#6"><b class="function">a</b> <span class="opt">?ansicode...?</span></a></li> <li><a href="#6"><b class="function">get_code_name</b> <i class="arg">code</i></a></li>
<li><a href="#7"><b class="function">get_code_name</b> <i class="arg">code</i></a></li> <li><a href="#7"><b class="function">reset</b></a></li>
<li><a href="#8"><b class="function">reset</b></a></li> <li><a href="#8"><b class="function">reset_soft</b></a></li>
<li><a href="#9"><b class="function">reset_soft</b></a></li> <li><a href="#9"><b class="function">reset_colour</b></a></li>
<li><a href="#10"><b class="function">reset_colour</b></a></li> <li><a href="#10"><b class="function">clear</b></a></li>
<li><a href="#11"><b class="function">clear</b></a></li> <li><a href="#11"><b class="function">clear_above</b></a></li>
<li><a href="#12"><b class="function">clear_above</b></a></li> <li><a href="#12"><b class="function">clear_below</b></a></li>
<li><a href="#13"><b class="function">clear_below</b></a></li> <li><a href="#13"><b class="function">cursor_on</b></a></li>
<li><a href="#14"><b class="function">cursor_on</b></a></li> <li><a href="#14"><b class="function">cursor_off</b></a></li>
<li><a href="#15"><b class="function">cursor_off</b></a></li> <li><a href="#15"><b class="function">move</b> <i class="arg">row</i> <i class="arg">col</i></a></li>
<li><a href="#16"><b class="function">move</b> <i class="arg">row</i> <i class="arg">col</i></a></li> <li><a href="#16"><b class="function">move_emit</b> <i class="arg">row</i> <i class="arg">col</i> <i class="arg">data</i> <span class="opt">?row col data...?</span></a></li>
<li><a href="#17"><b class="function">move_emit</b> <i class="arg">row</i> <i class="arg">col</i> <i class="arg">data</i> <span class="opt">?row col data...?</span></a></li> <li><a href="#17"><b class="function">move_forward</b> <i class="arg">n</i></a></li>
<li><a href="#18"><b class="function">move_forward</b> <i class="arg">n</i></a></li> <li><a href="#18"><b class="function">move_back</b> <i class="arg">n</i></a></li>
<li><a href="#19"><b class="function">move_back</b> <i class="arg">n</i></a></li> <li><a href="#19"><b class="function">move_up</b> <i class="arg">n</i></a></li>
<li><a href="#20"><b class="function">move_up</b> <i class="arg">n</i></a></li> <li><a href="#20"><b class="function">move_down</b> <i class="arg">n</i></a></li>
<li><a href="#21"><b class="function">move_down</b> <i class="arg">n</i></a></li> <li><a href="#21"><b class="function">move_column</b> <i class="arg">col</i></a></li>
<li><a href="#22"><b class="function">move_column</b> <i class="arg">col</i></a></li> <li><a href="#22"><b class="function">move_row</b> <i class="arg">row</i></a></li>
<li><a href="#23"><b class="function">move_row</b> <i class="arg">row</i></a></li> <li><a href="#23"><b class="function">cursor_save</b></a></li>
<li><a href="#24"><b class="function">cursor_save</b></a></li> <li><a href="#24"><b class="function">cursor_restore</b></a></li>
<li><a href="#25"><b class="function">cursor_restore</b></a></li> <li><a href="#25"><b class="function">cursor_save_dec</b></a></li>
<li><a href="#26"><b class="function">cursor_save_dec</b></a></li> <li><a href="#26"><b class="function">cursor_restore_attributes</b></a></li>
<li><a href="#27"><b class="function">cursor_restore_attributes</b></a></li> <li><a href="#27"><b class="function">enable_line_wrap</b></a></li>
<li><a href="#28"><b class="function">enable_line_wrap</b></a></li> <li><a href="#28"><b class="function">disable_line_wrap</b></a></li>
<li><a href="#29"><b class="function">disable_line_wrap</b></a></li> <li><a href="#29"><b class="function">query_mode_line_wrap</b></a></li>
<li><a href="#30"><b class="function">query_mode_line_wrap</b></a></li> <li><a href="#30"><b class="function">erase_line</b></a></li>
<li><a href="#31"><b class="function">erase_line</b></a></li> <li><a href="#31"><b class="function">erase_sol</b></a></li>
<li><a href="#32"><b class="function">erase_sol</b></a></li> <li><a href="#32"><b class="function">erase_eol</b></a></li>
<li><a href="#33"><b class="function">erase_eol</b></a></li> <li><a href="#33"><b class="function">scroll_up</b> <i class="arg">n</i></a></li>
<li><a href="#34"><b class="function">scroll_up</b> <i class="arg">n</i></a></li> <li><a href="#34"><b class="function">scroll_down</b> <i class="arg">n</i></a></li>
<li><a href="#35"><b class="function">scroll_down</b> <i class="arg">n</i></a></li> <li><a href="#35"><b class="function">insert_spaces</b> <i class="arg">count</i></a></li>
<li><a href="#36"><b class="function">insert_spaces</b> <i class="arg">count</i></a></li> <li><a href="#36"><b class="function">delete_characters</b> <i class="arg">count</i></a></li>
<li><a href="#37"><b class="function">delete_characters</b> <i class="arg">count</i></a></li> <li><a href="#37"><b class="function">erase_characters</b> <i class="arg">count</i></a></li>
<li><a href="#38"><b class="function">erase_characters</b> <i class="arg">count</i></a></li> <li><a href="#38"><b class="function">insert_lines</b> <i class="arg">count</i></a></li>
<li><a href="#39"><b class="function">insert_lines</b> <i class="arg">count</i></a></li> <li><a href="#39"><b class="function">delete_lines</b> <i class="arg">count</i></a></li>
<li><a href="#40"><b class="function">delete_lines</b> <i class="arg">count</i></a></li> <li><a href="#40"><b class="function">cursor_pos</b></a></li>
<li><a href="#41"><b class="function">cursor_pos</b></a></li> <li><a href="#41"><b class="function">request_cursor_information</b></a></li>
<li><a href="#42"><b class="function">request_cursor_information</b></a></li> <li><a href="#42"><b class="function">request_tabstops</b></a></li>
<li><a href="#43"><b class="function">request_tabstops</b></a></li> <li><a href="#43"><b class="function">titleset</b> <i class="arg">windowtitles</i></a></li>
<li><a href="#44"><b class="function">titleset</b> <i class="arg">windowtitles</i></a></li> <li><a href="#44"><b class="function">is_sgr_reset</b> <i class="arg">code</i></a></li>
<li><a href="#45"><b class="function">is_sgr_reset</b> <i class="arg">code</i></a></li> <li><a href="#45"><b class="function">has_sgr_leadingreset</b> <i class="arg">code</i></a></li>
<li><a href="#46"><b class="function">has_sgr_leadingreset</b> <i class="arg">code</i></a></li> <li><a href="#46"><b class="function">detect</b> <i class="arg">text</i></a></li>
<li><a href="#47"><b class="function">detect</b> <i class="arg">text</i></a></li> <li><a href="#47"><b class="function">detect_csi</b> <i class="arg">text</i></a></li>
<li><a href="#48"><b class="function">detect_csi</b> <i class="arg">text</i></a></li> <li><a href="#48"><b class="function">detect_sgr</b> <i class="arg">text</i></a></li>
<li><a href="#49"><b class="function">detect_sgr</b> <i class="arg">text</i></a></li> <li><a href="#49"><b class="function">strip</b> <i class="arg">text</i></a></li>
<li><a href="#50"><b class="function">strip</b> <i class="arg">text</i></a></li> <li><a href="#50"><b class="function">length</b> <i class="arg">text</i></a></li>
<li><a href="#51"><b class="function">length</b> <i class="arg">text</i></a></li> <li><a href="#51"><b class="function">VIEW</b> <i class="arg">string</i></a></li>
<li><a href="#52"><b class="function">VIEW</b> <i class="arg">string</i></a></li> <li><a href="#52"><b class="function">COUNT</b> <i class="arg">string</i></a></li>
<li><a href="#53"><b class="function">COUNT</b> <i class="arg">string</i></a></li> <li><a href="#53"><b class="function">index</b> <i class="arg">string</i> <i class="arg">index</i></a></li>
<li><a href="#54"><b class="function">index</b> <i class="arg">string</i> <i class="arg">index</i></a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -224,7 +223,14 @@
<dt><a name="2"><b class="function">stripansi</b> <i class="arg">text</i></a></dt> <dt><a name="2"><b class="function">stripansi</b> <i class="arg">text</i></a></dt>
<dd><p>Return a string with ansi codes stripped out</p> <dd><p>Return a string with ansi codes stripped out</p>
<p>Alternate graphics modes will be stripped - exposing the raw characters as they appear without graphics mode.</p> <p>Alternate graphics modes will be stripped - exposing the raw characters as they appear without graphics mode.</p>
<p>ie instead of a horizontal line you may see: qqqqqq</p></dd> <p>ie instead of a horizontal line you may see: qqqqqq
e.g who is to know that 'Rabbit Paws', 'Forbidden Thrill' and 'Tarsier' refer to a particular shade of pinky-red? (code 95)
Perhaps it's an indication that colour naming once we get to 256 colours or more is a fool's errand anyway.
The xterm names are boringly unimaginative - and also have some oddities such as:
DarkSlateGray1 which looks much more like cyan..
The greyxx names are spelt with an e - but the darkslategrayX variants use an a. Perhaps that's because they are more cyan than grey and the a is a hint?
there is no gold or gold2 - but there is gold1 and gold3
but in general the names bear some resemblance to the colours and are at least somewhat intuitive.</p></dd>
<dt><a name="3"><b class="function">a?</b> <span class="opt">?ansicode...?</span></a></dt> <dt><a name="3"><b class="function">a?</b> <span class="opt">?ansicode...?</span></a></dt>
<dd><p>Return an ansi string representing a table of codes and a panel showing the colours</p></dd> <dd><p>Return an ansi string representing a table of codes and a panel showing the colours</p></dd>
<dt><a name="4"><b class="function">a+</b> <span class="opt">?ansicode...?</span></a></dt> <dt><a name="4"><b class="function">a+</b> <span class="opt">?ansicode...?</span></a></dt>
@ -242,38 +248,30 @@
<p>to set background red</p> <p>to set background red</p>
<p>punk::ansi::a Red</p> <p>punk::ansi::a Red</p>
<p>see <b class="cmd">punk::ansi::a?</b> to display a list of codes</p></dd> <p>see <b class="cmd">punk::ansi::a?</b> to display a list of codes</p></dd>
<dt><a name="6"><b class="function">a</b> <span class="opt">?ansicode...?</span></a></dt> <dt><a name="6"><b class="function">get_code_name</b> <i class="arg">code</i></a></dt>
<dd><p>Returns the ansi code to reset any current settings and apply those from the supplied list</p>
<p>by calling punk::ansi::a with no arguments - the result is a reset to plain text</p>
<p>e.g to set foreground red and bold</p>
<p>punk::ansi::a red bold</p>
<p>to set background red</p>
<p>punk::ansi::a Red</p>
<p>see <b class="cmd">punk::ansi::a?</b> to display a list of codes</p></dd>
<dt><a name="7"><b class="function">get_code_name</b> <i class="arg">code</i></a></dt>
<dd><p>for example</p> <dd><p>for example</p>
<p>get_code_name red will return 31</p> <p>get_code_name red will return 31</p>
<p>get_code_name 31 will return red</p></dd> <p>get_code_name 31 will return red</p></dd>
<dt><a name="8"><b class="function">reset</b></a></dt> <dt><a name="7"><b class="function">reset</b></a></dt>
<dd><p>reset console</p></dd> <dd><p>reset console</p></dd>
<dt><a name="9"><b class="function">reset_soft</b></a></dt> <dt><a name="8"><b class="function">reset_soft</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="10"><b class="function">reset_colour</b></a></dt> <dt><a name="9"><b class="function">reset_colour</b></a></dt>
<dd><p>reset colour only</p></dd> <dd><p>reset colour only</p></dd>
<dt><a name="11"><b class="function">clear</b></a></dt> <dt><a name="10"><b class="function">clear</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="12"><b class="function">clear_above</b></a></dt> <dt><a name="11"><b class="function">clear_above</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="13"><b class="function">clear_below</b></a></dt> <dt><a name="12"><b class="function">clear_below</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="14"><b class="function">cursor_on</b></a></dt> <dt><a name="13"><b class="function">cursor_on</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="15"><b class="function">cursor_off</b></a></dt> <dt><a name="14"><b class="function">cursor_off</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="16"><b class="function">move</b> <i class="arg">row</i> <i class="arg">col</i></a></dt> <dt><a name="15"><b class="function">move</b> <i class="arg">row</i> <i class="arg">col</i></a></dt>
<dd><p>Return an ansi sequence to move to row,col</p> <dd><p>Return an ansi sequence to move to row,col</p>
<p>aka cursor home</p></dd> <p>aka cursor home</p></dd>
<dt><a name="17"><b class="function">move_emit</b> <i class="arg">row</i> <i class="arg">col</i> <i class="arg">data</i> <span class="opt">?row col data...?</span></a></dt> <dt><a name="16"><b class="function">move_emit</b> <i class="arg">row</i> <i class="arg">col</i> <i class="arg">data</i> <span class="opt">?row col data...?</span></a></dt>
<dd><p>Return an ansi string representing a move to row col with data appended</p> <dd><p>Return an ansi string representing a move to row col with data appended</p>
<p>row col data can be repeated any number of times to return a string representing the output of the data elements at all those points</p> <p>row col data can be repeated any number of times to return a string representing the output of the data elements at all those points</p>
<p>Compare to punk::console::move_emit which calls this function - but writes it to stdout</p> <p>Compare to punk::console::move_emit which calls this function - but writes it to stdout</p>
@ -285,76 +283,76 @@
<p>The following example shows how to do this manually, emitting the string blah at screen position 10,10 and emitting DONE back at the line we started:</p> <p>The following example shows how to do this manually, emitting the string blah at screen position 10,10 and emitting DONE back at the line we started:</p>
<pre class="doctools_example">punk::ansi::move_emit 10 10 blah {*}[punk::console::get_cursor_pos_list] DONE</pre> <pre class="doctools_example">punk::ansi::move_emit 10 10 blah {*}[punk::console::get_cursor_pos_list] DONE</pre>
<p>A string created by any move_emit_return for punk::ansi would not behave in an intuitive manner compared to other punk::ansi move functions - so is deliberately omitted.</p></dd> <p>A string created by any move_emit_return for punk::ansi would not behave in an intuitive manner compared to other punk::ansi move functions - so is deliberately omitted.</p></dd>
<dt><a name="18"><b class="function">move_forward</b> <i class="arg">n</i></a></dt> <dt><a name="17"><b class="function">move_forward</b> <i class="arg">n</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="19"><b class="function">move_back</b> <i class="arg">n</i></a></dt> <dt><a name="18"><b class="function">move_back</b> <i class="arg">n</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="20"><b class="function">move_up</b> <i class="arg">n</i></a></dt> <dt><a name="19"><b class="function">move_up</b> <i class="arg">n</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="21"><b class="function">move_down</b> <i class="arg">n</i></a></dt> <dt><a name="20"><b class="function">move_down</b> <i class="arg">n</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="22"><b class="function">move_column</b> <i class="arg">col</i></a></dt> <dt><a name="21"><b class="function">move_column</b> <i class="arg">col</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="23"><b class="function">move_row</b> <i class="arg">row</i></a></dt> <dt><a name="22"><b class="function">move_row</b> <i class="arg">row</i></a></dt>
<dd><p>VPA - Vertical Line Position Absolute</p></dd> <dd><p>VPA - Vertical Line Position Absolute</p></dd>
<dt><a name="24"><b class="function">cursor_save</b></a></dt> <dt><a name="23"><b class="function">cursor_save</b></a></dt>
<dd><p>equivalent term::ansi::code::ctrl::sc</p> <dd><p>equivalent term::ansi::code::ctrl::sc</p>
<p>This is the ANSI/SCO cursor save as opposed to the DECSC version</p> <p>This is the ANSI/SCO cursor save as opposed to the DECSC version</p>
<p>On many terminals either will work - but cursor_save_dec is shorter and perhaps more widely supported</p></dd> <p>On many terminals either will work - but cursor_save_dec is shorter and perhaps more widely supported</p></dd>
<dt><a name="25"><b class="function">cursor_restore</b></a></dt> <dt><a name="24"><b class="function">cursor_restore</b></a></dt>
<dd><p>equivalent term::ansi::code::ctrl::rc</p> <dd><p>equivalent term::ansi::code::ctrl::rc</p>
<p>ANSI/SCO - see also cursor_restore_dec for the DECRC version</p></dd> <p>ANSI/SCO - see also cursor_restore_dec for the DECRC version</p></dd>
<dt><a name="26"><b class="function">cursor_save_dec</b></a></dt> <dt><a name="25"><b class="function">cursor_save_dec</b></a></dt>
<dd><p>equivalent term::ansi::code::ctrl::sca</p> <dd><p>equivalent term::ansi::code::ctrl::sca</p>
<p>DECSC</p></dd> <p>DECSC</p></dd>
<dt><a name="27"><b class="function">cursor_restore_attributes</b></a></dt> <dt><a name="26"><b class="function">cursor_restore_attributes</b></a></dt>
<dd><p>equivalent term::ansi::code::ctrl::rca</p> <dd><p>equivalent term::ansi::code::ctrl::rca</p>
<p>DECRC</p></dd> <p>DECRC</p></dd>
<dt><a name="28"><b class="function">enable_line_wrap</b></a></dt> <dt><a name="27"><b class="function">enable_line_wrap</b></a></dt>
<dd><p>enable automatic line wrapping when characters entered beyond rightmost column</p> <dd><p>enable automatic line wrapping when characters entered beyond rightmost column</p>
<p>This will also allow forward movements to move to subsequent lines</p> <p>This will also allow forward movements to move to subsequent lines</p>
<p>This is DECAWM - and is the same sequence output by 'tput smam'</p></dd> <p>This is DECAWM - and is the same sequence output by 'tput smam'</p></dd>
<dt><a name="29"><b class="function">disable_line_wrap</b></a></dt> <dt><a name="28"><b class="function">disable_line_wrap</b></a></dt>
<dd><p>disable automatic line wrapping</p> <dd><p>disable automatic line wrapping</p>
<p>reset DECAWM - same sequence output by 'tput rmam' <p>reset DECAWM - same sequence output by 'tput rmam'
tput rmam</p></dd> tput rmam</p></dd>
<dt><a name="30"><b class="function">query_mode_line_wrap</b></a></dt> <dt><a name="29"><b class="function">query_mode_line_wrap</b></a></dt>
<dd><p>DECRQM to query line-wrap state</p> <dd><p>DECRQM to query line-wrap state</p>
<p>The punk::ansi::query_mode_ functions just emit the ansi query sequence.</p></dd> <p>The punk::ansi::query_mode_ functions just emit the ansi query sequence.</p></dd>
<dt><a name="31"><b class="function">erase_line</b></a></dt> <dt><a name="30"><b class="function">erase_line</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="32"><b class="function">erase_sol</b></a></dt> <dt><a name="31"><b class="function">erase_sol</b></a></dt>
<dd><p>Erase to start of line, leaving cursor position alone.</p></dd> <dd><p>Erase to start of line, leaving cursor position alone.</p></dd>
<dt><a name="33"><b class="function">erase_eol</b></a></dt> <dt><a name="32"><b class="function">erase_eol</b></a></dt>
<dd></dd> <dd></dd>
<dt><a name="34"><b class="function">scroll_up</b> <i class="arg">n</i></a></dt> <dt><a name="33"><b class="function">scroll_up</b> <i class="arg">n</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="35"><b class="function">scroll_down</b> <i class="arg">n</i></a></dt> <dt><a name="34"><b class="function">scroll_down</b> <i class="arg">n</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="36"><b class="function">insert_spaces</b> <i class="arg">count</i></a></dt> <dt><a name="35"><b class="function">insert_spaces</b> <i class="arg">count</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="37"><b class="function">delete_characters</b> <i class="arg">count</i></a></dt> <dt><a name="36"><b class="function">delete_characters</b> <i class="arg">count</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="38"><b class="function">erase_characters</b> <i class="arg">count</i></a></dt> <dt><a name="37"><b class="function">erase_characters</b> <i class="arg">count</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="39"><b class="function">insert_lines</b> <i class="arg">count</i></a></dt> <dt><a name="38"><b class="function">insert_lines</b> <i class="arg">count</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="40"><b class="function">delete_lines</b> <i class="arg">count</i></a></dt> <dt><a name="39"><b class="function">delete_lines</b> <i class="arg">count</i></a></dt>
<dd></dd> <dd></dd>
<dt><a name="41"><b class="function">cursor_pos</b></a></dt> <dt><a name="40"><b class="function">cursor_pos</b></a></dt>
<dd><p>cursor_pos unlikely to be useful on it's own like this as when written to the terminal, this sequence causes the terminal to emit the row;col sequence to stdin</p> <dd><p>cursor_pos unlikely to be useful on it's own like this as when written to the terminal, this sequence causes the terminal to emit the row;col sequence to stdin</p>
<p>The output on screen will look something like ^[[47;3R</p> <p>The output on screen will look something like ^[[47;3R</p>
<p>Use punk::console::get_cursor_pos or punk::console::get_cursor_pos_list instead.</p> <p>Use punk::console::get_cursor_pos or punk::console::get_cursor_pos_list instead.</p>
<p>These functions will emit the code - but read it in from stdin so that it doesn't display, and then return the row and column as a colon-delimited string or list respectively.</p> <p>These functions will emit the code - but read it in from stdin so that it doesn't display, and then return the row and column as a colon-delimited string or list respectively.</p>
<p>The punk::ansi::cursor_pos function is used by punk::console::get_cursor_pos and punk::console::get_cursor_pos_list</p></dd> <p>The punk::ansi::cursor_pos function is used by punk::console::get_cursor_pos and punk::console::get_cursor_pos_list</p></dd>
<dt><a name="42"><b class="function">request_cursor_information</b></a></dt> <dt><a name="41"><b class="function">request_cursor_information</b></a></dt>
<dd><p>DECRQPSR (DEC Request Presentation State Report) for DECCCIR Cursor Information report</p> <dd><p>DECRQPSR (DEC Request Presentation State Report) for DECCCIR Cursor Information report</p>
<p>When written to the terminal, this sequence causes the terminal to emit cursor information to stdin</p> <p>When written to the terminal, this sequence causes the terminal to emit cursor information to stdin</p>
<p>A stdin readloop will need to be in place to read this information</p></dd> <p>A stdin readloop will need to be in place to read this information</p></dd>
<dt><a name="43"><b class="function">request_tabstops</b></a></dt> <dt><a name="42"><b class="function">request_tabstops</b></a></dt>
<dd><p>DECRQPSR (DEC Request Presentation State Report) for DECTABSR Tab stop report</p> <dd><p>DECRQPSR (DEC Request Presentation State Report) for DECTABSR Tab stop report</p>
<p>When written to the terminal, this sequence causes the terminal to emit tabstop information to stdin</p></dd> <p>When written to the terminal, this sequence causes the terminal to emit tabstop information to stdin</p></dd>
<dt><a name="44"><b class="function">titleset</b> <i class="arg">windowtitles</i></a></dt> <dt><a name="43"><b class="function">titleset</b> <i class="arg">windowtitles</i></a></dt>
<dd><p>Returns the code to set the title of the terminal window to windowtitle</p> <dd><p>Returns the code to set the title of the terminal window to windowtitle</p>
<p>This may not work on terminals which have multiple panes/windows</p></dd> <p>This may not work on terminals which have multiple panes/windows</p></dd>
</dl> </dl>
@ -363,11 +361,11 @@ tput rmam</p></dd>
<p>API functions for punk::ansi::codetype</p> <p>API functions for punk::ansi::codetype</p>
<p>Utility functions for processing ansi code sequences</p> <p>Utility functions for processing ansi code sequences</p>
<dl class="doctools_definitions"> <dl class="doctools_definitions">
<dt><a name="45"><b class="function">is_sgr_reset</b> <i class="arg">code</i></a></dt> <dt><a name="44"><b class="function">is_sgr_reset</b> <i class="arg">code</i></a></dt>
<dd><p>Return a boolean indicating whether this string has a trailing pure SGR reset</p> <dd><p>Return a boolean indicating whether this string has a trailing pure SGR reset</p>
<p>Note that if the reset is not the very last item in the string - it will not be detected.</p> <p>Note that if the reset is not the very last item in the string - it will not be detected.</p>
<p>This is primarily intended for testing a single ansi code sequence, but code can be any string where the trailing SGR code is to be tested.</p></dd> <p>This is primarily intended for testing a single ansi code sequence, but code can be any string where the trailing SGR code is to be tested.</p></dd>
<dt><a name="46"><b class="function">has_sgr_leadingreset</b> <i class="arg">code</i></a></dt> <dt><a name="45"><b class="function">has_sgr_leadingreset</b> <i class="arg">code</i></a></dt>
<dd><p>The reset must be the very first item in code to be detected. Trailing strings/codes ignored.</p></dd> <dd><p>The reset must be the very first item in code to be detected. Trailing strings/codes ignored.</p></dd>
</dl> </dl>
</div> </div>
@ -376,25 +374,25 @@ tput rmam</p></dd>
<p>based on but not identical to the Perl Text Ansi module:</p> <p>based on but not identical to the Perl Text Ansi module:</p>
<p>https://github.com/perlancar/perl-Text-ANSI-Util/blob/master/lib/Text/ANSI/BaseUtil.pm</p> <p>https://github.com/perlancar/perl-Text-ANSI-Util/blob/master/lib/Text/ANSI/BaseUtil.pm</p>
<dl class="doctools_definitions"> <dl class="doctools_definitions">
<dt><a name="47"><b class="function">detect</b> <i class="arg">text</i></a></dt> <dt><a name="46"><b class="function">detect</b> <i class="arg">text</i></a></dt>
<dd><p>Return a boolean indicating whether Ansi codes were detected in text</p></dd> <dd><p>Return a boolean indicating whether Ansi codes were detected in text</p></dd>
<dt><a name="48"><b class="function">detect_csi</b> <i class="arg">text</i></a></dt> <dt><a name="47"><b class="function">detect_csi</b> <i class="arg">text</i></a></dt>
<dd><p>Return a boolean indicating whether an Ansi Control Sequence Introducer (CSI) was detected in text</p> <dd><p>Return a boolean indicating whether an Ansi Control Sequence Introducer (CSI) was detected in text</p>
<p>The csi is often represented in code as \x1b or \033 followed by a left bracket [</p> <p>The csi is often represented in code as \x1b or \033 followed by a left bracket [</p>
<p>The initial byte or escape is commonly referenced as ESC in Ansi documentation</p> <p>The initial byte or escape is commonly referenced as ESC in Ansi documentation</p>
<p>There is also a multi-byte escape sequence \u009b</p> <p>There is also a multi-byte escape sequence \u009b</p>
<p>This is less commonly used but is also detected here</p> <p>This is less commonly used but is also detected here</p>
<p>(This function is not in perl ta)</p></dd> <p>(This function is not in perl ta)</p></dd>
<dt><a name="49"><b class="function">detect_sgr</b> <i class="arg">text</i></a></dt> <dt><a name="48"><b class="function">detect_sgr</b> <i class="arg">text</i></a></dt>
<dd><p>Return a boolean indicating whether an ansi Select Graphics Rendition code was detected.</p> <dd><p>Return a boolean indicating whether an ansi Select Graphics Rendition code was detected.</p>
<p>This is the set of CSI sequences ending in 'm'</p> <p>This is the set of CSI sequences ending in 'm'</p>
<p>This is most commonly an Ansi colour code - but also things such as underline and italics</p> <p>This is most commonly an Ansi colour code - but also things such as underline and italics</p>
<p>An SGR with empty or a single zero argument is a reset of the SGR features - this is also detected.</p> <p>An SGR with empty or a single zero argument is a reset of the SGR features - this is also detected.</p>
<p>(This function is not in perl ta)</p></dd> <p>(This function is not in perl ta)</p></dd>
<dt><a name="50"><b class="function">strip</b> <i class="arg">text</i></a></dt> <dt><a name="49"><b class="function">strip</b> <i class="arg">text</i></a></dt>
<dd><p>Return text stripped of Ansi codes</p> <dd><p>Return text stripped of Ansi codes</p>
<p>This is a tailcall to punk::ansi::stripansi</p></dd> <p>This is a tailcall to punk::ansi::stripansi</p></dd>
<dt><a name="51"><b class="function">length</b> <i class="arg">text</i></a></dt> <dt><a name="50"><b class="function">length</b> <i class="arg">text</i></a></dt>
<dd><p>Return the character length after stripping ansi codes - not the printing length</p></dd> <dd><p>Return the character length after stripping ansi codes - not the printing length</p></dd>
</dl> </dl>
</div> </div>
@ -403,12 +401,12 @@ tput rmam</p></dd>
<p>Working with strings containing ansi in a way that preserves/understands the codes is always going to be significantly slower than working with plain strings</p> <p>Working with strings containing ansi in a way that preserves/understands the codes is always going to be significantly slower than working with plain strings</p>
<p>Just as working with other forms of markup such as HTML - you simply need to be aware of the tradeoffs and design accordingly.</p> <p>Just as working with other forms of markup such as HTML - you simply need to be aware of the tradeoffs and design accordingly.</p>
<dl class="doctools_definitions"> <dl class="doctools_definitions">
<dt><a name="52"><b class="function">VIEW</b> <i class="arg">string</i></a></dt> <dt><a name="51"><b class="function">VIEW</b> <i class="arg">string</i></a></dt>
<dd><p>Return a string with specific ANSI control characters substituted with visual equivalents frome the appropriate unicode C0 and C1 visualisation sets</p> <dd><p>Return a string with specific ANSI control characters substituted with visual equivalents frome the appropriate unicode C0 and C1 visualisation sets</p>
<p>For debugging purposes, certain other standard control characters are converted to visual representation, for example backspace (mapped to \\U2408 '\U2408')</p> <p>For debugging purposes, certain other standard control characters are converted to visual representation, for example backspace (mapped to \\U2408 '\U2408')</p>
<p>Horizontal tab is mapped to \\U2409 '\U2409'. For many of the punk terminal text operations, tabs have already been mapped to the appropriate number of spaces using textutil::tabify functions</p> <p>Horizontal tab is mapped to \\U2409 '\U2409'. For many of the punk terminal text operations, tabs have already been mapped to the appropriate number of spaces using textutil::tabify functions</p>
<p>As punkshell uses linefeed where possible in preference to crlf even on windows, cr is mapped to \\U240D '\U240D' - but lf is left as is.</p></dd> <p>As punkshell uses linefeed where possible in preference to crlf even on windows, cr is mapped to \\U240D '\U240D' - but lf is left as is.</p></dd>
<dt><a name="53"><b class="function">COUNT</b> <i class="arg">string</i></a></dt> <dt><a name="52"><b class="function">COUNT</b> <i class="arg">string</i></a></dt>
<dd><p>Returns the count of visible graphemes and non-ansi control characters</p> <dd><p>Returns the count of visible graphemes and non-ansi control characters</p>
<p>Incomplete! grapheme clustering support not yet implemented - only diacritics are currently clustered to count as one grapheme.</p> <p>Incomplete! grapheme clustering support not yet implemented - only diacritics are currently clustered to count as one grapheme.</p>
<p>This will not count strings hidden inside a 'privacy message' or other ansi codes which may have content between their opening escape and their termination sequence.</p> <p>This will not count strings hidden inside a 'privacy message' or other ansi codes which may have content between their opening escape and their termination sequence.</p>
@ -416,7 +414,7 @@ tput rmam</p></dd>
<p>Note that this returns the number of characters in the payload (after applying combiners) <p>Note that this returns the number of characters in the payload (after applying combiners)
It is not always the same as the width of the string as rendered on a terminal due to 2wide Unicode characters and the usual invisible control characters such as \r and \n</p> It is not always the same as the width of the string as rendered on a terminal due to 2wide Unicode characters and the usual invisible control characters such as \r and \n</p>
<p>To get the width, use punk::ansi::printing_length instead, which is also ansi aware.</p></dd> <p>To get the width, use punk::ansi::printing_length instead, which is also ansi aware.</p></dd>
<dt><a name="54"><b class="function">index</b> <i class="arg">string</i> <i class="arg">index</i></a></dt> <dt><a name="53"><b class="function">index</b> <i class="arg">string</i> <i class="arg">index</i></a></dt>
<dd><p>Takes a string that possibly contains ansi codes such as colour,underline etc (SGR codes)</p> <dd><p>Takes a string that possibly contains ansi codes such as colour,underline etc (SGR codes)</p>
<p>Returns the character (with applied ansi effect) at position index</p> <p>Returns the character (with applied ansi effect) at position index</p>
<p>The string could contain non SGR ansi codes - and these will (mostly) be ignored, so shouldn't affect the output.</p> <p>The string could contain non SGR ansi codes - and these will (mostly) be ignored, so shouldn't affect the output.</p>

115
src/embedded/www/doc/files/punk/_module_args-0.1.0.tm.html

@ -141,7 +141,7 @@
<li>package require <b class="pkgname">punk::args</b></li> <li>package require <b class="pkgname">punk::args</b></li>
</ul> </ul>
<ul class="doctools_syntax"> <ul class="doctools_syntax">
<li><a href="#1"><b class="function">opts_values</b> <i class="arg">optionspecs</i> <i class="arg">rawargs</i> <span class="opt">?option value...?</span></a></li> <li><a href="#1"><b class="function">get_dict</b> <i class="arg">optionspecs</i> <i class="arg">rawargs</i> <span class="opt">?option value...?</span></a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -153,19 +153,26 @@
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3> <div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>There are 2 main conventions for parsing a proc args list</p> <p>There are 2 main conventions for parsing a proc args list</p>
<ol class="doctools_enumerated"> <ol class="doctools_enumerated">
<li><p>leading option-value pairs followed by a list of values (Tk style)</p></li> <li><p>leading option-value pairs followed by a list of values (Tcl style)</p></li>
<li><p>leading list of values followed by option-value pairs (Tcl style)</p></li> <li><p>leading list of values followed by option-value pairs (Tk style)</p></li>
</ol> </ol>
<p>punk::args is focused on the 1st convention (Tk style): parsing of args in leading option-value pair style - even for non-Tk usage.</p> <p>There are exceptions in both Tcl and Tk commands regarding this ordering</p>
<p>punk::args is focused on the 1st convention (Tcl style): parsing of the 'args' variable in leading option-value pair style</p>
<p>The proc can still contain some leading required values e.g</p> <p>The proc can still contain some leading required values e.g</p>
<pre class="doctools_example">proc dostuff {arg1 arg2 args} {...}}</pre> <pre class="doctools_example">proc dostuff {arg1 arg2 args} {...}}</pre>
<p>but having the core values elements at the end of args is more generally useful - especially in cases where the number of trailing values is unknown and/or the proc is to be called in a functional 'pipeline' style.</p> <p>but having the core values elements at the end of args is arguably more generally useful - especially in cases where the number of trailing values is unknown and/or the proc is to be called in a functional 'pipeline' style.</p>
<p>The basic principle is that a call to punk::args::opts_vals is made near the beginning of the proc e.g</p> <p>The basic principle is that a call to punk::args::opts_vals is made near the beginning of the proc e.g</p>
<pre class="doctools_example"> <pre class="doctools_example">
proc dofilestuff {args} { proc dofilestuff {args} {
lassign [dict values [punk::args { lassign [dict values [punk::args {
*proc -help &quot;do some stuff with files e.g dofilestuff &lt;file1&gt; &lt;file2&gt; &lt;file3&gt;&quot;
*opts -type string
#comment lines ok
-directory -default &quot;&quot; -directory -default &quot;&quot;
-translation -default binary -translation -default binary
#setting -type none indicates a flag that doesn't take a value (solo flag)
-nocomplain -type none
*values -min 1 -max -1
} $args]] opts values } $args]] opts values
puts &quot;translation is [dict get $opts -translation]&quot; puts &quot;translation is [dict get $opts -translation]&quot;
foreach f [dict values $values] { foreach f [dict values $values] {
@ -173,19 +180,94 @@
} }
} }
</pre> </pre>
<p>The lines beginning with * are optional in most cases and can be used to set defaults and some extra controls</p>
<p>- the above example would work just fine with only the -&lt;optionname&gt; lines, but would allow zero filenames to be supplied as no -min value is set for *values</p>
<p>valid * lines being with *proc *opts *values</p>
<p>lines beginning with a dash define options - a name can optionally be given to each trailing positional argument.</p>
<p>If no names are defined for positional arguments, they will end up in the values key of the dict with numerical keys starting at zero.</p>
<p>e.g the result from the punk::args call above may be something like:</p>
<p>opts {-translation binary -directory &quot;&quot; -nocomplain 0} values {0 file1.txt 1 file2.txt 2 file3.txt}</p>
<p>Here is an example that requires the number of values supplied to be exactly 2 and names the positional arguments</p>
<p>It also demonstrates an inital argument 'category' that is outside of the scope for punk::args processing - allowing leading and trailing positional arguments</p>
<pre class="doctools_example">
proc dofilestuff {category args} {
lassign [dict values [punk::args {
-directory -default &quot;&quot;
-translation -default binary
-nocomplain -type none
*values -min 2 -max 2
fileA -existingfile 1
fileB -existingfile 1
} $args]] opts values
puts &quot;$category fileA: [dict get $values fileA]&quot;
puts &quot;$category fileB: [dict get $values fileB]&quot;
}
</pre>
<p>By using standard tcl proc named arguments prior to args, and setting *values -min 0 -max 0</p>
<p>a Tk-style ordering can be acheived, where punk::args is only handling the trailing flags and the values element of the returned dict can be ignored</p>
<p>This use of leading positional arguments means the type validation features can't be applied to them. It can be done manually as usual,</p>
<p>or an additional call could be made to punk::args e.g</p>
<pre class="doctools_example">
punk::args {
category -choices {cat1 cat2 cat3}
another_leading_arg -type boolean
} [list $category $another_leading_arg]
</pre>
</div> </div>
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Notes</a></h3> <div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">Notes</a></h3>
<p>There are alternative args parsing packages such as:</p> <p>For internal functions not requiring features such as solo flags, prefix matching, type checking etc - a well crafted switch statement will be the fastest pure-tcl solution.</p>
<p>When functions are called often and/or in inner loops, a switch based solution generally makes the most sense.
For functions that are part of an API a package may be more suitable.</p>
<p>The following example shows a switch-based solution that is highly performant (sub microsecond for the no-args case)</p>
<pre class="doctools_example">
proc test1_switch {args} {
set opts [dict create\
-return &quot;object&quot;\
-frametype &quot;heavy&quot;\
-show_edge 1\
-show_seps 0\
-x a\
-y b\
-z c\
-1 1\
-2 2\
-3 3\
]
foreach {k v} $args {
switch -- $k {
-return - -show_edge - -show_seps - -frametype - -x - -y - -z - -1 - -2 - -3 {
dict set opts $k $v
}
default {
error &quot;unrecognised option '$k'. Known options [dict keys $opts]&quot;
}
}
}
return $opts
}
</pre>
<p>Note that the switch statement uses literals so that the compiler produces a jump-table for best performance.</p>
<p>Attempting to build the switch branch using the values from dict keys $opts will stop the jump table being built.
To create the faster switch statement without repeating the key names, the proc body would need to be built using string map.</p>
<p>use punk::lib::show_jump_tables &lt;procname&gt; to verify that a jump table exists.</p>
<p>There are many alternative args parsing packages a few of which are listed here.</p>
<ol class="doctools_enumerated"> <ol class="doctools_enumerated">
<li><p>argp</p></li> <li><p>argp (pure tcl)</p></li>
<li><p>The tcllib set of TEPAM modules</p> <li><p>parse_args (c implementation)</p></li>
<li><p>argparse (pure tcl *)</p></li>
<li><p>cmdline (pure tcl)</p></li>
<li><p>opt (pure tcl) distributed with Tcl but considered deprecated</p></li>
<li><p>The tcllib set of TEPAM modules (pure tcl)</p>
<p>TEPAM requires an alternative procedure declaration syntax instead of proc - but has support for Tk and documentation generation.</p></li> <p>TEPAM requires an alternative procedure declaration syntax instead of proc - but has support for Tk and documentation generation.</p></li>
</ol> </ol>
<p>(* c implementation planned/proposed)</p>
<p>punk::args was designed initially without specific reference to TEPAM - and to handle some edge cases in specific projects where TEPAM wasn't suitable.</p> <p>punk::args was designed initially without specific reference to TEPAM - and to handle some edge cases in specific projects where TEPAM wasn't suitable.</p>
<p>In subsequent revisions of punk::args - some features were made to operate in a way that is similar to TEPAM - to avoid gratuitous differences where possible, but of course there are differences</p> <p>In subsequent revisions of punk::args - some features were made to operate in a way that is similar to TEPAM - to avoid gratuitous differences where possible, but of course there are differences</p>
<p>and those used TEPAM or mixing TEPAM and punk::args should take care to assess the differences.</p> <p>and those used TEPAM or mixing TEPAM and punk::args should take care to assess the differences.</p>
<p>TEPAM is a mature solution and is widely available as it is included in tcllib.</p> <p>TEPAM is a mature solution and is widely available as it is included in tcllib.</p>
<p>Serious consideration should be given to using TEPAM if suitable for your project.</p> <p>Serious consideration should be given to using TEPAM or one of the other packages, if suitable for your project.</p>
<p>punk::args is relatively performant for a pure-tcl solution - with the parsing of the argument specification block occuring only on the first run - after which a cached version of the spec is used.</p>
<p>punk::args is not limited to procs. It can be used in apply or coroutine situations for example.</p>
</div> </div>
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">dependencies</a></h3> <div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">dependencies</a></h3>
<p>packages used by punk::args</p> <p>packages used by punk::args</p>
@ -203,7 +285,7 @@
<div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::args</a></h3> <div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::args</a></h3>
<p>Core API functions for punk::args</p> <p>Core API functions for punk::args</p>
<dl class="doctools_definitions"> <dl class="doctools_definitions">
<dt><a name="1"><b class="function">opts_values</b> <i class="arg">optionspecs</i> <i class="arg">rawargs</i> <span class="opt">?option value...?</span></a></dt> <dt><a name="1"><b class="function">get_dict</b> <i class="arg">optionspecs</i> <i class="arg">rawargs</i> <span class="opt">?option value...?</span></a></dt>
<dd><p>Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values</p> <dd><p>Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values</p>
<p>Returns a dict of the form: opts &lt;options_dict&gt; values &lt;values_dict&gt;</p> <p>Returns a dict of the form: opts &lt;options_dict&gt; values &lt;values_dict&gt;</p>
<p>ARGUMENTS:</p> <p>ARGUMENTS:</p>
@ -211,11 +293,18 @@
<dt>multiline-string <i class="arg">optionspecs</i></dt> <dt>multiline-string <i class="arg">optionspecs</i></dt>
<dd><p>This a block of text with records delimited by newlines (lf or crlf) - but with multiline values allowed if properly quoted/braced</p> <dd><p>This a block of text with records delimited by newlines (lf or crlf) - but with multiline values allowed if properly quoted/braced</p>
<p>'info complete' is used to determine if a record spans multiple lines due to multiline values</p> <p>'info complete' is used to determine if a record spans multiple lines due to multiline values</p>
<p>Each optionspec line must be of the form:</p> <p>Each optionspec line defining a flag must be of the form:</p>
<p>-optionname -key val -key2 val2...</p> <p>-optionname -key val -key2 val2...</p>
<p>where the valid keys for each option specification are: -default -type -range -choices -optional</p></dd> <p>where the valid keys for each option specification are: -default -type -range -choices -optional</p>
<p>Each optionspec line defining a positional argument is of the form:</p>
<p>argumentname -key val -ky2 val2...</p>
<p>where the valid keys for each option specification are: -default -type -range -choices</p>
<p>comment lines begining with # are ignored and can be placed anywhere except within a multiline value where it would become part of that value</p>
<p>lines beginning with *proc *opts or *values also take -key val pairs and can be used to set defaults and control settings.</p>
<p>*opts or *values lines can appear multiple times with defaults affecting flags/values that follow.</p></dd>
<dt>list <i class="arg">rawargs</i></dt> <dt>list <i class="arg">rawargs</i></dt>
<dd><p>This is a list of the arguments to parse. Usually it will be the \$args value from the containing proc</p></dd> <dd><p>This is a list of the arguments to parse. Usually it will be the $args value from the containing proc,
but it could be a manually constructed list of values made for example from positional args defined in the proc.</p></dd>
</dl></dd> </dl></dd>
</dl> </dl>
</div> </div>

304
src/embedded/www/doc/files/punk/_module_island-0.1.0.tm.html

@ -0,0 +1,304 @@
<!DOCTYPE html><html><head>
<title>shellspy_module_punk::island - punk::island for safe interps</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
color: black;
}
BODY {
background: #FFFFFF;
color: black;
}
DIV.doctools {
margin-left: 10%;
margin-right: 10%;
}
DIV.doctools H1,DIV.doctools H2 {
margin-left: -5%;
}
H1, H2, H3, H4 {
margin-top: 1em;
font-family: sans-serif;
font-size: large;
color: #005A9C;
background: transparent;
text-align: left;
}
H1.doctools_title {
text-align: center;
}
UL,OL {
margin-right: 0em;
margin-top: 3pt;
margin-bottom: 3pt;
}
UL LI {
list-style: disc;
}
OL LI {
list-style: decimal;
}
DT {
padding-top: 1ex;
}
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
font: normal 12pt/14pt sans-serif;
list-style: none;
}
LI.doctools_section, LI.doctools_subsection {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
PRE {
display: block;
font-family: monospace;
white-space: pre;
margin: 0%;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
padding-left: 1ex;
padding-right: 1ex;
width: 100%;
}
PRE.doctools_example {
color: black;
background: #f5dcb3;
border: 1px solid black;
}
UL.doctools_requirements LI, UL.doctools_syntax LI {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
DIV.doctools_synopsis {
color: black;
background: #80ffff;
border: 1px solid black;
font-family: serif;
margin-top: 1em;
margin-bottom: 1em;
}
UL.doctools_syntax {
margin-top: 1em;
border-top: 1px solid black;
}
UL.doctools_requirements {
margin-bottom: 1em;
border-bottom: 1px solid black;
}
--></style>
</head>
<!-- Generated from file '_module_island-0.1.0.tm.man' by tcllib/doctools with format 'html'
-->
<!-- Copyright &amp;copy; 2024
-->
<!-- shellspy_module_punk::island.0
-->
<body><hr> [
<a href="../../../toc.html">Main Table Of Contents</a>
&#124; <a href="../../toc.html">Table Of Contents</a>
&#124; <a href="../../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">shellspy_module_punk::island(0) 0.1.0 doc &quot;punk::island for safe interps&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>shellspy_module_punk::island - filesystem islands for safe interps</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">Overview</a>
<ul>
<li class="doctools_subsection"><a href="#subsection1">Concepts</a></li>
<li class="doctools_subsection"><a href="#subsection2">dependencies</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section3">API</a>
<ul>
<li class="doctools_subsection"><a href="#subsection3">Namespace punk::island::class</a></li>
<li class="doctools_subsection"><a href="#subsection4">Namespace punk::island::interps</a></li>
<li class="doctools_subsection"><a href="#subsection5">Namespace punk::island</a></li>
<li class="doctools_subsection"><a href="#subsection6">Namespace punk::island::lib</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section4">Internal</a>
<ul>
<li class="doctools_subsection"><a href="#subsection7">Namespace punk::island::system</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">punk::island</b></li>
</ul>
<ul class="doctools_syntax">
<li><a href="#1"><b class="function">add</b> <i class="arg">child</i> <i class="arg">path</i></a></li>
<li><a href="#2"><b class="function">reset</b> <i class="arg">child</i></a></li>
<li><a href="#3"><b class="function">Allowed</b> <i class="arg">child</i> <i class="arg">fname</i></a></li>
<li><a href="#4"><b class="function">File</b> <i class="arg">child</i> <i class="arg">cmd</i> <i class="arg">args</i></a></li>
<li><a href="#5"><b class="function">Open</b> <i class="arg">child</i> <i class="arg">args</i></a></li>
<li><a href="#6"><b class="function">Expose</b> <i class="arg">child</i> <i class="arg">cmd</i> <i class="arg">args</i></a></li>
<li><a href="#7"><b class="function">Glob</b> <i class="arg">child</i> <i class="arg">args</i></a></li>
<li><a href="#8"><b class="function">Init</b> <i class="arg">child</i></a></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>Package to a allow a safe interpreter to access islands of the</p>
<p>filesystem only, i.e. restricted directory trees within the</p>
<p>filesystem. The package brings back file, open and glob to the child interp</p>
<p>interpreter, though in a restricted manner.</p>
<p>JN Warning:</p>
<p>This mechanism can have interactions with package loading from auto_path - needs review.</p>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2>
<p>overview of punk::island</p>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>-</p>
</div>
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">dependencies</a></h3>
<p>packages used by punk::island</p>
<ul class="doctools_itemized">
<li><p><b class="package">Tcl 8.6</b></p></li>
</ul>
</div>
</div>
<div id="section3" class="doctools_section"><h2><a name="section3">API</a></h2>
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Namespace punk::island::class</a></h3>
<p>class definitions</p>
<ol class="doctools_enumerated">
</ol>
</div>
<div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Namespace punk::island::interps</a></h3>
<p>hosts information for interpreters</p>
<dl class="doctools_definitions">
</dl>
</div>
<div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::island</a></h3>
<p>Core API functions for punk::island</p>
<dl class="doctools_definitions">
<dt><a name="1"><b class="function">add</b> <i class="arg">child</i> <i class="arg">path</i></a></dt>
<dd><p>Add a path to the list of paths that are explicitely allowed for access</p>
<p>to a child interpreter. Access to any path that has not been explicitely</p>
<p>allowed will be denied. Paths that are added to the list of allowed</p>
<p>islands are always fully normalized.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter to control</p></dd>
</dl></dd>
<dt><a name="2"><b class="function">reset</b> <i class="arg">child</i></a></dt>
<dd><p>Remove all access path allowance and arrange for the interpreter to be</p>
<p>able to return to the regular safe state.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter</p></dd>
</dl></dd>
</dl>
</div>
<div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Namespace punk::island::lib</a></h3>
<p>Secondary functions that are part of the API</p>
<dl class="doctools_definitions">
</dl>
</div>
</div>
<div id="section4" class="doctools_section"><h2><a name="section4">Internal</a></h2>
<div id="subsection7" class="doctools_subsection"><h3><a name="subsection7">Namespace punk::island::system</a></h3>
<p>Internal functions that are not part of the API</p>
<dl class="doctools_definitions">
<dt><a name="3"><b class="function">Allowed</b> <i class="arg">child</i> <i class="arg">fname</i></a></dt>
<dd><p>Check that the file name passed as an argument is within the islands of</p>
<p>the filesystem that have been registered through the add command for a</p>
<p>given (safe) interpreter. The path is fully normalized before testing</p>
<p>against the islands, which themselves are fully normalized.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter</p></dd>
<dt>string <i class="arg">fname</i></dt>
<dd><p>(relative) path to the file to test</p></dd>
</dl></dd>
<dt><a name="4"><b class="function">File</b> <i class="arg">child</i> <i class="arg">cmd</i> <i class="arg">args</i></a></dt>
<dd><p>Parses the options and arguments to the file command to discover which</p>
<p>paths it tries to access and only return the results of its execution</p>
<p>when these path are within the allowed islands of the filesystem.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter</p></dd>
<dt>string <i class="arg">cmd</i></dt>
<dd><p>Subcommand of the file command</p></dd>
<dt>string <i class="arg">args</i></dt>
<dd><p>Arguments to the file subcommand</p></dd>
</dl></dd>
<dt><a name="5"><b class="function">Open</b> <i class="arg">child</i> <i class="arg">args</i></a></dt>
<dd><p>Parses the options and arguments to the open command to discover which</p>
<p>paths it tries to access and only return the results of its execution</p>
<p>when these path are within the allowed islands of the filesystem.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter</p></dd>
<dt>string <i class="arg">args</i></dt>
<dd><p>Arguments to the open subcommand</p></dd>
</dl></dd>
<dt><a name="6"><b class="function">Expose</b> <i class="arg">child</i> <i class="arg">cmd</i> <i class="arg">args</i></a></dt>
<dd><p>This procedure allows to callback a command that would typically have</p>
<p>been hidden from a child interpreter. It does not &quot;interp expose&quot; but</p>
<p>rather calls the hidden command, so we can easily revert back.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter</p></dd>
<dt>string <i class="arg">cmd</i></dt>
<dd><p>Hidden command to call</p></dd>
<dt>string <i class="arg">args</i></dt>
<dd><p>Arguments to the command</p></dd>
</dl></dd>
<dt><a name="7"><b class="function">Glob</b> <i class="arg">child</i> <i class="arg">args</i></a></dt>
<dd><p>Parses the options and arguments to the glob command to discover which</p>
<p>paths it tries to access and only return the results of its execution</p>
<p>when these path are within the allowed islands of the filesystem.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter</p></dd>
<dt>string <i class="arg">args</i></dt>
<dd><p>Arguments to the glob command</p></dd>
</dl></dd>
<dt><a name="8"><b class="function">Init</b> <i class="arg">child</i></a></dt>
<dd><p>Initialise child interpreter so that it will be able to perform some</p>
<p>file operations, but only within some islands of the filesystem.</p>
<p>Arguments:</p>
<dl class="doctools_arguments">
<dt>string <i class="arg">child</i></dt>
<dd><p>Identifier of the child interpreter</p></dd>
</dl></dd>
</dl>
</div>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../../index.html#filesystem">filesystem</a>, <a href="../../../index.html#interp">interp</a>, <a href="../../../index.html#module">module</a></p>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2024</p>
</div>
</div></body></html>

17
src/embedded/www/doc/files/punk/_module_lib-0.1.1.tm.html

@ -167,7 +167,6 @@
<li><a href="#25"><b class="function">linesort</b> <span class="opt">?sortoption ?val?...?</span> <i class="arg">textblock</i></a></li> <li><a href="#25"><b class="function">linesort</b> <span class="opt">?sortoption ?val?...?</span> <i class="arg">textblock</i></a></li>
<li><a href="#26"><b class="function">list_as_lines</b> <span class="opt">?-joinchar char?</span> <i class="arg">linelist</i></a></li> <li><a href="#26"><b class="function">list_as_lines</b> <span class="opt">?-joinchar char?</span> <i class="arg">linelist</i></a></li>
<li><a href="#27"><b class="function">lines_as_list</b> <span class="opt">?option value ...?</span> <i class="arg">text</i></a></li> <li><a href="#27"><b class="function">lines_as_list</b> <span class="opt">?option value ...?</span> <i class="arg">text</i></a></li>
<li><a href="#28"><b class="function">opts_values</b> <span class="opt">?option value...?</span> <i class="arg">optionspecs</i> <i class="arg">rawargs</i></a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -217,7 +216,7 @@
<p>We want to resolve the index used, without passing arbitrary expressions into the 'expr' function - which could have security risks.</p> <p>We want to resolve the index used, without passing arbitrary expressions into the 'expr' function - which could have security risks.</p>
<p>lindex_resolve will parse the index expression and return -1 if the supplied index expression is out of bounds for the supplied list.</p> <p>lindex_resolve will parse the index expression and return -1 if the supplied index expression is out of bounds for the supplied list.</p>
<p>Otherwise it will return an integer corresponding to the position in the list.</p> <p>Otherwise it will return an integer corresponding to the position in the list.</p>
<p>Like Tcl list commands - it will produce an error if the form of the</p></dd> <p>Like Tcl list commands - it will produce an error if the form of the index is not acceptable</p></dd>
<dt><a name="4"><b class="function">K</b> <i class="arg">x</i> <i class="arg">y</i></a></dt> <dt><a name="4"><b class="function">K</b> <i class="arg">x</i> <i class="arg">y</i></a></dt>
<dd><p>The K-combinator function - returns the first argument, x and discards y</p> <dd><p>The K-combinator function - returns the first argument, x and discards y</p>
<p>see <a href="https://wiki.tcl-lang.org/page/K">https://wiki.tcl-lang.org/page/K</a></p> <p>see <a href="https://wiki.tcl-lang.org/page/K">https://wiki.tcl-lang.org/page/K</a></p>
@ -336,20 +335,6 @@ but has the disadvantage of being slower for 'small' numbers and using more memo
<dd><p>Returns a list of possibly trimmed lines depeding on options</p> <dd><p>Returns a list of possibly trimmed lines depeding on options</p>
<p>The concept of lines is raw lines from splitting on newline after crlf is mapped to lf</p> <p>The concept of lines is raw lines from splitting on newline after crlf is mapped to lf</p>
<p>- not console lines which may be entirely different due to control characters such as vertical tabs or ANSI movements</p></dd> <p>- not console lines which may be entirely different due to control characters such as vertical tabs or ANSI movements</p></dd>
<dt><a name="28"><b class="function">opts_values</b> <span class="opt">?option value...?</span> <i class="arg">optionspecs</i> <i class="arg">rawargs</i></a></dt>
<dd><p>Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values</p>
<p>Returns a dict of the form: opts &lt;options_dict&gt; values &lt;values_dict&gt;</p>
<p>ARGUMENTS:</p>
<dl class="doctools_arguments">
<dt>multiline-string <i class="arg">optionspecs</i></dt>
<dd><p>This a block of text with records delimited by newlines (lf or crlf) - but with multiline values allowed if properly quoted/braced</p>
<p>'info complete' is used to determine if a record spans multiple lines due to multiline values</p>
<p>Each optionspec line must be of the form:</p>
<p>-optionname -key val -key2 val2...</p>
<p>where the valid keys for each option specification are: -default -type -range -choices -optional</p></dd>
<dt>list <i class="arg">rawargs</i></dt>
<dd><p>This is a list of the arguments to parse. Usually it will be the \$args value from the containing proc</p></dd>
</dl></dd>
</dl> </dl>
</div> </div>
</div> </div>

187
src/embedded/www/doc/files/punk/repl/_module_codethread-0.1.0.tm.html

@ -0,0 +1,187 @@
<!DOCTYPE html><html><head>
<title>shellspy_module_punk::repl::codethread - -</title>
<style type="text/css"><!--
HTML {
background: #FFFFFF;
color: black;
}
BODY {
background: #FFFFFF;
color: black;
}
DIV.doctools {
margin-left: 10%;
margin-right: 10%;
}
DIV.doctools H1,DIV.doctools H2 {
margin-left: -5%;
}
H1, H2, H3, H4 {
margin-top: 1em;
font-family: sans-serif;
font-size: large;
color: #005A9C;
background: transparent;
text-align: left;
}
H1.doctools_title {
text-align: center;
}
UL,OL {
margin-right: 0em;
margin-top: 3pt;
margin-bottom: 3pt;
}
UL LI {
list-style: disc;
}
OL LI {
list-style: decimal;
}
DT {
padding-top: 1ex;
}
UL.doctools_toc,UL.doctools_toc UL, UL.doctools_toc UL UL {
font: normal 12pt/14pt sans-serif;
list-style: none;
}
LI.doctools_section, LI.doctools_subsection {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
PRE {
display: block;
font-family: monospace;
white-space: pre;
margin: 0%;
padding-top: 0.5ex;
padding-bottom: 0.5ex;
padding-left: 1ex;
padding-right: 1ex;
width: 100%;
}
PRE.doctools_example {
color: black;
background: #f5dcb3;
border: 1px solid black;
}
UL.doctools_requirements LI, UL.doctools_syntax LI {
list-style: none;
margin-left: 0em;
text-indent: 0em;
padding: 0em;
}
DIV.doctools_synopsis {
color: black;
background: #80ffff;
border: 1px solid black;
font-family: serif;
margin-top: 1em;
margin-bottom: 1em;
}
UL.doctools_syntax {
margin-top: 1em;
border-top: 1px solid black;
}
UL.doctools_requirements {
margin-bottom: 1em;
border-bottom: 1px solid black;
}
--></style>
</head>
<!-- Generated from file '_module_codethread-0.1.0.tm.man' by tcllib/doctools with format 'html'
-->
<!-- Copyright &amp;copy; 2024
-->
<!-- shellspy_module_punk::repl::codethread.0
-->
<body><hr> [
<a href="../../../../toc.html">Main Table Of Contents</a>
&#124; <a href="../../../toc.html">Table Of Contents</a>
&#124; <a href="../../../../index.html">Keyword Index</a>
] <hr>
<div class="doctools">
<h1 class="doctools_title">shellspy_module_punk::repl::codethread(0) 0.1.0 doc &quot;-&quot;</h1>
<div id="name" class="doctools_section"><h2><a name="name">Name</a></h2>
<p>shellspy_module_punk::repl::codethread - Module API</p>
</div>
<div id="toc" class="doctools_section"><h2><a name="toc">Table Of Contents</a></h2>
<ul class="doctools_toc">
<li class="doctools_section"><a href="#toc">Table Of Contents</a></li>
<li class="doctools_section"><a href="#synopsis">Synopsis</a></li>
<li class="doctools_section"><a href="#section1">Description</a></li>
<li class="doctools_section"><a href="#section2">Overview</a>
<ul>
<li class="doctools_subsection"><a href="#subsection1">Concepts</a></li>
<li class="doctools_subsection"><a href="#subsection2">dependencies</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section3">API</a>
<ul>
<li class="doctools_subsection"><a href="#subsection3">Namespace punk::repl::codethread::class</a></li>
<li class="doctools_subsection"><a href="#subsection4">Namespace punk::repl::codethread</a></li>
<li class="doctools_subsection"><a href="#subsection5">Namespace punk::repl::codethread::lib</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#section4">Internal</a>
<ul>
<li class="doctools_subsection"><a href="#subsection6">Namespace punk::repl::codethread::system</a></li>
</ul>
</li>
<li class="doctools_section"><a href="#keywords">Keywords</a></li>
<li class="doctools_section"><a href="#copyright">Copyright</a></li>
</ul>
</div>
<div id="synopsis" class="doctools_section"><h2><a name="synopsis">Synopsis</a></h2>
<div class="doctools_synopsis">
<ul class="doctools_requirements">
<li>package require <b class="pkgname">punk::repl::codethread</b></li>
</ul>
</div>
</div>
<div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2>
<p>-</p>
</div>
<div id="section2" class="doctools_section"><h2><a name="section2">Overview</a></h2>
<p>overview of punk::repl::codethread</p>
<div id="subsection1" class="doctools_subsection"><h3><a name="subsection1">Concepts</a></h3>
<p>-</p>
</div>
<div id="subsection2" class="doctools_subsection"><h3><a name="subsection2">dependencies</a></h3>
<p>packages used by punk::repl::codethread</p>
<ul class="doctools_itemized">
<li><p><b class="package">Tcl 8.6</b></p></li>
</ul>
</div>
</div>
<div id="section3" class="doctools_section"><h2><a name="section3">API</a></h2>
<div id="subsection3" class="doctools_subsection"><h3><a name="subsection3">Namespace punk::repl::codethread::class</a></h3>
<p>class definitions</p>
<ol class="doctools_enumerated">
</ol>
</div>
<div id="subsection4" class="doctools_subsection"><h3><a name="subsection4">Namespace punk::repl::codethread</a></h3>
<p>Core API functions for punk::repl::codethread</p>
<dl class="doctools_definitions">
</dl>
</div>
<div id="subsection5" class="doctools_subsection"><h3><a name="subsection5">Namespace punk::repl::codethread::lib</a></h3>
<p>Secondary functions that are part of the API</p>
<dl class="doctools_definitions">
</dl>
</div>
</div>
<div id="section4" class="doctools_section"><h2><a name="section4">Internal</a></h2>
<div id="subsection6" class="doctools_subsection"><h3><a name="subsection6">Namespace punk::repl::codethread::system</a></h3>
<p>Internal functions that are not part of the API</p>
</div>
</div>
<div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2>
<p><a href="../../../../index.html#module">module</a></p>
</div>
<div id="copyright" class="doctools_section"><h2><a name="copyright">Copyright</a></h2>
<p>Copyright &copy; 2024</p>
</div>
</div></body></html>

48
src/embedded/www/doc/toc.html

@ -17,70 +17,90 @@
<td class="#doctools_tocright">overtype text layout - ansi aware</td> <td class="#doctools_tocright">overtype text layout - ansi aware</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='overtype_module_overtype'><a href="files/_module_overtype-1.6.3.tm.html">overtype_module_overtype</a></td>
<td class="#doctools_tocright">overtype text layout - ansi aware</td>
</tr>
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell'><a href="files/main.html">punkshell</a></td> <td class="#doctools_tocleft" ><a name='punkshell'><a href="files/main.html">punkshell</a></td>
<td class="#doctools_tocright">punkshell - Core</td> <td class="#doctools_tocright">punkshell - Core</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_project_changes'><a href="files/project_changes.html">punkshell__project_changes</a></td> <td class="#doctools_tocleft" ><a name='punkshell_project_changes'><a href="files/project_changes.html">punkshell__project_changes</a></td>
<td class="#doctools_tocright">punkshell Changes</td> <td class="#doctools_tocright">punkshell Changes</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_project_intro'><a href="files/project_intro.html">punkshell__project_intro</a></td> <td class="#doctools_tocleft" ><a name='punkshell_project_intro'><a href="files/project_intro.html">punkshell__project_intro</a></td>
<td class="#doctools_tocright">Introduction to punkshell</td> <td class="#doctools_tocright">Introduction to punkshell</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_ansi'><a href="files/punk/_module_ansi-0.1.1.tm.html">punkshell_module_punk::ansi</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_ansi'><a href="files/punk/_module_ansi-0.1.1.tm.html">punkshell_module_punk::ansi</a></td>
<td class="#doctools_tocright">Ansi string functions</td> <td class="#doctools_tocright">Ansi string functions</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_args'><a href="files/punk/_module_args-0.1.0.tm.html">punkshell_module_punk::args</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_args'><a href="files/punk/_module_args-0.1.0.tm.html">punkshell_module_punk::args</a></td>
<td class="#doctools_tocright">args parsing</td> <td class="#doctools_tocright">args parsing</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_cap'><a href="files/punk/_module_cap-0.1.0.tm.html">punkshell_module_punk::cap</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_cap'><a href="files/punk/_module_cap-0.1.0.tm.html">punkshell_module_punk::cap</a></td>
<td class="#doctools_tocright">capability provider and handler plugin system</td> <td class="#doctools_tocright">capability provider and handler plugin system</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_char'><a href="files/punk/_module_char-0.1.0.tm.html">punkshell_module_punk::char</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_char'><a href="files/punk/_module_char-0.1.0.tm.html">punkshell_module_punk::char</a></td>
<td class="#doctools_tocright">character-set and unicode utilities</td> <td class="#doctools_tocright">character-set and unicode utilities</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_encmime'><a href="files/punk/_module_encmime-0.1.0.tm.html">punkshell_module_punk::encmime</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_encmime'><a href="files/punk/_module_encmime-0.1.0.tm.html">punkshell_module_punk::encmime</a></td>
<td class="#doctools_tocright">mime encodings related subset of tcllib mime</td> <td class="#doctools_tocright">mime encodings related subset of tcllib mime</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_fileline'><a href="files/punk/_module_fileline-0.1.0.tm.html">punkshell_module_punk::fileline</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_fileline'><a href="files/punk/_module_fileline-0.1.0.tm.html">punkshell_module_punk::fileline</a></td>
<td class="#doctools_tocright">file line-handling utilities</td> <td class="#doctools_tocright">file line-handling utilities</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_flib'><a href="files/punk/_module_flib-0.1.0.tm.html">punkshell_module_punk::flib</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_flib'><a href="files/punk/_module_flib-0.1.0.tm.html">punkshell_module_punk::flib</a></td>
<td class="#doctools_tocright">flib experimental</td> <td class="#doctools_tocright">flib experimental</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_lib'><a href="files/punk/_module_lib-0.1.1.tm.html">punkshell_module_punk::lib</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_lib'><a href="files/punk/_module_lib-0.1.1.tm.html">punkshell_module_punk::lib</a></td>
<td class="#doctools_tocright">punk general utility functions</td> <td class="#doctools_tocright">punk general utility functions</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_mix_commandset_project'><a href="files/punk/mix/commandset/_module_project-0.1.0.tm.html">punkshell_module_punk::mix::commandset::project</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_mix_commandset_project'><a href="files/punk/mix/commandset/_module_project-0.1.0.tm.html">punkshell_module_punk::mix::commandset::project</a></td>
<td class="#doctools_tocright">dec commandset - project</td> <td class="#doctools_tocright">dec commandset - project</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_path'><a href="files/punk/_module_path-0.1.0.tm.html">punkshell_module_punk::path</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_path'><a href="files/punk/_module_path-0.1.0.tm.html">punkshell_module_punk::path</a></td>
<td class="#doctools_tocright">Filesystem path utilities</td> <td class="#doctools_tocright">Filesystem path utilities</td>
</tr> </tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_argparsingtest'><a href="files/_module_argparsingtest-0.1.0.tm.html">shellspy_module_argparsingtest</a></td>
<td class="#doctools_tocright">Module API</td>
</tr>
<tr class="#doctools_toceven" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_aliascore'><a href="files/punk/_module_aliascore-0.1.0.tm.html">shellspy_module_punk::aliascore</a></td>
<td class="#doctools_tocright">Module API</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_assertion'><a href="files/punk/_module_assertion-0.1.0.tm.html">shellspy_module_punk::assertion</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_assertion'><a href="files/punk/_module_assertion-0.1.0.tm.html">shellspy_module_punk::assertion</a></td>
<td class="#doctools_tocright">assertion alternative to control::assert</td> <td class="#doctools_tocright">assertion alternative to control::assert</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_basictelnet'><a href="files/punk/_module_basictelnet-0.1.0.tm.html">shellspy_module_punk::basictelnet</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_basictelnet'><a href="files/punk/_module_basictelnet-0.1.0.tm.html">shellspy_module_punk::basictelnet</a></td>
<td class="#doctools_tocright">basic telnet client - DKF/Wiki</td> <td class="#doctools_tocright">basic telnet client - DKF/Wiki</td>
</tr> </tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_island'><a href="files/punk/_module_island-0.1.0.tm.html">shellspy_module_punk::island</a></td>
<td class="#doctools_tocright">filesystem islands for safe interps</td>
</tr>
<tr class="#doctools_toceven" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_repl_codethread'><a href="files/punk/repl/_module_codethread-0.1.0.tm.html">shellspy_module_punk::repl::codethread</a></td>
<td class="#doctools_tocright">Module API</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_sshrun'><a href="files/punk/_module_sshrun-0.1.0.tm.html">shellspy_module_punk::sshrun</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_sshrun'><a href="files/punk/_module_sshrun-0.1.0.tm.html">shellspy_module_punk::sshrun</a></td>
<td class="#doctools_tocright">Tcl procedures to execute tcl scripts in remote hosts</td> <td class="#doctools_tocright">Tcl procedures to execute tcl scripts in remote hosts</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_uc'><a href="files/punk/_module_uc-0.1.0.tm.html">shellspy_module_punk::uc</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_uc'><a href="files/punk/_module_uc-0.1.0.tm.html">shellspy_module_punk::uc</a></td>
<td class="#doctools_tocright">Module API</td> <td class="#doctools_tocright">Module API</td>
</tr> </tr>

46
src/embedded/www/index.html

@ -13,7 +13,7 @@
] <hr> ] <hr>
<h3> Keyword Index </h3> <h3> Keyword Index </h3>
<hr><div class="#doctools_idxnav"> <hr><div class="#doctools_idxnav">
<a href="#cA"> A </a> &#183; <a href="#cB"> B </a> &#183; <a href="#cC"> C </a> &#183; <a href="#cD"> D </a> &#183; <a href="#cE"> E </a> &#183; <a href="#cF"> F </a> &#183; <a href="#cL"> L </a> &#183; <a href="#cM"> M </a> &#183; <a href="#cP"> P </a> &#183; <a href="#cR"> R </a> &#183; <a href="#cS"> S </a> &#183; <a href="#cT"> T </a> &#183; <a href="#cU"> U </a> <a href="#cA"> A </a> &#183; <a href="#cB"> B </a> &#183; <a href="#cC"> C </a> &#183; <a href="#cD"> D </a> &#183; <a href="#cE"> E </a> &#183; <a href="#cF"> F </a> &#183; <a href="#cI"> I </a> &#183; <a href="#cL"> L </a> &#183; <a href="#cM"> M </a> &#183; <a href="#cP"> P </a> &#183; <a href="#cR"> R </a> &#183; <a href="#cS"> S </a> &#183; <a href="#cT"> T </a> &#183; <a href="#cU"> U </a>
</div> </div>
<hr><table class="#doctools_idx" width="100%"> <hr><table class="#doctools_idx" width="100%">
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
@ -22,7 +22,7 @@
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="ansi"> ansi </a></td> <td class="#doctools_idxleft" width="35%"><a name="ansi"> ansi </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/_module_overtype-1.6.2.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a> <a href="doc/files/_module_overtype-1.6.2.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/_module_overtype-1.6.3.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a>
</td></tr> </td></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="args"> args </a></td> <td class="#doctools_idxleft" width="35%"><a name="args"> args </a></td>
@ -107,12 +107,20 @@
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="filesystem"> filesystem </a></td> <td class="#doctools_idxleft" width="35%"><a name="filesystem"> filesystem </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a> <a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a> &#183; <a href="doc/files/punk/_module_island-0.1.0.tm.html"> shellspy_module_punk::island </a>
</td></tr> </td></tr>
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
<a name="cL">Keywords: L</a> <a name="cI">Keywords: I</a>
</th></tr> </th></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="interp"> interp </a></td>
<td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_island-0.1.0.tm.html"> shellspy_module_punk::island </a>
</td></tr>
<tr class="#doctools_idxheader"><th colspan="2">
<a name="cL">Keywords: L</a>
</th></tr>
<tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="lib"> lib </a></td> <td class="#doctools_idxleft" width="35%"><a name="lib"> lib </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_lib-0.1.1.tm.html"> punkshell_module_punk::lib </a> <a href="doc/files/punk/_module_lib-0.1.1.tm.html"> punkshell_module_punk::lib </a>
@ -120,35 +128,35 @@
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
<a name="cM">Keywords: M</a> <a name="cM">Keywords: M</a>
</th></tr> </th></tr>
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="module"> module </a></td> <td class="#doctools_idxleft" width="35%"><a name="module"> module </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/_module_overtype-1.6.2.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a> &#183; <a href="doc/files/punk/_module_args-0.1.0.tm.html"> punkshell_module_punk::args </a> &#183; <a href="doc/files/punk/_module_cap-0.1.0.tm.html"> punkshell_module_punk::cap </a> &#183; <a href="doc/files/punk/_module_char-0.1.0.tm.html"> punkshell_module_punk::char </a> &#183; <a href="doc/files/punk/_module_encmime-0.1.0.tm.html"> punkshell_module_punk::encmime </a> &#183; <a href="doc/files/punk/_module_fileline-0.1.0.tm.html"> punkshell_module_punk::fileline </a> &#183; <a href="doc/files/punk/_module_flib-0.1.0.tm.html"> punkshell_module_punk::flib </a> &#183; <a href="doc/files/punk/_module_lib-0.1.1.tm.html"> punkshell_module_punk::lib </a> &#183; <a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a> &#183; <a href="doc/files/punk/_module_assertion-0.1.0.tm.html"> shellspy_module_punk::assertion </a> &#183; <a href="doc/files/punk/_module_basictelnet-0.1.0.tm.html"> shellspy_module_punk::basictelnet </a> &#183; <a href="doc/files/punk/_module_sshrun-0.1.0.tm.html"> shellspy_module_punk::sshrun </a> &#183; <a href="doc/files/punk/_module_uc-0.1.0.tm.html"> shellspy_module_punk::uc </a> <a href="doc/files/_module_overtype-1.6.2.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/_module_overtype-1.6.3.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a> &#183; <a href="doc/files/punk/_module_args-0.1.0.tm.html"> punkshell_module_punk::args </a> &#183; <a href="doc/files/punk/_module_cap-0.1.0.tm.html"> punkshell_module_punk::cap </a> &#183; <a href="doc/files/punk/_module_char-0.1.0.tm.html"> punkshell_module_punk::char </a> &#183; <a href="doc/files/punk/_module_encmime-0.1.0.tm.html"> punkshell_module_punk::encmime </a> &#183; <a href="doc/files/punk/_module_fileline-0.1.0.tm.html"> punkshell_module_punk::fileline </a> &#183; <a href="doc/files/punk/_module_flib-0.1.0.tm.html"> punkshell_module_punk::flib </a> &#183; <a href="doc/files/punk/_module_lib-0.1.1.tm.html"> punkshell_module_punk::lib </a> &#183; <a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a> &#183; <a href="doc/files/_module_argparsingtest-0.1.0.tm.html"> shellspy_module_argparsingtest </a> &#183; <a href="doc/files/punk/_module_aliascore-0.1.0.tm.html"> shellspy_module_punk::aliascore </a> &#183; <a href="doc/files/punk/_module_assertion-0.1.0.tm.html"> shellspy_module_punk::assertion </a> &#183; <a href="doc/files/punk/_module_basictelnet-0.1.0.tm.html"> shellspy_module_punk::basictelnet </a> &#183; <a href="doc/files/punk/_module_island-0.1.0.tm.html"> shellspy_module_punk::island </a> &#183; <a href="doc/files/punk/repl/_module_codethread-0.1.0.tm.html"> shellspy_module_punk::repl::codethread </a> &#183; <a href="doc/files/punk/_module_sshrun-0.1.0.tm.html"> shellspy_module_punk::sshrun </a> &#183; <a href="doc/files/punk/_module_uc-0.1.0.tm.html"> shellspy_module_punk::uc </a>
</td></tr> </td></tr>
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
<a name="cP">Keywords: P</a> <a name="cP">Keywords: P</a>
</th></tr> </th></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="parse"> parse </a></td> <td class="#doctools_idxleft" width="35%"><a name="parse"> parse </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_args-0.1.0.tm.html"> punkshell_module_punk::args </a> &#183; <a href="doc/files/punk/_module_fileline-0.1.0.tm.html"> punkshell_module_punk::fileline </a> <a href="doc/files/punk/_module_args-0.1.0.tm.html"> punkshell_module_punk::args </a> &#183; <a href="doc/files/punk/_module_fileline-0.1.0.tm.html"> punkshell_module_punk::fileline </a>
</td></tr> </td></tr>
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="path"> path </a></td> <td class="#doctools_idxleft" width="35%"><a name="path"> path </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a> <a href="doc/files/punk/_module_path-0.1.0.tm.html"> punkshell_module_punk::path </a>
</td></tr> </td></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="plugin"> plugin </a></td> <td class="#doctools_idxleft" width="35%"><a name="plugin"> plugin </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_cap-0.1.0.tm.html"> punkshell_module_punk::cap </a> <a href="doc/files/punk/_module_cap-0.1.0.tm.html"> punkshell_module_punk::cap </a>
</td></tr> </td></tr>
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="proc"> proc </a></td> <td class="#doctools_idxleft" width="35%"><a name="proc"> proc </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_args-0.1.0.tm.html"> punkshell_module_punk::args </a> <a href="doc/files/punk/_module_args-0.1.0.tm.html"> punkshell_module_punk::args </a>
</td></tr> </td></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="punk"> punk </a></td> <td class="#doctools_idxleft" width="35%"><a name="punk"> punk </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a> <a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a>
@ -156,7 +164,7 @@
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
<a name="cR">Keywords: R</a> <a name="cR">Keywords: R</a>
</th></tr> </th></tr>
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="repl"> repl </a></td> <td class="#doctools_idxleft" width="35%"><a name="repl"> repl </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a> <a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a>
@ -164,17 +172,17 @@
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
<a name="cS">Keywords: S</a> <a name="cS">Keywords: S</a>
</th></tr> </th></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="shell"> shell </a></td> <td class="#doctools_idxleft" width="35%"><a name="shell"> shell </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a> <a href="doc/files/main.html"> punkshell </a> &#183; <a href="doc/files/project_changes.html"> punkshell__project_changes </a> &#183; <a href="doc/files/project_intro.html"> punkshell__project_intro </a>
</td></tr> </td></tr>
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="ssh"> ssh </a></td> <td class="#doctools_idxleft" width="35%"><a name="ssh"> ssh </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_sshrun-0.1.0.tm.html"> shellspy_module_punk::sshrun </a> <a href="doc/files/punk/_module_sshrun-0.1.0.tm.html"> shellspy_module_punk::sshrun </a>
</td></tr> </td></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="string"> string </a></td> <td class="#doctools_idxleft" width="35%"><a name="string"> string </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a> <a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a>
@ -182,20 +190,20 @@
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
<a name="cT">Keywords: T</a> <a name="cT">Keywords: T</a>
</th></tr> </th></tr>
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="terminal"> terminal </a></td> <td class="#doctools_idxleft" width="35%"><a name="terminal"> terminal </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a> <a href="doc/files/punk/_module_ansi-0.1.1.tm.html"> punkshell_module_punk::ansi </a>
</td></tr> </td></tr>
<tr class="#doctools_idxodd" valign=top> <tr class="#doctools_idxeven" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="text"> text </a></td> <td class="#doctools_idxleft" width="35%"><a name="text"> text </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/_module_overtype-1.6.2.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/punk/_module_fileline-0.1.0.tm.html"> punkshell_module_punk::fileline </a> <a href="doc/files/_module_overtype-1.6.2.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/_module_overtype-1.6.3.tm.html"> overtype_module_overtype </a> &#183; <a href="doc/files/punk/_module_fileline-0.1.0.tm.html"> punkshell_module_punk::fileline </a>
</td></tr> </td></tr>
<tr class="#doctools_idxheader"><th colspan="2"> <tr class="#doctools_idxheader"><th colspan="2">
<a name="cU">Keywords: U</a> <a name="cU">Keywords: U</a>
</th></tr> </th></tr>
<tr class="#doctools_idxeven" valign=top> <tr class="#doctools_idxodd" valign=top>
<td class="#doctools_idxleft" width="35%"><a name="utility"> utility </a></td> <td class="#doctools_idxleft" width="35%"><a name="utility"> utility </a></td>
<td class="#doctools_idxright" width="65%"> <td class="#doctools_idxright" width="65%">
<a href="doc/files/punk/_module_lib-0.1.1.tm.html"> punkshell_module_punk::lib </a> <a href="doc/files/punk/_module_lib-0.1.1.tm.html"> punkshell_module_punk::lib </a>

48
src/embedded/www/toc.html

@ -17,70 +17,90 @@
<td class="#doctools_tocright">overtype text layout - ansi aware</td> <td class="#doctools_tocright">overtype text layout - ansi aware</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='overtype_module_overtype'><a href="doc/files/_module_overtype-1.6.3.tm.html">overtype_module_overtype</a></td>
<td class="#doctools_tocright">overtype text layout - ansi aware</td>
</tr>
<tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell'><a href="doc/files/main.html">punkshell</a></td> <td class="#doctools_tocleft" ><a name='punkshell'><a href="doc/files/main.html">punkshell</a></td>
<td class="#doctools_tocright">punkshell - Core</td> <td class="#doctools_tocright">punkshell - Core</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_project_changes'><a href="doc/files/project_changes.html">punkshell__project_changes</a></td> <td class="#doctools_tocleft" ><a name='punkshell_project_changes'><a href="doc/files/project_changes.html">punkshell__project_changes</a></td>
<td class="#doctools_tocright">punkshell Changes</td> <td class="#doctools_tocright">punkshell Changes</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_project_intro'><a href="doc/files/project_intro.html">punkshell__project_intro</a></td> <td class="#doctools_tocleft" ><a name='punkshell_project_intro'><a href="doc/files/project_intro.html">punkshell__project_intro</a></td>
<td class="#doctools_tocright">Introduction to punkshell</td> <td class="#doctools_tocright">Introduction to punkshell</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_ansi'><a href="doc/files/punk/_module_ansi-0.1.1.tm.html">punkshell_module_punk::ansi</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_ansi'><a href="doc/files/punk/_module_ansi-0.1.1.tm.html">punkshell_module_punk::ansi</a></td>
<td class="#doctools_tocright">Ansi string functions</td> <td class="#doctools_tocright">Ansi string functions</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_args'><a href="doc/files/punk/_module_args-0.1.0.tm.html">punkshell_module_punk::args</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_args'><a href="doc/files/punk/_module_args-0.1.0.tm.html">punkshell_module_punk::args</a></td>
<td class="#doctools_tocright">args parsing</td> <td class="#doctools_tocright">args parsing</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_cap'><a href="doc/files/punk/_module_cap-0.1.0.tm.html">punkshell_module_punk::cap</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_cap'><a href="doc/files/punk/_module_cap-0.1.0.tm.html">punkshell_module_punk::cap</a></td>
<td class="#doctools_tocright">capability provider and handler plugin system</td> <td class="#doctools_tocright">capability provider and handler plugin system</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_char'><a href="doc/files/punk/_module_char-0.1.0.tm.html">punkshell_module_punk::char</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_char'><a href="doc/files/punk/_module_char-0.1.0.tm.html">punkshell_module_punk::char</a></td>
<td class="#doctools_tocright">character-set and unicode utilities</td> <td class="#doctools_tocright">character-set and unicode utilities</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_encmime'><a href="doc/files/punk/_module_encmime-0.1.0.tm.html">punkshell_module_punk::encmime</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_encmime'><a href="doc/files/punk/_module_encmime-0.1.0.tm.html">punkshell_module_punk::encmime</a></td>
<td class="#doctools_tocright">mime encodings related subset of tcllib mime</td> <td class="#doctools_tocright">mime encodings related subset of tcllib mime</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_fileline'><a href="doc/files/punk/_module_fileline-0.1.0.tm.html">punkshell_module_punk::fileline</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_fileline'><a href="doc/files/punk/_module_fileline-0.1.0.tm.html">punkshell_module_punk::fileline</a></td>
<td class="#doctools_tocright">file line-handling utilities</td> <td class="#doctools_tocright">file line-handling utilities</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_flib'><a href="doc/files/punk/_module_flib-0.1.0.tm.html">punkshell_module_punk::flib</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_flib'><a href="doc/files/punk/_module_flib-0.1.0.tm.html">punkshell_module_punk::flib</a></td>
<td class="#doctools_tocright">flib experimental</td> <td class="#doctools_tocright">flib experimental</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_lib'><a href="doc/files/punk/_module_lib-0.1.1.tm.html">punkshell_module_punk::lib</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_lib'><a href="doc/files/punk/_module_lib-0.1.1.tm.html">punkshell_module_punk::lib</a></td>
<td class="#doctools_tocright">punk general utility functions</td> <td class="#doctools_tocright">punk general utility functions</td>
</tr> </tr>
<tr class="#doctools_toceven" > <tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_mix_commandset_project'><a href="doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html">punkshell_module_punk::mix::commandset::project</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_mix_commandset_project'><a href="doc/files/punk/mix/commandset/_module_project-0.1.0.tm.html">punkshell_module_punk::mix::commandset::project</a></td>
<td class="#doctools_tocright">dec commandset - project</td> <td class="#doctools_tocright">dec commandset - project</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='punkshell_module_punk_path'><a href="doc/files/punk/_module_path-0.1.0.tm.html">punkshell_module_punk::path</a></td> <td class="#doctools_tocleft" ><a name='punkshell_module_punk_path'><a href="doc/files/punk/_module_path-0.1.0.tm.html">punkshell_module_punk::path</a></td>
<td class="#doctools_tocright">Filesystem path utilities</td> <td class="#doctools_tocright">Filesystem path utilities</td>
</tr> </tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_argparsingtest'><a href="doc/files/_module_argparsingtest-0.1.0.tm.html">shellspy_module_argparsingtest</a></td>
<td class="#doctools_tocright">Module API</td>
</tr>
<tr class="#doctools_toceven" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_aliascore'><a href="doc/files/punk/_module_aliascore-0.1.0.tm.html">shellspy_module_punk::aliascore</a></td>
<td class="#doctools_tocright">Module API</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_assertion'><a href="doc/files/punk/_module_assertion-0.1.0.tm.html">shellspy_module_punk::assertion</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_assertion'><a href="doc/files/punk/_module_assertion-0.1.0.tm.html">shellspy_module_punk::assertion</a></td>
<td class="#doctools_tocright">assertion alternative to control::assert</td> <td class="#doctools_tocright">assertion alternative to control::assert</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_basictelnet'><a href="doc/files/punk/_module_basictelnet-0.1.0.tm.html">shellspy_module_punk::basictelnet</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_basictelnet'><a href="doc/files/punk/_module_basictelnet-0.1.0.tm.html">shellspy_module_punk::basictelnet</a></td>
<td class="#doctools_tocright">basic telnet client - DKF/Wiki</td> <td class="#doctools_tocright">basic telnet client - DKF/Wiki</td>
</tr> </tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_island'><a href="doc/files/punk/_module_island-0.1.0.tm.html">shellspy_module_punk::island</a></td>
<td class="#doctools_tocright">filesystem islands for safe interps</td>
</tr>
<tr class="#doctools_toceven" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_repl_codethread'><a href="doc/files/punk/repl/_module_codethread-0.1.0.tm.html">shellspy_module_punk::repl::codethread</a></td>
<td class="#doctools_tocright">Module API</td>
</tr>
<tr class="#doctools_tocodd" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_sshrun'><a href="doc/files/punk/_module_sshrun-0.1.0.tm.html">shellspy_module_punk::sshrun</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_sshrun'><a href="doc/files/punk/_module_sshrun-0.1.0.tm.html">shellspy_module_punk::sshrun</a></td>
<td class="#doctools_tocright">Tcl procedures to execute tcl scripts in remote hosts</td> <td class="#doctools_tocright">Tcl procedures to execute tcl scripts in remote hosts</td>
</tr> </tr>
<tr class="#doctools_tocodd" > <tr class="#doctools_toceven" >
<td class="#doctools_tocleft" ><a name='shellspy_module_punk_uc'><a href="doc/files/punk/_module_uc-0.1.0.tm.html">shellspy_module_punk::uc</a></td> <td class="#doctools_tocleft" ><a name='shellspy_module_punk_uc'><a href="doc/files/punk/_module_uc-0.1.0.tm.html">shellspy_module_punk::uc</a></td>
<td class="#doctools_tocright">Module API</td> <td class="#doctools_tocright">Module API</td>
</tr> </tr>

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

@ -0,0 +1,468 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'pmix make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.2.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) 2024
#
# @@ Meta Begin
# Application argparsingtest 999999.0a1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin shellspy_module_argparsingtest 0 999999.0a1.0]
#[copyright "2024"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
#[require argparsingtest]
#[keywords module]
#[description]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of argparsingtest
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by argparsingtest
#[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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval argparsingtest::class {
#*** !doctools
#[subsection {Namespace argparsingtest::class}]
#[para] class definitions
if {[info commands [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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval argparsingtest {
namespace export {[a-z]*} ;# Convention: export all lowercase
#variable xyz
#*** !doctools
#[subsection {Namespace argparsingtest}]
#[para] Core API functions for argparsingtest
#[list_begin definitions]
proc test1_switchmerge {args} {
set defaults [dict create\
-return string\
-frametype \uFFEF\
-show_edge \uFFEF\
-show_seps \uFFEF\
-x a\
-y b\
-z c\
-1 1\
-2 2\
-3 3\
]
foreach {k v} $args {
switch -- $k {
-return - -show_edge - -show_seps - -frametype - -x - -y - -z - -1 - -2 - -3 {}
default {
error "unrecognised option '$k'. Known options [dict keys $defaults]"
}
}
}
set opts [dict merge $defaults $args]
}
#if we need to loop to test arg validity anyway - then dict set as we go is slightly faster than a dict merge at the end
proc test1_switch {args} {
set opts [dict create\
-return string\
-frametype \uFFEF\
-show_edge \uFFEF\
-show_seps \uFFEF\
-x a\
-y b\
-z c\
-1 1\
-2 2\
-3 3\
]
foreach {k v} $args {
switch -- $k {
-return - -show_edge - -show_seps - -frametype - -x - -y - -z - -1 - -2 - -3 {
dict set opts $k $v
}
default {
error "unrecognised option '$k'. Known options [dict keys $opts]"
}
}
}
return $opts
}
proc test1_switch2 {args} {
set opts [dict create\
-return string\
-frametype \uFFEF\
-show_edge \uFFEF\
-show_seps \uFFEF\
-x a\
-y b\
-z c\
-1 1\
-2 2\
-3 3\
]
set switches [lmap v [dict keys $opts] {list $v -}]
set switches [concat {*}$switches]
set switches [lrange $switches 0 end-1]
foreach {k v} $args {
switch -- $k\
{*}$switches {
dict set opts $k $v
}\
default {
error "unrecognised option '$k'. Known options [dict keys $opts]"
}
}
return $opts
}
proc test1_prefix {args} {
set opts [dict create\
-return string\
-frametype \uFFEF\
-show_edge \uFFEF\
-show_seps \uFFEF\
-x a\
-y b\
-z c\
-1 1\
-2 2\
-3 3\
]
foreach {k v} $args {
dict set opts [tcl::prefix::match -message "test1_prefix option $k" {-return -frametype -show_edge -show_seps -x -y -z -1 -2 -3} $k] $v
}
return $opts
}
proc test1_prefix2 {args} {
set opts [dict create\
-return string\
-frametype \uFFEF\
-show_edge \uFFEF\
-show_seps \uFFEF\
-x a\
-y b\
-z c\
-1 1\
-2 2\
-3 3\
]
if {[llength $args]} {
set knownflags [dict keys $opts]
}
foreach {k v} $args {
dict set opts [tcl::prefix::match -message "test1_prefix2 option $k" $knownflags $k] $v
}
return $opts
}
#punk::args is slower than argp - but comparable, and argp doesn't support solo flags
proc test1_punkargs {args} {
set argd [punk::args::get_dict {
*proc -name argtest4 -description "test of punk::args::get_dict comparative performance"
*opts -anyopts 0
-return -default string -type string
-frametype -default \uFFEF -type string
-show_edge -default \uFFEF -type string
-show_seps -default \uFFEF -type string
-join -type none -multiple 1
-x -default a -type string
-y -default b -type string
-z -default c -type string
-1 -default 1 -type boolean
-2 -default 2 -type integer
-3 -default 3 -type integer
*values
} $args]
return [dict get $argd opts]
}
proc test1_punkargs_validate_without_ansi {args} {
set argd [punk::args::get_dict {
*proc -name argtest4 -description "test of punk::args::get_dict comparative performance"
*opts -anyopts 0
-return -default string -type string
-frametype -default \uFFEF -type string
-show_edge -default \uFFEF -type string
-show_seps -default \uFFEF -type string
-join -type none -multiple 1
-x -default a -type string
-y -default b -type string
-z -default c -type string
-1 -default 1 -type boolean -validate_without_ansi true
-2 -default 2 -type integer -validate_without_ansi true
-3 -default 3 -type integer -validate_without_ansi true
*values
} $args]
return [dict get $argd opts]
}
package require opt
variable optlist
tcl::OptProc test1_opt {
{-return string "return type"}
{-frametype \uFFEF "type of frame"}
{-show_edge \uFFEF "show table outer borders"}
{-show_seps \uFFEF "show separators"}
{-join "solo option"}
{-x a "x val"}
{-y b "y val"}
{-z c "z val"}
{-1 1 "1val"}
{-2 -int 2 "2val"}
{-3 -int 3 "3val"}
} {
set opts [dict create]
foreach v [info locals] {
dict set opts $v [set $v]
}
return $opts
}
package require cmdline
#cmdline::getoptions is much faster than typedGetoptions
proc test1_cmdline_untyped {args} {
set cmdlineopts_untyped {
{return.arg "string" "return val"}
{frametype.arg \uFFEF "frame type"}
{show_edge.arg \uFFEF "show table borders"}
{show_seps.arg \uFFEF "show table seps"}
{join "join the things"}
{x.arg a "arg x"}
{y.arg b "arg y"}
{z.arg c "arg z"}
{1.arg 1 "arg 1"}
{2.arg 2 "arg 2"}
{3.arg 3 "arg 3"}
}
set usage "usage etc"
return [::cmdline::getoptions args $cmdlineopts_untyped $usage]
}
proc test1_cmdline_typed {args} {
set cmdlineopts_typed {
{return.arg "string" "return val"}
{frametype.arg \uFFEF "frame type"}
{show_edge.arg \uFFEF "show table borders"}
{show_seps.arg \uFFEF "show table seps"}
{join "join the things"}
{x.arg a "arg x"}
{y.arg b "arg y"}
{z.arg c "arg z"}
{1.boolean 1 "arg 1"}
{2.integer 2 "arg 2"}
{3.integer 3 "arg 3"}
}
set usage "usage etc"
return [::cmdline::typedGetoptions args $cmdlineopts_typed $usage]
}
catch {
package require argp
argp::registerArgs test1_argp {
{ -return string "string" }
{ -frametype string \uFFEF }
{ -show_edge string \uFFEF }
{ -show_seps string \uFFEF }
{ -x string a }
{ -y string b }
{ -z string c }
{ -1 boolean 1 }
{ -2 integer 2 }
{ -3 integer 3 }
}
}
proc test1_argp {args} {
argp::parseArgs opts
return [array get opts]
}
package require tepam
tepam::procedure {test1_tepam} {
-args {
{-return -type string -default string}
{-frametype -type string -default \uFFEF}
{-show_edge -type string -default \uFFEF}
{-show_seps -type string -default \uFFEF}
{-join -type none -multiple}
{-x -type string -default a}
{-y -type string -default b}
{-z -type string -default c}
{-1 -type boolean -default 1}
{-2 -type integer -default 2}
{-3 -type integer -default 3}
}
} {
return [dict create return $return frametype $frametype show_edge $show_edge show_seps $show_seps x $x y $y z $z 1 $1 2 $2 3 $3 join $join]
}
#multiline values use first line of each record to determine amount of indent to trim
proc test_multiline {args} {
set t3 [textblock::frame t3]
set argd [punk::args::get_dict [subst {
-template1 -default {
******
* t1 *
******
}
-template2 -default { ------
******
* t2 *
******}
-template3 -default {$t3}
#substituted or literal values with newlines - no autoindent applied - caller will have to pad appropriately
-template3b -default {
$t3
-----------------
$t3
abc\ndef
}
-template4 -default "******
* t4 *
******"
-template5 -default "
"
-flag -default 0 -type boolean
}] $args]
return $argd
}
#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 argparsingtest ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval argparsingtest::lib {
namespace export {[a-z]*} ;# Convention: export all lowercase
namespace path [namespace parent]
#*** !doctools
#[subsection {Namespace argparsingtest::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 argparsingtest::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval argparsingtest::system {
#*** !doctools
#[subsection {Namespace argparsingtest::system}]
#[para] Internal functions that are not part of the API
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide argparsingtest [namespace eval argparsingtest {
variable pkg argparsingtest
variable version
set version 999999.0a1.0
}]
return
#*** !doctools
#[manpage_end]

3
src/modules/argparsingtest-buildversion.txt

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

42
src/modules/flagfilter-0.3.tm

@ -1881,17 +1881,18 @@ namespace eval flagfilter {
set cf_defaults [dict create] set cf_defaults [dict create\
dict set cf_defaults -caller $caller -caller $caller\
dict set cf_defaults -return [list arglistremaining] -return [list arglistremaining]\
dict set cf_defaults -match [list] -match [list]\
dict set cf_defaults -commandprocessors [list] -commandprocessors [list]\
dict set cf_defaults -soloflags [list] -soloflags [list]\
dict set cf_defaults -extras [list] -extras [list]\
dict set cf_defaults -defaults [list] -defaults [list]\
dict set cf_defaults -required [list] -required [list]\
dict set cf_defaults -values \uFFFF -values \uFFFF\
dict set cf_defaults -debugargs 0 -debugargs 0\
]
dict set cf_defaults -debugargsonerror 1 ;#error level to use when dispatch error occurs.. will not set lower than -debugargs dict set cf_defaults -debugargsonerror 1 ;#error level to use when dispatch error occurs.. will not set lower than -debugargs
@ -1899,18 +1900,17 @@ namespace eval flagfilter {
if {([llength $args] % 2) != 0} { if {([llength $args] % 2) != 0} {
do_error "check_flags error when called from '$caller' :check_flags must be called with even number of arguments of form: -flag value Valid flags are: '[dict keys $cf_defaults]' \n got: $args" do_error "check_flags error when called from '$caller' :check_flags must be called with even number of arguments of form: -flag value Valid flags are: '[dict keys $cf_defaults]' \n got: $args"
} }
set cf_invalid_flags [list] set cf_args $cf_defaults
foreach k [dict keys $args] { foreach {k v} $args {
if {$k ni [dict keys $cf_defaults]} { switch -- $k {
lappend cf_invalid_flags $k -caller - -return - -match - -commandprocessors - -soloflags - -extras - -defaults - -required - -values - -debugargs - -debugargsonerror {
dict set cf_args $k $v
}
default {
do_error "check_flags error when called from ${caller}: Unknown option '$k': must be one of '[dict keys $cf_defaults]' \nIf calling check_flags directly, put args being checked in -values {...}"
} }
} }
if {[llength $cf_invalid_flags]} {
do_error "check_flags error when called from ${caller}: Unknown or incompatible option(s)'$cf_invalid_flags': must be one of '[dict keys $cf_defaults]' \nIf calling check_flags directly, put args being checked in -values e.g -values [list {*}$cf_invalid_flags]"
} }
set cf_args [dict merge $cf_defaults $args]
unset args unset args
#################################################### ####################################################
#now look at -values etc that check_flags is checking #now look at -values etc that check_flags is checking
@ -2430,7 +2430,7 @@ namespace eval flagfilter {
do_debug 1 $debugc "returnkeys '[dict keys $returnval]'" do_debug 1 $debugc "returnkeys '[dict keys $returnval]'"
} }
do_debug 1 $debugc "[string repeat = 40]" do_debug 1 $debugc "[string repeat = 40]"
foreach {k v} $combined { dict for {k v} $combined {
set dlev [dict get $debugdict $k] set dlev [dict get $debugdict $k]
switch -- $k { switch -- $k {
dispatch { dispatch {

1912
src/modules/natsort-0.1.1.6.tm

File diff suppressed because it is too large Load Diff

519
src/modules/punk-0.1.tm

@ -72,10 +72,14 @@ set punk_testd [dict create \
] ]
#impolitely cooperative withe punk repl - todo - tone it down. #impolitely cooperative withe punk repl - todo - tone it down.
namespace eval ::repl { #namespace eval ::punk::repl::codethread {
variable running 0 # variable running 0
} #}
package require punk::lib package require punk::lib
package require punk::aliascore ;#mostly punk::lib aliases
punk::aliascore::init
package require punk::repl::codethread
package require punk::config package require punk::config
package require punk::ansi package require punk::ansi
#package require textblock #package require textblock
@ -156,6 +160,35 @@ namespace eval punk {
#variable re_headvar1 {([a-zA-Z:@.(),]+?)(?![^(]*\))(,.*)*$} #variable re_headvar1 {([a-zA-Z:@.(),]+?)(?![^(]*\))(,.*)*$}
proc get_repl_runid {} {
if {[tsv::exists repl runid]} {
return [tsv::get repl runid]
} else {
return 0
}
}
#ordinary emission of chunklist when no repl
proc emit_chunklist {chunklist} {
set result ""
foreach record $chunklist {
lassign $record type data
switch -- $type {
stdout {
puts stdout "$data"
}
stderr {
puts stderr $data
}
result {}
default {
puts stdout "$type $data"
}
}
}
return $result
}
#----------------------------------------------------------------------------------- #-----------------------------------------------------------------------------------
#strlen is important for testing issues with string representationa and shimmering. #strlen is important for testing issues with string representationa and shimmering.
#This specific implementation with append (as at 2023-09) is designed to ensure the original str representation isn't changed #This specific implementation with append (as at 2023-09) is designed to ensure the original str representation isn't changed
@ -219,6 +252,12 @@ namespace eval punk {
} }
return $stack return $stack
} }
#review - there are various type of uuid - we should use something consistent across platforms
#twapi is used on windows because it's about 5 times faster - but is this more important than consistency?
#twapi is much slower to load in the first place (e.g 75ms vs 6ms if package names already loaded) - so for oneshots tcllib uuid is better anyway
#(counterpoint: in the case of punk - we currently need twapi anyway on windows)
#does tcllib's uuid use the same mechanisms on different platforms anyway?
proc ::punk::uuid {} { proc ::punk::uuid {} {
set has_twapi 0 set has_twapi 0
if 0 { if 0 {
@ -239,7 +278,7 @@ namespace eval punk {
} }
if {!$has_twapi} { if {!$has_twapi} {
if {[catch {package require uuid} errM]} { if {[catch {package require uuid} errM]} {
error "Unable to load a package for uuid on this platform. Try tcllib's uuid (any platform) - twapi for windows" error "Unable to load a package for uuid on this platform. Try installing tcllib's uuid (any platform) - or twapi for windows"
} }
return [uuid::uuid generate] return [uuid::uuid generate]
} else { } else {
@ -357,56 +396,6 @@ namespace eval punk {
dict set output len [dict get $inf len] dict set output len [dict get $inf len]
return $output return $output
} }
namespace eval ensemble {
#wiki.tcl-lang.org/page/ensemble+extend
# extend an ensemble-like routine with the routines in some namespace
proc extend {routine extension} {
if {![string match ::* $routine]} {
set resolved [uplevel 1 [list ::namespace which $routine]]
if {$resolved eq {}} {
error [list {no such routine} $routine]
}
set routine $resolved
}
set routinens [namespace qualifiers $routine]
if {$routinens eq {::}} {
set routinens {}
}
set routinetail [namespace tail $routine]
if {![string match ::* $extension]} {
set extension [uplevel 1 [
list [namespace which namespace] current]]::$extension
}
if {![namespace exists $extension]} {
error [list {no such namespace} $extension]
}
set extension [namespace eval $extension [
list [namespace which namespace] current]]
namespace eval $extension [
list [namespace which namespace] export *]
while 1 {
set renamed ${routinens}::${routinetail}_[info cmdcount]
if {[namespace which $renamed] eq {}} break
}
rename $routine $renamed
namespace eval $extension [
list namespace ensemble create -command $routine -unknown [
list apply {{renamed ensemble routine args} {
list $renamed $routine
}} $renamed
]
]
return $routine
}
}
#review - extending core commands could be a bit intrusive...although it can make sense in a pipeline. #review - extending core commands could be a bit intrusive...although it can make sense in a pipeline.
#e.g contrived pipeline example to only allow setting existing keys #e.g contrived pipeline example to only allow setting existing keys
@ -427,7 +416,7 @@ namespace eval punk {
} }
#punk::ensemble::extend dict ::punk::dictextension #punk::lib::ensemble::extend dict ::punk::dictextension
@ -4218,6 +4207,306 @@ namespace eval punk {
return [expr {$e - $s + 1}] return [expr {$e - $s + 1}]
} }
# unknown --
# This procedure is called when a Tcl command is invoked that doesn't
# exist in the interpreter. It takes the following steps to make the
# command available:
#
# 1. See if the autoload facility can locate the command in a
# Tcl script file. If so, load it and execute it.
# 2. If the command was invoked interactively at top-level:
# (a) see if the command exists as an executable UNIX program.
# If so, "exec" the command.
# (b) see if the command requests csh-like history substitution
# in one of the common forms !!, !<number>, or ^old^new. If
# so, emulate csh's history substitution.
# (c) see if the command is a unique abbreviation for another
# command. If so, invoke the command.
#
# Arguments:
# args - A list whose elements are the words of the original
# command, including the command name.
#review - we shouldn't really be doing this
#We need to work out if we can live with the real default unknown and just inject some special cases at the beginning before falling-back to the normal one
proc ::unknown args {
#puts stderr "unk>$args"
variable ::tcl::UnknownPending
global auto_noexec auto_noload env tcl_interactive errorInfo errorCode
if {[info exists errorInfo]} {
set savedErrorInfo $errorInfo
}
if {[info exists errorCode]} {
set savedErrorCode $errorCode
}
set name [lindex $args 0]
if {![info exists auto_noload]} {
#
# Make sure we're not trying to load the same proc twice.
#
if {[info exists UnknownPending($name)]} {
return -code error "self-referential recursion\
in \"unknown\" for command \"$name\""
}
set UnknownPending($name) pending
set ret [catch {
auto_load $name [uplevel 1 {::namespace current}]
} msg opts]
unset UnknownPending($name)
if {$ret != 0} {
dict append opts -errorinfo "\n (autoloading \"$name\")"
return -options $opts $msg
}
if {![array size UnknownPending]} {
unset UnknownPending
}
if {$msg} {
if {[info exists savedErrorCode]} {
set ::errorCode $savedErrorCode
} else {
unset -nocomplain ::errorCode
}
if {[info exists savedErrorInfo]} {
set errorInfo $savedErrorInfo
} else {
unset -nocomplain errorInfo
}
set code [catch {uplevel 1 $args} msg opts]
if {$code == 1} {
#
# Compute stack trace contribution from the [uplevel].
# Note the dependence on how Tcl_AddErrorInfo, etc.
# construct the stack trace.
#
set errInfo [dict get $opts -errorinfo]
set errCode [dict get $opts -errorcode]
set cinfo $args
if {[string length [encoding convertto utf-8 $cinfo]] > 150} {
set cinfo [string range $cinfo 0 150]
while {[string length [encoding convertto utf-8 $cinfo]] > 150} {
set cinfo [string range $cinfo 0 end-1]
}
append cinfo ...
}
set tail "\n (\"uplevel\" body line 1)\n invoked\
from within\n\"uplevel 1 \$args\""
set expect "$msg\n while executing\n\"$cinfo\"$tail"
if {$errInfo eq $expect} {
#
# The stack has only the eval from the expanded command
# Do not generate any stack trace here.
#
dict unset opts -errorinfo
dict incr opts -level
return -options $opts $msg
}
#
# Stack trace is nested, trim off just the contribution
# from the extra "eval" of $args due to the "catch" above.
#
set last [string last $tail $errInfo]
if {$last + [string length $tail] != [string length $errInfo]} {
# Very likely cannot happen
return -options $opts $msg
}
set errInfo [string range $errInfo 0 $last-1]
set tail "\"$cinfo\""
set last [string last $tail $errInfo]
if {$last < 0 || $last + [string length $tail] != [string length $errInfo]} {
return -code error -errorcode $errCode \
-errorinfo $errInfo $msg
}
set errInfo [string range $errInfo 0 $last-1]
set tail "\n invoked from within\n"
set last [string last $tail $errInfo]
if {$last + [string length $tail] == [string length $errInfo]} {
return -code error -errorcode $errCode \
-errorinfo [string range $errInfo 0 $last-1] $msg
}
set tail "\n while executing\n"
set last [string last $tail $errInfo]
if {$last + [string length $tail] == [string length $errInfo]} {
return -code error -errorcode $errCode \
-errorinfo [string range $errInfo 0 $last-1] $msg
}
return -options $opts $msg
} else {
dict incr opts -level
return -options $opts $msg
}
}
}
#set isrepl [expr {[file tail [file rootname [info script]]] eq "repl"}]
set isrepl [punk::repl::codethread::is_running] ;#may not be reading though
if {$isrepl} {
#set ::tcl_interactive 1
}
if {$isrepl || (([info level] == 1) && (([info script] eq "" ) )
&& ([info exists tcl_interactive] && $tcl_interactive))} {
if {![info exists auto_noexec]} {
set new [auto_execok $name]
if {$new ne ""} {
set redir ""
if {[namespace which -command console] eq ""} {
set redir ">&@stdout <@stdin"
}
#windows experiment todo - use twapi and named pipes
#twapi::namedpipe_server {\\.\pipe\something}
#Then override tcl 'exec' and replace all stdout/stderr/stdin with our fake ones
#These can be stacked with shellfilter and operate as OS handles - which we can't do with fifo2 etc
#
if {[string first " " $new] > 0} {
set c1 $name
} else {
set c1 $new
}
# -- --- --- --- ---
set idlist_stdout [list]
set idlist_stderr [list]
#set shellrun::runout ""
#when using exec with >&@stdout (to ensure process is connected to console) - the output unfortunately doesn't go via the shellfilter stacks
#lappend idlist_stderr [shellfilter::stack::add stderr ansiwrap -settings {-colour {red bold}}]
#lappend idlist_stdout [shellfilter::stack::add stdout tee_to_var -action float -settings {-varname ::shellrun::runout}]
if {![dict get $::punk::config::running exec_unknown]} {
#This runs external executables in a context in which they are not attached to a terminal
#VIM for example won't run, and various programs can't detect terminal dimensions etc and/or will default to ansi-free output
#ctrl-c propagation also needs to be considered
set teehandle punksh
uplevel 1 [list ::catch \
[list ::shellfilter::run [concat [list $new] [lrange $args 1 end]] -teehandle $teehandle -inbuffering line -outbuffering none ] \
::tcl::UnknownResult ::tcl::UnknownOptions]
if {[string trim $::tcl::UnknownResult] ne "exitcode 0"} {
dict set ::tcl::UnknownOptions -code error
set ::tcl::UnknownResult "Non-zero exit code from command '$args' $::tcl::UnknownResult"
} else {
#no point returning "exitcode 0" if that's the only non-error return.
#It is misleading. Better to return empty string.
set ::tcl::UnknownResult ""
}
} else {
set repl_runid [punk::get_repl_runid]
#set ::punk::last_run_display [list]
set redir ">&@stdout <@stdin"
uplevel 1 [list ::catch [concat exec $redir $new [lrange $args 1 end]] ::tcl::UnknownResult ::tcl::UnknownOptions]
#we can't detect stdout/stderr output from the exec
#for now emit an extra \n on stderr
#todo - there is probably no way around this but to somehow exec in the context of a completely separate console
#This is probably a tricky problem - especially to do cross-platform
#
# - use [dict get $::tcl::UnknownOptions -code] (0|1) exit
if {[dict get $::tcl::UnknownOptions -code] == 0} {
set c green
set m "ok"
} else {
set c yellow
set m "errorCode $::errorCode"
}
set chunklist [list]
lappend chunklist [list "info" "[a $c]$m[a] " ]
if {$repl_runid != 0} {
tsv::lappend repl runchunks-$repl_runid {*}$chunklist
}
}
foreach id $idlist_stdout {
shellfilter::stack::remove stdout $id
}
foreach id $idlist_stderr {
shellfilter::stack::remove stderr $id
}
# -- --- --- --- ---
#uplevel 1 [list ::catch \
# [concat exec $redir $new [lrange $args 1 end]] \
# ::tcl::UnknownResult ::tcl::UnknownOptions]
#puts "===exec with redir:$redir $::tcl::UnknownResult =="
dict incr ::tcl::UnknownOptions -level
return -options $::tcl::UnknownOptions $::tcl::UnknownResult
}
}
if {$name eq "!!"} {
set newcmd [history event]
} elseif {[regexp {^!(.+)$} $name -> event]} {
set newcmd [history event $event]
} elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $name -> old new]} {
set newcmd [history event -1]
catch {regsub -all -- $old $newcmd $new newcmd}
}
if {[info exists newcmd]} {
tclLog $newcmd
history change $newcmd 0
uplevel 1 [list ::catch $newcmd \
::tcl::UnknownResult ::tcl::UnknownOptions]
dict incr ::tcl::UnknownOptions -level
return -options $::tcl::UnknownOptions $::tcl::UnknownResult
}
set ret [catch {set candidates [info commands $name*]} msg]
if {$name eq "::"} {
set name ""
}
if {$ret != 0} {
dict append opts -errorinfo \
"\n (expanding command prefix \"$name\" in unknown)"
return -options $opts $msg
}
# Filter out bogus matches when $name contained
# a glob-special char [Bug 946952]
if {$name eq ""} {
# Handle empty $name separately due to strangeness
# in [string first] (See RFE 1243354)
set cmds $candidates
} else {
set cmds [list]
foreach x $candidates {
if {[string first $name $x] == 0} {
lappend cmds $x
}
}
}
#punk - disable prefix match search
set default_cmd_search 0
if {$default_cmd_search} {
if {[llength $cmds] == 1} {
uplevel 1 [list ::catch [lreplace $args 0 0 [lindex $cmds 0]] \
::tcl::UnknownResult ::tcl::UnknownOptions]
dict incr ::tcl::UnknownOptions -level
return -options $::tcl::UnknownOptions $::tcl::UnknownResult
}
if {[llength $cmds]} {
return -code error "ambiguous command name \"$name\": [lsort $cmds]"
}
} else {
#punk hacked version - report matches but don't run
if {[llength $cmds]} {
return -code error "unknown command name \"$name\": possible match(es) [lsort $cmds]"
}
}
}
return -code error -errorcode [list TCL LOOKUP COMMAND $name] \
"invalid command name \"$name\""
}
proc know {cond body} { proc know {cond body} {
set existing [info body ::unknown] set existing [info body ::unknown]
#assuming we can't test on cond being present in existing unknown script - because it may be fairly simple and prone to false positives (?) #assuming we can't test on cond being present in existing unknown script - because it may be fairly simple and prone to false positives (?)
@ -4251,6 +4540,7 @@ namespace eval punk {
return "($scr)" return "($scr)"
} }
} }
proc configure_unknown {} { proc configure_unknown {} {
#----------------------------- #-----------------------------
#these are critical e.g core behaviour or important for repl displaying output correctly #these are critical e.g core behaviour or important for repl displaying output correctly
@ -4265,8 +4555,9 @@ namespace eval punk {
#can't use know - because we don't want to return before original unknown body is called. #can't use know - because we don't want to return before original unknown body is called.
proc ::unknown {args} [string map [list] { proc ::unknown {args} [string map [list] {
package require base64 package require base64
set ::punk::last_run_display [list] #set ::punk::last_run_display [list]
set ::repl::last_unknown [lindex $args 0] ;#jn #set ::repl::last_unknown [lindex $args 0] ;#jn
tsv::set repl last_unknown [lindex $args 0] ;#REVIEW
}][info body ::unknown] }][info body ::unknown]
@ -4286,17 +4577,8 @@ namespace eval punk {
#know {[expr $args] || 1} {expr $args} #know {[expr $args] || 1} {expr $args}
know {[expr $args] || 1} {tailcall expr $args} know {[expr $args] || 1} {tailcall expr $args}
#it is significantly faster to call a proc like this than to inline it in the unknown proc #it is significantly faster to call a proc such as punk::lib::range like this than to inline it in the unknown proc
proc ::punk::range {from to args} { know {[regexp {^([0-9]+)\.\.([0-9]+)$} [lindex $args 0 0] -> from to]} {punk::lib:range $from $to}
if {[info commands lseq] ne ""} {
#tcl 8.7+ lseq significantly faster for larger ranges
return [lseq $from $to]
}
set count [expr {($to -$from) + 1}]
incr from -1
return [lmap v [lrepeat $count 0] {incr from}]
}
know {[regexp {^([0-9]+)\.\.([0-9]+)$} [lindex $args 0 0] -> from to]} {punk::range $from $to}
#NOTE: #NOTE:
@ -5192,7 +5474,7 @@ namespace eval punk {
} }
#------------------------------------------------------------------- #-------------------------------------------------------------------
namespace export help aliases alias dirfiles dirfiles_dict exitcode % pipedata pipecase pipeline pipematch pipeswitch pipeswitchc pipecase linelist linesort inspect list_as_lines is_list_all_in_list is_list_all_ni_list val treemore namespace export help aliases alias dirfiles dirfiles_dict exitcode % pipedata pipecase pipeline pipematch pipeswitch pipeswitchc pipecase linelist linesort inspect list_as_lines val treemore
#namespace ensemble create #namespace ensemble create
@ -6040,7 +6322,8 @@ namespace eval punk {
#JMN #JMN
set is_win [expr {"windows" eq $::tcl_platform(platform)}] set is_win [expr {"windows" eq $::tcl_platform(platform)}]
set ::punk::last_run_display [list] set repl_runid [get_repl_runid]
#set ::punk::last_run_display [list]
if {([llength $args]) && ([lindex $args 0] eq "")} { if {([llength $args]) && ([lindex $args 0] eq "")} {
set args [lrange $args 1 end] set args [lrange $args 1 end]
@ -6065,18 +6348,22 @@ namespace eval punk {
set filebytes [tcl::mathop::+ {*}$filesizes] set filebytes [tcl::mathop::+ {*}$filesizes]
lappend result filebytes [format_number $filebytes] lappend result filebytes [format_number $filebytes]
} }
if {$::repl::running} { if {[punk::repl::codethread::is_running]} {
if {[llength [info commands ::punk::console::titleset]]} { if {[llength [info commands ::punk::console::titleset]]} {
::punk::console::titleset [lrange $result 1 end] ::punk::console::titleset [lrange $result 1 end]
} }
}
set out [punk::dirfiles_dict_as_lines -stripbase 1 $matchinfo] set out [punk::dirfiles_dict_as_lines -stripbase 1 $matchinfo]
#puts stdout $out
#puts stderr [a+ white]$out[a]
set chunklist [list] set chunklist [list]
lappend chunklist [list stdout "[a+ brightwhite]$out[a]\n"] lappend chunklist [list stdout "[a+ brightwhite]$out[a]\n"]
lappend chunklist [list result $result] lappend chunklist [list result $result]
set ::punk::last_run_display $chunklist if {$repl_runid != 0} {
if {![tsv::llength repl runchunks-$repl_runid]} {
#set ::punk::last_run_display $chunklist
tsv::lappend repl runchunks-$repl_runid {*}$chunklist
}
} else {
punk::emit_chunklist $chunklist
} }
#puts stdout "-->[ansistring VIEW $result]" #puts stdout "-->[ansistring VIEW $result]"
return $result return $result
@ -6105,9 +6392,7 @@ namespace eval punk {
set searchspec [lindex $args 0] set searchspec [lindex $args 0]
set result "" set result ""
if {$::repl::running} {
set chunklist [list] set chunklist [list]
}
#Only merge results if location matches previous (caller can deliberately intersperse bogus globs to force split if desired) #Only merge results if location matches previous (caller can deliberately intersperse bogus globs to force split if desired)
#TODO - remove duplicate file or dir items for overlapping patterns in same location!!! (at least for count, filebyte totals if not for display) #TODO - remove duplicate file or dir items for overlapping patterns in same location!!! (at least for count, filebyte totals if not for display)
@ -6183,12 +6468,8 @@ namespace eval punk {
dict incr this_result filebytes 0 ;#ensure key exists! dict incr this_result filebytes 0 ;#ensure key exists!
} }
dict lappend this_result pattern [dict get $matchinfo opts -glob] dict lappend this_result pattern [dict get $matchinfo opts -glob]
if {$::repl::running} {
set out [punk::dirfiles_dict_as_lines -stripbase 1 $matchinfo] set out [punk::dirfiles_dict_as_lines -stripbase 1 $matchinfo]
lappend chunklist [list stdout "[a+ brightwhite]$out[a]\n"] lappend chunklist [list stdout "[a+ brightwhite]$out[a]\n"]
}
set last_location $location set last_location $location
} }
@ -6203,15 +6484,21 @@ namespace eval punk {
} }
if {[punk::repl::codethread::is_running]} {
if {$::repl::running} { if {![tsv::llength repl runchunks-$repl_runid]} {
set ::punk::last_run_display $chunklist #set ::punk::last_run_display $chunklist
tsv::lappend repl runchunks-$repl_runid {*}$chunklist
}
}
if {$repl_runid == 0} {
punk::emit_chunklist $chunklist
} }
return $result return $result
} }
} }
proc dd/ {args} { proc dd/ {args} {
set ::punk::last_run_display [list] #set ::punk::last_run_display [list]
set repl_runid [get_repl_runid]
if {![llength $args]} { if {![llength $args]} {
set path .. set path ..
} else { } else {
@ -6232,17 +6519,24 @@ namespace eval punk {
lappend result filebytes [format_number $filebytes] lappend result filebytes [format_number $filebytes]
} }
if {$::repl::running} {
set out [punk::dirfiles_dict_as_lines -stripbase 1 $matchinfo] set out [punk::dirfiles_dict_as_lines -stripbase 1 $matchinfo]
#return $out\n[pwd] #return $out\n[pwd]
set chunklist [list] set chunklist [list]
lappend chunklist [list stdout "[a+ brightwhite]$out[a]\n"] lappend chunklist [list stdout "[a+ brightwhite]$out[a]\n"]
lappend chunklist [list result $result] lappend chunklist [list result $result]
set ::punk::last_run_display $chunklist
if {[punk::repl::codethread::is_running]} {
if {![tsv::llength repl runchunks-$repl_runid]} {
#set ::punk::last_run_display $chunklist
tsv::lappend repl runchunks-$repl_runid {*}$chunklist
}
if {[llength [info commands ::punk::console::titleset]]} { if {[llength [info commands ::punk::console::titleset]]} {
::punk::console::titleset [lrange $result 1 end] ;#strip location key ::punk::console::titleset [lrange $result 1 end] ;#strip location key
} }
} }
if {$repl_runid == 0} {
punk::emit_chunklist $chunklist
}
return $result return $result
} }
@ -6537,6 +6831,10 @@ namespace eval punk {
return $result return $result
} }
} }
#linelistraw is essentially split $text \n so is only really of use for pipelines, where the argument order is more convenient
#like linelist - but keeps leading and trailing empty lines #like linelist - but keeps leading and trailing empty lines
#single \n produces {} {} #single \n produces {} {}
#the result can be joined to reform the arg if a single arg supplied #the result can be joined to reform the arg if a single arg supplied
@ -6931,8 +7229,8 @@ namespace eval punk {
#todo - load from source code annotation? #todo - load from source code annotation?
set cmdinfo [list] set cmdinfo [list]
lappend cmdinfo [list help "This help. To see available subitems type: help topics"] lappend cmdinfo [list help "This help. To see available subitems type: help topics"]
lappend cmdinfo [list deck "(ensemble command to make new projects/modules and to generate docs)"] lappend cmdinfo [list dev "(ensemble command to make new projects/modules and to generate docs)"]
lappend cmdinfo [list a? "view ANSI colours"] lappend cmdinfo [list a? "view ANSI colours\n e.g a? web"]
lappend cmdinfo [list ./ "view/change directory"] lappend cmdinfo [list ./ "view/change directory"]
lappend cmdinfo [list ../ "go up one directory"] lappend cmdinfo [list ../ "go up one directory"]
lappend cmdinfo [list ./new "make new directory and switch to it"] lappend cmdinfo [list ./new "make new directory and switch to it"]
@ -6973,8 +7271,8 @@ namespace eval punk {
if {$topic in [list tcl]} { if {$topic in [list tcl]} {
if {[punk::repl::has_script_var_bug]} { if {[punk::lib::system::has_script_var_bug]} {
append warningblock \n "minor warning: punk::repl::has_script_var_bug returned true! (string rep for list variable in script generated when script changed)" append warningblock \n "minor warning: punk::lib::system::has_script_var_bug returned true! (string rep for list variable in script generated when script changed)"
} }
} }
@ -7104,7 +7402,7 @@ namespace eval punk {
tailcall ::punk::console::mode $raw_or_line tailcall ::punk::console::mode $raw_or_line
} }
#this hides cmds mode command - probably no big deal - anyone who needs it will know how to exec it. #this hides windows cmd's mode command - probably no big deal - anyone who needs it will know how to exec it.
interp alias {} mode {} punk::mode interp alias {} mode {} punk::mode
@ -7149,6 +7447,7 @@ namespace eval punk {
} }
proc alias {{aliasorglob ""} args} { proc alias {{aliasorglob ""} args} {
set nsthis [uplevel 1 {::namespace current}] ;#must use :: - we can find ourselves in a namespace with a different 'namespace' command
if {[llength $args]} { if {[llength $args]} {
if {$aliasorglob in [interp aliases ""]} { if {$aliasorglob in [interp aliases ""]} {
set existing [interp alias "" $aliasorglob] set existing [interp alias "" $aliasorglob]
@ -7224,13 +7523,6 @@ namespace eval punk {
interp alias {} colour {} punk::console::colour
interp alias {} ansi {} punk::console::ansi
interp alias {} color {} punk::console::colour
interp alias {} a+ {} punk::console::code_a+
interp alias {} a= {} punk::console::code_a
interp alias {} a {} punk::console::code_a
interp alias {} a? {} punk::console::code_a?
#interp alias {} c {} clear ;#external executable 'clear' may not always be available #interp alias {} c {} clear ;#external executable 'clear' may not always be available
#todo - review #todo - review
@ -7283,20 +7575,14 @@ namespace eval punk {
#---------------------------------------------- #----------------------------------------------
interp alias {} linelistraw {} punk::linelistraw interp alias {} linelistraw {} punk::linelistraw
interp alias {} linelist {} punk::lib::linelist ;#critical for = assignment features
interp alias {} linesort {} punk::lib::linesort
# 'path' collides with kettle path in kettle::doc function - todo - patch kettle? # 'path' collides with kettle path in kettle::doc function - todo - patch kettle?
interp alias {} PATH {} punk::path interp alias {} PATH {} punk::path
interp alias {} path_list {} punk::path_list interp alias {} path_list {} punk::path_list
#interp alias {} list_as_lines {} punk::list_as_lines
interp alias {} list_as_lines {} punk::lib::list_as_lines
interp alias {} lines_as_list {} punk::lib::lines_as_list
interp alias {} ansistrip {} punk::ansi::stripansi ;#review
interp alias {} list_filter_cond {} punk::list_filter_cond interp alias {} list_filter_cond {} punk::list_filter_cond
interp alias {} is_list_all_in_list {} punk::is_list_all_in_list
interp alias {} is_list_all_ni_list {} punk::is_list_all_ni_list
interp alias {} inspect {} punk::inspect interp alias {} inspect {} punk::inspect
interp alias {} ooinspect {} punk::ooinspect interp alias {} ooinspect {} punk::ooinspect
interp alias {} pdict {} punk::pdict interp alias {} pdict {} punk::pdict
@ -7318,6 +7604,9 @@ namespace eval punk {
interp alias {} listset {} punk::listset ;#identical to pipeset interp alias {} listset {} punk::listset ;#identical to pipeset
#non-core aliases
interp alias {} is_list_all_in_list {} punk::lib::is_list_all_in_list
interp alias {} is_list_all_ni_list {} punk::libis_list_all_ni_list
@ -7369,6 +7658,10 @@ namespace eval punk {
set has_powershell 0 set has_powershell 0
} }
if {$has_powershell} { if {$has_powershell} {
#see also powershell runspaces etc:
# powershell runspaces e.g $rs=[RunspaceFactory]::CreateRunspace()
# $ps = [Powershell]::Create()
interp alias {} ps {} exec >@stdout pwsh -nolo -nop -c interp alias {} ps {} exec >@stdout pwsh -nolo -nop -c
interp alias {} psx {} runx -n pwsh -nop -nolo -c interp alias {} psx {} runx -n pwsh -nop -nolo -c
interp alias {} psr {} run -n pwsh -nop -nolo -c interp alias {} psr {} run -n pwsh -nop -nolo -c
@ -7396,13 +7689,13 @@ namespace eval punk {
proc repl {startstop} { proc repl {startstop} {
switch -- $startstop { switch -- $startstop {
stop { stop {
if {$::repl::running} { if {[punk::repl::codethread::is_running]} {
puts stdout "Attempting repl stop. Try ctrl-c or exit command to leave interpreter" puts stdout "Attempting repl stop. Try ctrl-c or exit command to leave interpreter"
set ::repl::done 1 set ::repl::done 1
} }
} }
start { start {
if {!$::repl::running} { if {[punk::repl::codethread::is_running]} {
repl::start stdin repl::start stdin
} }
} }
@ -7417,10 +7710,12 @@ package require punk::mod
#punk::mod::cli set_alias pmod #punk::mod::cli set_alias pmod
punk::mod::cli set_alias app punk::mod::cli set_alias app
#todo - change to punk::deck #todo - change to punk::dev
package require punk::mix package require punk::mix
punk::mix::cli set_alias pmix punk::mix::cli set_alias dev
punk::mix::cli set_alias deck punk::mix::cli set_alias deck ;#deprecate!
#todo - add punk::deck for managing cli modules and commandsets
package require punkcheck::cli package require punkcheck::cli
punkcheck::cli set_alias pcheck punkcheck::cli set_alias pcheck

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

@ -0,0 +1,221 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'pmix make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.2.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) 2024
#
# @@ Meta Begin
# Application punk::aliascore 999999.0a1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin shellspy_module_punk::aliascore 0 999999.0a1.0]
#[copyright "2024"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
#[require punk::aliascore]
#[keywords module]
#[description]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of punk::aliascore
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by punk::aliascore
#[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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::aliascore::class {
#*** !doctools
#[subsection {Namespace punk::aliascore::class}]
#[para] class definitions
if {[info commands [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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::aliascore {
namespace export {[a-z]*} ;# Convention: export all lowercase
variable aliases
set aliases [dict create\
list_as_lines punk::lib::list_as_lines\
lines_as_list punk::lib::lines_as_list\
linelist punk::lib::linelist\
linesort punk::lib::linesort\
ansistrip punk::ansi::stripansi\
]
#*** !doctools
#[subsection {Namespace punk::aliascore}]
#[para] Core API functions for punk::aliascore
#[list_begin definitions]
#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"
#}
#todo - options as to whether we should raise an error if collisions found, undo aliases etc?
proc init {args} {
set defaults {-force 0}
set opts [dict merge $defaults $args]
set opt_force [dict get $opts -force]
variable aliases
if {!$opt_force} {
set existing [list]
set conflicts [list]
foreach {a cmd} $aliases {
if {[info commands ::$a] ne ""} {
lappend existing $a
set existing_target [interp alias "" $a]
if {$existing_target ne $cmd} {
#command exists in global ns but is either an alias to something else, or some other type of command
lappend conflicts $a
}
}
}
if {[llength $conflicts]} {
error "punk::aliascore::init declined to create any aliases because -force == 0 and conflicts found:$conflicts"
}
}
dict for {a cmd} $aliases {
interp alias {} $a {} {*}$cmd
}
return [dict keys $aliases]
}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::aliascore ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#interp alias {} list_as_lines {} punk::lib::list_as_lines
#interp alias {} lines_as_list {} punk::lib::lines_as_list
#interp alias {} ansistrip {} punk::ansi::stripansi ;#review
#interp alias {} linelist {} punk::lib::linelist ;#critical for = assignment features
#interp alias {} linesort {} punk::lib::linesort
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::aliascore::lib {
namespace export {[a-z]*} ;# Convention: export all lowercase
namespace path [namespace parent]
#*** !doctools
#[subsection {Namespace punk::aliascore::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::aliascore::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval punk::aliascore::system {
#*** !doctools
#[subsection {Namespace punk::aliascore::system}]
#[para] Internal functions that are not part of the API
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::aliascore [namespace eval punk::aliascore {
variable pkg punk::aliascore
variable version
set version 999999.0a1.0
}]
return
#*** !doctools
#[manpage_end]

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

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

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

@ -141,19 +141,20 @@ namespace eval punk::ansi::class {
if {[llength $arglist] %2 != 0} { if {[llength $arglist] %2 != 0} {
puts stderr "render_to_input_line usage: ?-dimensions WxH? ?-minus charcount? x" puts stderr "render_to_input_line usage: ?-dimensions WxH? ?-minus charcount? x"
} }
set defaults [dict create\ set opts [dict create\
-dimensions 80x24\ -dimensions 80x24\
-minus 0\ -minus 0\
] ]
dict for {k v} $arglist { dict for {k v} $arglist {
switch -- $k { switch -- $k {
-dimensions - -minus { } -dimensions - -minus {
dict set opts $k $v
}
default { default {
puts stderr "render_to_input_line unexpected argument '$k' usage: ?-dimensions WxH? ?-minus charcount? x" puts stderr "render_to_input_line unexpected argument '$k' usage: ?-dimensions WxH? ?-minus charcount? x"
} }
} }
} }
set opts [dict merge $defaults $arglist]
set opt_dimensions [dict get $opts -dimensions] set opt_dimensions [dict get $opts -dimensions]
set opt_minus [dict get $opts -minus] set opt_minus [dict get $opts -minus]
lassign [split $opt_dimensions x] w h lassign [split $opt_dimensions x] w h
@ -221,15 +222,17 @@ namespace eval punk::ansi::class {
-vt 0\ -vt 0\
-width "auto"\ -width "auto"\
] ]
set opts $defaults
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-lf - -vt - -width {} -lf - -vt - -width {
dict set opts $k $v
}
default { default {
error "viewcodes unrecognised option '$k'. Known options [dict keys $defaults]" error "viewcodes unrecognised option '$k'. Known options [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opts_lf [dict get $opts -lf] set opts_lf [dict get $opts -lf]
set opts_vt [dict get $opts -vt] set opts_vt [dict get $opts -vt]
set opts_width [dict get $opts -width] set opts_width [dict get $opts -width]
@ -249,15 +252,17 @@ namespace eval punk::ansi::class {
set defaults [list\ set defaults [list\
-width "auto"\ -width "auto"\
] ]
set opts $defaults
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-width {} -width {
dict set opts $k $v
}
default { default {
error "viewchars unrecognised option '$k'. Known options [dict keys $defaults]" error "viewchars unrecognised option '$k'. Known options [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opts_width [dict get $opts -width] set opts_width [dict get $opts -width]
if {$opts_width eq ""} { if {$opts_width eq ""} {
return [punk::ansi::stripansiraw [$o_ansistringobj get]] return [punk::ansi::stripansiraw [$o_ansistringobj get]]
@ -275,15 +280,17 @@ namespace eval punk::ansi::class {
set defaults [list\ set defaults [list\
-width "auto"\ -width "auto"\
] ]
set opts $defaults
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-width {} -width {
dict set opts $k $v
}
default { default {
error "viewstyle unrecognised option '$k'. Known options [dict keys $defaults]" error "viewstyle unrecognised option '$k'. Known options [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set opts_width [dict get $opts -width] set opts_width [dict get $opts -width]
if {$opts_width eq ""} { if {$opts_width eq ""} {
return [ansistring VIEWSTYLE [$o_ansistringobj get]] return [ansistring VIEWSTYLE [$o_ansistringobj get]]
@ -1423,16 +1430,17 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
} }
proc colourmap1 {args} { proc colourmap1 {args} {
set defaults {-bg Web-white -forcecolour 0} set opts {-bg Web-white -forcecolour 0}
dict for {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-bg - -forcecolour {} -bg - -forcecolour {
dict set opts $k $v
}
default { default {
error "colourmap1 unrecognised option $k. Known-options: [dict keys $defaults] error "colourmap1 unrecognised option $k. Known-options: [dict keys $opts]
} }
} }
} }
set opts [dict merge $defaults $args]
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc "forcecolour" set fc "forcecolour"
} else { } else {
@ -1815,16 +1823,17 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
# $WEB_colour_map_gray\ # $WEB_colour_map_gray\
#] #]
proc colourtable_web {args} { proc colourtable_web {args} {
set defaults {-forcecolour 0 -groups *} set opts {-forcecolour 0 -groups *}
foreach {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-groups - -forcecolour {} -groups - -forcecolour {
dict set opts $k $v
}
default { default {
error "colourtable_web unrecognised option '$k'. Known-options: [dict keys $defaults]" error "colourtable_web unrecognised option '$k'. Known-options: [dict keys $defaults]"
} }
} }
} }
set opts [dict merge $defaults $args]
set fc "" set fc ""
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc "forcecolour" set fc "forcecolour"
@ -1894,19 +1903,20 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
proc colourtable_x11diff {args} { proc colourtable_x11diff {args} {
variable X11_colour_map_diff variable X11_colour_map_diff
variable WEB_colour_map variable WEB_colour_map
set defaults [dict create\ set opts [dict create\
-forcecolour 0\ -forcecolour 0\
-return "string"\ -return "string"\
] ]
dict for {k v} $args { foreach {k v} $args {
switch -- $k { switch -- $k {
-return - -forcecolour {} -return - -forcecolour {
dict set opts $k $v
}
default { default {
error "colourtable_x11diff unrecognised option '$k'. Known options [dict keys $defaults]" error "colourtable_x11diff unrecognised option '$k'. Known options [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set fc "" set fc ""
if {[dict get $opts -forcecolour]} { if {[dict get $opts -forcecolour]} {
set fc "forcecolour" set fc "forcecolour"
@ -3698,20 +3708,21 @@ namespace eval punk::ansi {
variable codestate_empty variable codestate_empty
set othercodes [list] set othercodes [list]
set defaults [dict create\ set opts [dict create\
-filter_fg 0\ -filter_fg 0\
-filter_bg 0\ -filter_bg 0\
-filter_reset 0\ -filter_reset 0\
] ]
dict for {k v} $args { dict for {k v} $args {
switch -- $k { switch -- $k {
-filter_fg - -filter_bg - -filter_reset {} -filter_fg - -filter_bg - -filter_reset {
dict set opts $k $v
}
default { default {
error "sgr_merge unknown option '$k'. Known options [dict keys $defaults]" error "sgr_merge unknown option '$k'. Known options [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $args]
set codestate $codestate_empty set codestate $codestate_empty
set codestate_initial $codestate_empty ;#keep a copy for resets. set codestate_initial $codestate_empty ;#keep a copy for resets.
@ -4331,6 +4342,39 @@ namespace eval punk::ansi::ta {
} }
return [lappend list [string range $text $start end]] return [lappend list [string range $text $start end]]
} }
#experiment for coroutine generator
proc _perlish_split_yield {re text} {
if {[string length $text] == 0} {
yield {}
}
set list [list]
set start 0
#We can get $matchEnd < $matchStart; we need to ensure there is an exit condition for non-greedy empty results REVIEW
while {[regexp -start $start -indices -- $re $text match]} {
lassign $match matchStart matchEnd
#puts "->start $start ->match $matchStart $matchEnd"
if {$matchEnd < $matchStart} {
yield [string range $text $start $matchStart-1]
yield [string index $text $matchStart]
incr start
if {$start >= [string length $text]} {
break
}
continue
}
yield [string range $text $start $matchStart-1]
yield [string range $text $matchStart $matchEnd]
set start [expr {$matchEnd+1}]
#?
if {$start >= [string length $text]} {
break
}
}
#return [lappend list [string range $text $start end]]
yield [string range $text $start end]
}
proc _perlish_split2 {re text} { proc _perlish_split2 {re text} {
if {[string length $text] == 0} { if {[string length $text] == 0} {
return {} return {}
@ -4399,7 +4443,7 @@ namespace eval punk::ansi::class {
error {usage: ?-width <int>? ?-wrap [1|0]? ?-overflow [1|0]? from_ansistring to_ansistring} error {usage: ?-width <int>? ?-wrap [1|0]? ?-overflow [1|0]? from_ansistring to_ansistring}
} }
lassign [lrange $args end-1 end] from_ansistring to_ansistring lassign [lrange $args end-1 end] from_ansistring to_ansistring
set defaults [dict create\ set opts [dict create\
-width \uFFEF\ -width \uFFEF\
-wrap 1\ -wrap 1\
-overflow 0\ -overflow 0\
@ -4411,17 +4455,17 @@ namespace eval punk::ansi::class {
] ]
puts "[info object class [self]] renderer [self] constructor from ansistring $from_ansistring to ansistring $to_ansistring" puts "[info object class [self]] renderer [self] constructor from ansistring $from_ansistring to ansistring $to_ansistring"
set argsflags [lrange $args 0 end-2] set argsflags [lrange $args 0 end-2]
dict for {k v} $argsflags { foreach {k v} $argsflags {
switch -- $k { switch -- $k {
-width - -wrap - -overflow - -appendlines - -looplimit - -experimental {} -width - -wrap - -overflow - -appendlines - -looplimit - -experimental {
dict set opts $k $v
}
default { default {
set known_opts [dict keys $defaults]
#don't use [self class] - or we'll get the superclass #don't use [self class] - or we'll get the superclass
error "[info object class [self]] unknown option '$k'. Known options: $known_opts" error "[info object class [self]] unknown option '$k'. Known options: [dict keys $opts]"
} }
} }
} }
set opts [dict merge $defaults $argsflags]
set o_width [dict get $opts -width] set o_width [dict get $opts -width]
set o_wrap [dict get $opts -wrap] set o_wrap [dict get $opts -wrap]
set o_overflow [dict get $opts -overflow] set o_overflow [dict get $opts -overflow]

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

File diff suppressed because it is too large Load Diff

5
src/modules/punk/basictelnet-999999.0a1.0.tm

@ -45,7 +45,7 @@
#[para] packages used by punk::basictelnet #[para] packages used by punk::basictelnet
#[list_begin itemized] #[list_begin itemized]
package require Tcl 8.6 package require Tcl 8.6-
#*** !doctools #*** !doctools
#[item] [package {Tcl 8.6}] #[item] [package {Tcl 8.6}]
@ -492,6 +492,8 @@ namespace eval punk::basictelnet {
proc toServer {sock} { proc toServer {sock} {
variable server_option_state variable server_option_state
variable encoding_guess variable encoding_guess
#note that this punk::console namespace is likely to be in a different thread (codethread) to the punk::repl thread which will have it's own punk::console namespace
# - even though they may both be using the same stdin stdout. The repl readloop will be inactive during the call to telnet
upvar ::punk::console::input_chunks_waiting input_chunks_waiting upvar ::punk::console::input_chunks_waiting input_chunks_waiting
set nextwaiting "" set nextwaiting ""
@ -821,6 +823,7 @@ namespace eval punk::basictelnet {
catch {fileevent $sock readable {}} catch {fileevent $sock readable {}}
catch {close $sock} catch {close $sock}
set closed($sock) 1 set closed($sock) 1
fileevent stdin readable {}
} }
proc write string { proc write string {

25
src/modules/punk/cap-999999.0a1.0.tm

@ -350,15 +350,19 @@ namespace eval punk::cap {
variable pkgcapsdeclared variable pkgcapsdeclared
variable pkgcapsaccepted variable pkgcapsaccepted
variable caps variable caps
set defaults [dict create\ set opts [dict create\
-nowarnings false -nowarnings false
] ]
dict for {k v} $args { foreach {k v} $args {
if {$k ni $defaults} { switch -- $k {
error "Unrecognized option $k. Known options [dict keys $defaults]" -nowarnings {
dict set opts $k $v
}
default {
error "Unrecognized option $k. Known options [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
set warnings [expr {! [dict get $opts -nowarnings]}] set warnings [expr {! [dict get $opts -nowarnings]}]
if {[string match ::* $pkg]} { if {[string match ::* $pkg]} {
@ -433,13 +437,14 @@ namespace eval punk::cap {
#another call to register_pkg with same pkg may have been made (most likely with different capname) so we must append - but check not already present #another call to register_pkg with same pkg may have been made (most likely with different capname) so we must append - but check not already present
#dict lappend pkgcapsdeclared $pkg $capabilitylist #dict lappend pkgcapsdeclared $pkg $capabilitylist
if {[dict exists $pkgcapsdeclared $pkg]} { if {[dict exists $pkgcapsdeclared $pkg]} {
set capspecs [dict get $pkgcapsdeclared $pkg] #review - untested
foreach spec $capspecs { set mergecapspecs [dict get $pkgcapsdeclared $pkg]
if {$spec ni $capspecs} { foreach spec $capabilitylist {
lappend capspecs $spec if {$spec ni $mergecapspecs} {
lappend mergecapspecs $spec
} }
} }
dict set pkgcapsdeclared $pkg $capspecs dict set pkgcapsdeclared $pkg $mergecapspecs
} else { } else {
dict set pkgcapsdeclared $pkg $capabilitylist dict set pkgcapsdeclared $pkg $capabilitylist
} }

27
src/modules/punk/cap/handlers/templates-999999.0a1.0.tm

@ -242,9 +242,12 @@ namespace eval punk::cap::handlers::templates {
set capabilityname $capname set capabilityname $capname
} }
method folders {args} { method folders {args} {
lassign [punk::args::opts_values { set argd [punk::args::get_dict {
-startdir -default "" -startdir -default ""
} $args -maxvalues 0] _o opts *values -max 0
} $args]
set opts [dict get $argd opts]
set opt_startdir [dict get $opts -startdir] set opt_startdir [dict get $opts -startdir]
if {$opt_startdir eq ""} { if {$opt_startdir eq ""} {
set startdir [pwd] set startdir [pwd]
@ -456,11 +459,14 @@ namespace eval punk::cap::handlers::templates {
return $folderdict return $folderdict
} }
method get_itemdict_projectlayouts {args} { method get_itemdict_projectlayouts {args} {
lassign [punk::args::opts_values { set argd [punk::args::get_dict {
-startdir -default "" *opts -anyopts 1
#peek -startdir while allowing all other opts/vals to be verified down-the-line instead of here #peek -startdir while allowing all other opts/vals to be verified down-the-line instead of here
} $args -maxvalues -1 -anyopts 1] _o opts _v values -startdir -default ""
set opt_startdir [dict get $opts -startdir] *values -maxvalues -1
} $args]
set opt_startdir [dict get $argd opts -startdir]
if {$opt_startdir eq ""} { if {$opt_startdir eq ""} {
set searchbase [pwd] set searchbase [pwd]
} else { } else {
@ -628,15 +634,18 @@ namespace eval punk::cap::handlers::templates {
#and a file selection mechanism command -command_get_items_from_base #and a file selection mechanism command -command_get_items_from_base
#and a name determining command -command_get_item_name #and a name determining command -command_get_item_name
method _get_itemdict {args} { method _get_itemdict {args} {
lassign [punk::args::opts_values { set argd [punk::args::get_dict {
*opts -anyopts 0
-startdir -default "" -startdir -default ""
-templatefolder_subdir -optional 0 -templatefolder_subdir -optional 0
-command_get_items_from_base -optional 0 -command_get_items_from_base -optional 0
-command_get_item_name -optional 0 -command_get_item_name -optional 0
-not -default "" -multiple 1 -not -default "" -multiple 1
*values -maxvalues -1
globsearches -default * -multiple 1 globsearches -default * -multiple 1
} $args -maxvalues -1] _o opts _v values } $args]
set globsearches [dict get $values globsearches]; #note that in this case our globsearch won't reduce the machine's effort in scannning the filesystem - as we need to search on the renamed results set opts [dict get $argd opts]
set globsearches [dict get $argd values globsearches]; #note that in this case our globsearch won't reduce the machine's effort in scannning the filesystem - as we need to search on the renamed results
# -- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- ---
set opt_startdir [dict get $opts -startdir] set opt_startdir [dict get $opts -startdir]
set opt_templatefolder_subdir [dict get $opts -templatefolder_subdir] set opt_templatefolder_subdir [dict get $opts -templatefolder_subdir]

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

@ -1205,22 +1205,25 @@ namespace eval punk::char {
} }
proc char_info_dec {dec args} { proc char_info_dec {dec args} {
set dec_char [expr {$dec}] set dec_char [expr {$dec}]
set defaults [dict create\ set opts [dict create\
-fields {default}\ -fields {default}\
-except {}\ -except {}\
] ]
set known_opts [dict keys $defaults]
#testwidth is so named because it peforms an actual test on the console using ansi escapes - and the name gives a hint that it is a little slow #testwidth is so named because it peforms an actual test on the console using ansi escapes - and the name gives a hint that it is a little slow
set known_fields [list all default dec hex desc short testwidth char memberof] ;#maint fields from charinfo 'desc' 'short' set known_fields [list all default dec hex desc short testwidth char memberof] ;#maint fields from charinfo 'desc' 'short'
#todo - unicode properties #todo - unicode properties
# tclwhitespace (different to unicode concept of whitespace. review ) # tclwhitespace (different to unicode concept of whitespace. review )
foreach {k v} $args { foreach {k v} $args {
if {![dict exists $defaults $k]} { switch -- $k {
error "char_info unrecognised option '$k'. Known options:'$known_opts' known_fields: $known_fields usage: char_info <char> ?-fields {<fieldnames>}? ?-except {<fieldnames>}?" -fields - -except {
dict set opts $k $v
}
default {
error "char_info unrecognised option '$k'. Known options:'[dict keys $opts]' known_fields: $known_fields usage: char_info <char> ?-fields {<fieldnames>}? ?-except {<fieldnames>}?"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- ---
set opt_fields [dict get $opts -fields] set opt_fields [dict get $opts -fields]
set opt_except [dict get $opts -except] set opt_except [dict get $opts -except]
@ -1569,6 +1572,7 @@ namespace eval punk::char {
if {$name_or_glob eq "*"} { if {$name_or_glob eq "*"} {
return [lsort [dict keys $charsets]] return [lsort [dict keys $charsets]]
} }
#dict keys $dict <pattern> doesn't have option for case insensitive searches
return [lsort [lsearch -all -inline -nocase [dict keys $charsets] $name_or_glob]] return [lsort [lsearch -all -inline -nocase [dict keys $charsets] $name_or_glob]]
} }
} }

9
src/modules/punk/config-0.1.tm

@ -47,6 +47,9 @@ namespace eval punk::config {
#default file logs to logs folder at same location as exe if writable, or empty string #default file logs to logs folder at same location as exe if writable, or empty string
dict set startup logfile_stdout "" dict set startup logfile_stdout ""
dict set startup logfile_stderr "" dict set startup logfile_stderr ""
set exename [info nameofexecutable]
if {$exename ne ""} {
set exefolder [file dirname [info nameofexecutable]] set exefolder [file dirname [info nameofexecutable]]
set log_folder $exefolder/logs set log_folder $exefolder/logs
dict set startup scriptlib $exefolder/scriptlib dict set startup scriptlib $exefolder/scriptlib
@ -57,6 +60,12 @@ namespace eval punk::config {
dict set startup logfile_stderr $log_folder/repl-exec-stderr.txt dict set startup logfile_stderr $log_folder/repl-exec-stderr.txt
} }
} }
} else {
#probably a safe interp - which cannot access info nameofexecutable even if access given to the location via punk::island
#review - todo?
dict set startup scriptlib ""
dict set startup apps ""
}
#todo - load/write config file #todo - load/write config file

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

@ -671,7 +671,7 @@ namespace eval punk::console {
} else { } else {
#! todo? for now, emit a clue as to what's happening. #! todo? for now, emit a clue as to what's happening.
puts stderr "[punk::ansi::a+ yellow bold]-->punk::console::get_ansi_response_payload cannot trigger existing handler $existing_handler while over-read data is in punk::console::input_chunks_waiting($input) instead of channel [ansistring VIEW $input_chunks_waiting($input)][punk::ansi::a]" puts stderr "[punk::ansi::a+ yellow bold]-->punk::console::get_ansi_response_payload cannot trigger existing handler $existing_handler while over-read data is in punk::console::input_chunks_waiting($input) instead of channel [ansistring VIEW $input_chunks_waiting($input)][punk::ansi::a]"
if {$::repl::running} { if {[package provide punk::repl::codethread] ne "" && [punk::repl::codethread::is_running]} {
if {[eof $input]} { if {[eof $input]} {
puts stdout "restarting repl" puts stdout "restarting repl"
repl::reopen_stdin repl::reopen_stdin
@ -682,7 +682,7 @@ namespace eval punk::console {
#Note - we still may be in_repl_handler here (which disables its own reader while executing commandlines) #Note - we still may be in_repl_handler here (which disables its own reader while executing commandlines)
#The input_chunks_waiting may really belong to the existing_handler we found - but if it doesn't consume them they will end up being read by the repl_handler when it eventually re-enables. #The input_chunks_waiting may really belong to the existing_handler we found - but if it doesn't consume them they will end up being read by the repl_handler when it eventually re-enables.
#todo - some better structure than just a list of waiting chunks indexed by input channel, so repl/other handlers can determine the context in which these waiting chunks were generated? #todo - some better structure than just a list of waiting chunks indexed by input channel, so repl/other handlers can determine the context in which these waiting chunks were generated?
} elseif {$::repl::running} { } elseif {[package provide punk::repl::codethread] ne "" && [punk::repl::codethread::is_running]} {
if {[llength $input_chunks_waiting($input)]} { if {[llength $input_chunks_waiting($input)]} {
#don't trigger the repl handler manually - we will inevitably get things out of order - as it knows when to enable/disable itself based on whether chunks are waiting. #don't trigger the repl handler manually - we will inevitably get things out of order - as it knows when to enable/disable itself based on whether chunks are waiting.
#triggering it by putting it on the eventloop will potentially result in re-entrancy #triggering it by putting it on the eventloop will potentially result in re-entrancy
@ -1030,10 +1030,29 @@ namespace eval punk::console {
#todo - determine cursor on/off state before the call to restore properly. May only be possible #todo - determine cursor on/off state before the call to restore properly. May only be possible
proc get_size {{inoutchannels {stdin stdout}}} { proc get_size {{inoutchannels {stdin stdout}}} {
lassign $inoutchannels in out lassign $inoutchannels in out
#we can't reliably use [chan names] for stdin,stdout. There could be stacked channels and they may have a names such as file22fb27fe810
#chan eof is faster whether chan exists or not than
if {[catch {chan eof $in} is_eof]} {
error "punk::console::get_size input channel $in seems to be closed ([info level 1])"
} else {
if {$is_eof} {
error "punk::console::get_size eof on input channel $in ([info level 1])"
}
}
if {[catch {chan eof $out} is_eof]} {
error "punk::console::get_size output channel $out seems to be closed ([info level 1])"
} else {
if {$is_eof} {
error "punk::console::get_size eof on output channel $out ([info level 1])"
}
}
#keep out of catch - no point in even trying a restore move if we can't get start position - just fail here.
lassign [get_cursor_pos_list $inoutchannels] start_row start_col
if {[catch { if {[catch {
#some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that.
#This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere.
lassign [get_cursor_pos_list $inoutchannels] start_row start_col
puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::move 2000 2000] puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::move 2000 2000]
lassign [get_cursor_pos_list $inoutchannels] lines cols lassign [get_cursor_pos_list $inoutchannels] lines cols
puts -nonewline $out [punk::ansi::move $start_row $start_col][punk::console::cursor_on];flush stdout puts -nonewline $out [punk::ansi::move $start_row $start_col][punk::console::cursor_on];flush stdout
@ -1251,7 +1270,7 @@ namespace eval punk::console {
return [exec {*}$cmd1] return [exec {*}$cmd1]
} else { } else {
puts stderr "infocmp doesn't seem to be present" puts stderr "infocmp doesn't seem to be present"
if {$::tcl_platform(os) eq "FreeBSD"} { if {$::tcl_platform(platform) eq "FreeBSD"} {
puts stderr "For FreeBSD - install ncurses to get infocmp and related binaries and also install terminfo-db" puts stderr "For FreeBSD - install ncurses to get infocmp and related binaries and also install terminfo-db"
} }
set tcmd [auto_execok tput] set tcmd [auto_execok tput]
@ -1395,6 +1414,9 @@ namespace eval punk::console {
namespace import ansi::insert_lines namespace import ansi::insert_lines
namespace import ansi::delete_lines namespace import ansi::delete_lines
interp alias {} smcup {} ::punk::console::enable_alt_screen
interp alias {} rmcup {} ::punk::console::disable_alt_screen
#experimental #experimental
proc rhs_prompt {col text} { proc rhs_prompt {col text} {
package require textblock package require textblock
@ -1784,11 +1806,13 @@ namespace eval punk::console {
interp alias {} colour {} punk::console::colour
interp alias {} ansi {} punk::console::ansi
interp alias {} color {} punk::console::colour
interp alias {} a+ {} punk::console::code_a+
interp alias {} a= {} punk::console::code_a
interp alias {} a {} punk::console::code_a
interp alias {} a? {} punk::console::code_a?

17
src/modules/punk/du-999999.0a1.0.tm

@ -25,8 +25,10 @@ namespace eval punk::du {
variable has_twapi 0 variable has_twapi 0
} }
if {"windows" eq $::tcl_platform(platform)} { if {"windows" eq $::tcl_platform(platform)} {
if {![interp issafe]} {
package require zzzload package require zzzload
zzzload::pkg_require twapi zzzload::pkg_require twapi
}
if {[catch {package require twapi}]} { if {[catch {package require twapi}]} {
puts stderr "Warning: punk::du - unable to load twapi. Disk operations may be much slower on windows without the twapi package" puts stderr "Warning: punk::du - unable to load twapi. Disk operations may be much slower on windows without the twapi package"
@ -818,19 +820,22 @@ namespace eval punk::du {
#this is the cross-platform pure-tcl version - which calls glob multiple times to make sure it gets everythign it needs and can ignore everything it needs to. #this is the cross-platform pure-tcl version - which calls glob multiple times to make sure it gets everythign it needs and can ignore everything it needs to.
#These repeated calls to glob will be a killer for performance - especially on a network share or when walking a large directory structure #These repeated calls to glob will be a killer for performance - especially on a network share or when walking a large directory structure
proc du_dirlisting_generic {folderpath args} { proc du_dirlisting_generic {folderpath args} {
set defaults [dict create\ set opts [dict create\
-glob *\ -glob *\
-with_sizes 0\ -with_sizes 0\
-with_times 0\ -with_times 0\
] ]
set errors [dict create] set errors [dict create]
set known_opts [dict keys $defaults] foreach {k v} $args {
dict for {k -} $args { switch -- $k {
if {$k ni $known_opts} { -glob - -with_sizes - -with_times {
error "du_dirlisting_generic unknown-option $k" dict set opts $k $v
}
default {
error "du_dirlisting_generic unknown-option '$k'. Known-options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_glob [dict get $opts -glob] set opt_glob [dict get $opts -glob]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---

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

@ -1,4 +1,4 @@
# -*- tcl -*- # -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt # Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
# #
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem. # Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem.
@ -275,7 +275,7 @@ namespace eval punk::fileline::class {
#[call class::textinfo [method chunk_boundary_display]] #[call class::textinfo [method chunk_boundary_display]]
#[para]Returns a string displaying the boundaries at chunksize bytes between chunkstart and chunkend #[para]Returns a string displaying the boundaries at chunksize bytes between chunkstart and chunkend
#[para]Defaults to using ansi colour if punk::ansi module is available. Use -ansi 0 to disable colour #[para]Defaults to using ansi colour if punk::ansi module is available. Use -ansi 0 to disable colour
set defaults [dict create\ set opts [dict create\
-ansi $::punk::fileline::ansi::enabled\ -ansi $::punk::fileline::ansi::enabled\
-offset 0\ -offset 0\
-displaybytes 200\ -displaybytes 200\
@ -292,11 +292,15 @@ namespace eval punk::fileline::class {
] ]
set known_opts [dict keys $defaults] set known_opts [dict keys $defaults]
foreach {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
error "[self]::chunk_boundary error: unknown option '$k'. Known options: $known_opts" -ansi - -offset - -displaybytes - -truncatedmark - -completemark - -moremark - -continuemark - -linemaxwidth - -linebase - -limit - -boundaries - -showconfig - -boundaryheader {
dict set opts $k $v
}
default {
error "[self]::chunk_boundary error: unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_ansi [dict get $opts -ansi] set opt_ansi [dict get $opts -ansi]
set opt_offset [dict get $opts -offset] set opt_offset [dict get $opts -offset]
@ -612,20 +616,23 @@ namespace eval punk::fileline::class {
#[para]This is true even if only a single square bracket is being searched for. e.g {*[lb]file*} will not find the word file followed by a left square-bracket - even though the search didn't close the square brackets. #[para]This is true even if only a single square bracket is being searched for. e.g {*[lb]file*} will not find the word file followed by a left square-bracket - even though the search didn't close the square brackets.
#[para]In the above case - the literal search should be {*\[lb]file*} #[para]In the above case - the literal search should be {*\[lb]file*}
set defaults [dict create\ set opts [dict create\
-limit 0\ -limit 0\
-strategy 1\ -strategy 1\
-start 0\ -start 0\
-end end\ -end end\
-limitfrom start\ -limitfrom start\
] ]
set known_opts [dict keys $defaults] foreach {k v} $args {
dict for {k v} $args { switch -- $k {
if {$k ni $known_opts} { -limit - -strategy - -start - -end - -limitfrom {
error "linepayload_find_glob unknown option '$k'. Known options: $known_opts" dict set opts $k $v
}
default {
error "linepayload_find_glob unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_limit [dict get $opts -limit] set opt_limit [dict get $opts -limit]
if {![string is integer -strict $opt_limit] || $opt_limit < 0} { if {![string is integer -strict $opt_limit] || $opt_limit < 0} {
@ -1261,13 +1268,14 @@ namespace eval punk::fileline {
#[para]Currently only utf-8, utf-16* and utf-32* are properly supported even though the other BOMs are detected, reported via get_bomid, and stripped from the data. #[para]Currently only utf-8, utf-16* and utf-32* are properly supported even though the other BOMs are detected, reported via get_bomid, and stripped from the data.
#[para]GB18030 falls back to cp936/gbk (unless a gb18030 encoding has been installed). Use -encoding binary if this isn't suitable and you need to do your own processing of the raw data. #[para]GB18030 falls back to cp936/gbk (unless a gb18030 encoding has been installed). Use -encoding binary if this isn't suitable and you need to do your own processing of the raw data.
set defaults { set argument_specification {
-file -default {} -type existingfile -file -default {} -type existingfile
-translation -default binary -translation -default binary
-encoding -default "\uFFFF" -encoding -default "\uFFFF"
-includebom -default 0 -includebom -default 0
*values -min 0 -max 1
} }
lassign [dict values [punk::args::opts_values $defaults $args -minvalues 0 -maxvalues 1]] opts values lassign [dict values [punk::args::get_dict $argument_specification $args]] opts values
# -- --- --- --- # -- --- --- ---
set opt_file [dict get $opts -file] set opt_file [dict get $opts -file]
set opt_translation [dict get $opts -translation] set opt_translation [dict get $opts -translation]
@ -1591,16 +1599,19 @@ namespace eval punk::fileline::system {
#much faster when resultant boundary size is large (at least when offset 0) #much faster when resultant boundary size is large (at least when offset 0)
proc _range_spans_chunk_boundaries_lseq {start end chunksize args} { proc _range_spans_chunk_boundaries_lseq {start end chunksize args} {
if {$chunksize < 1} {error "chunksize must be > 0"} ;#sanitycheck in case called directly if {$chunksize < 1} {error "chunksize must be > 0"} ;#sanitycheck in case called directly
set defaults [dict create\ set opts [dict create\
-offset 0\ -offset 0\
] ]
set known_opts [dict keys $defaults]
foreach {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
error "unknown option '$k'. Known options: $known_opts" -offset {
dict set opts $k $v
}
default {
error "unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- # -- --- --- ---
set opt_offset [dict get $opts -offset] set opt_offset [dict get $opts -offset]
# -- --- --- --- # -- --- --- ---

561
src/modules/punk/island-999999.0a1.0.tm

@ -0,0 +1,561 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'pmix make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.2.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) 2024
#
# @@ Meta Begin
# Application punk::island 999999.0a1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
#This version of island has been namespaced as the package punk::island as it may need to diverge in functionality for the purposes of use in the punk::repl system.
#see: https://wiki.tcl-lang.org/page/island
##################
## Module Name -- island.tcl
## Original Author -- Emmanuel Frecon - efrecon@gmail.com
## Description:
##
## Package to a allow a safe interpreter to access islands of the
## filesystem only, i.e. restricted directory trees within the
## filesystem. The package brings back file, open and glob to the slave
## interpreter, though in a restricted manner.
##
##################
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin shellspy_module_punk::island 0 999999.0a1.0]
#[copyright "2024"]
#[titledesc {filesystem islands for safe interps}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk::island for safe interps}] [comment {-- Description at end of page heading --}]
#[require punk::island]
#[keywords module interp filesystem]
#[description]
#[para] Package to a allow a safe interpreter to access islands of the
#[para] filesystem only, i.e. restricted directory trees within the
#[para] filesystem. The package brings back file, open and glob to the child interp
#[para] interpreter, though in a restricted manner.
#[para] JN Warning:
#[para] This mechanism can have interactions with package loading from auto_path - needs review.
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of punk::island
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by punk::island
#[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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::island::class {
#*** !doctools
#[subsection {Namespace punk::island::class}]
#[para] class definitions
if {[info commands [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 ---}]
}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Will host information for interpreters
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::island::interps {
#*** !doctools
#[subsection {Namespace punk::island::interps}]
#[para] hosts information for interpreters
#[list_begin definitions]
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::island::interps ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::island {
namespace export {[a-z]*}; # Convention: export all lowercase
namespace ensemble create
#*** !doctools
#[subsection {Namespace punk::island}]
#[para] Core API functions for punk::island
#[list_begin definitions]
#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 string p1] A description of string argument p1.
# # [arg_def integer n] A description of integer argument n.
# # [list_end]
# return "ok"
#}
proc add { child path } {
#*** !doctools
#[call [fun add] [arg child] [arg path]]
#[para] Add a path to the list of paths that are explicitely allowed for access
#[para] to a child interpreter. Access to any path that has not been explicitely
#[para] allowed will be denied. Paths that are added to the list of allowed
#[para] islands are always fully normalized.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter to control
# [list_end]
set vname [namespace current]::interps::[string map {: _} $child]
if { ![info exists $vname]} {
system::Init $child
}
upvar \#0 $vname paths
lappend paths [::file dirname [::file normalize $path/___]]
}
proc reset { child } {
#*** !doctools
#[call [fun reset] [arg child]]
#[para] Remove all access path allowance and arrange for the interpreter to be
#[para] able to return to the regular safe state.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter
# [list_end]
set vname [namespace current]::interps::[string map {: _} $child]
if { [info exists $vname] } {
$child alias file {}
$child alias open {}
$child alias glob {}
$child alias fconfigure {}
unset $vname
}
}
########################
##
## Procedures below are internal to the implementation.
##
########################
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::island ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::island::lib {
namespace export *
namespace path [namespace parent]
#*** !doctools
#[subsection {Namespace punk::island::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::island::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval punk::island::system {
#*** !doctools
#[subsection {Namespace punk::island::system}]
#[para] Internal functions that are not part of the API
#[list_begin definitions]
proc Allowed { child fname } {
#*** !doctools
#[call [fun Allowed] [arg child] [arg fname]]
#[para] Check that the file name passed as an argument is within the islands of
#[para] the filesystem that have been registered through the add command for a
#[para] given (safe) interpreter. The path is fully normalized before testing
#[para] against the islands, which themselves are fully normalized.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter
# [arg_def string fname] (relative) path to the file to test
# [list_end]
set vname ::punk::island::interps::[string map {: _} $child]
upvar \#0 $vname paths
set abs_fname [::file dirname [::file normalize $fname/___]]
foreach path $paths {
if { [string first $path $abs_fname] == 0 } {
return 1
}
}
return 0
}
proc File { child cmd args } {
#*** !doctools
#[call [fun File] [arg child] [arg cmd] [arg args]]
#[para] Parses the options and arguments to the file command to discover which
#[para] paths it tries to access and only return the results of its execution
#[para] when these path are within the allowed islands of the filesystem.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter
# [arg_def string cmd] Subcommand of the file command
# [arg_def string args] Arguments to the file subcommand
# [list_end]
switch $cmd {
atime -
attributes -
executable -
exists -
isdirectory -
isfile -
lstat -
mtime -
normalize -
owned -
readable -
readlink -
size -
stat -
system -
type -
writable {
set fname [lindex $args 0]
if { [Allowed $child $fname] } {
return [uplevel [linsert $args 0 ::file $cmd]]
# file is highly restrictive in child interpreters, so we can't do the following.
return [uplevel [linsert $args 0 $child invokehidden ::file $cmd]]
} else {
#return -code error "Access to $fname denied."
return [uplevel [linsert $args 0 $child invokehidden ::file $cmd]]
#return [uplevel [list $child invokehidden tcl:file:$cmd {*}$args]]
}
}
channels -
dirname -
extension -
join -
nativename -
pathtype -
rootname -
separator -
split -
tail -
volumes {
return [uplevel [list ::file $cmd {*}$args]]
# file is highly restrictive in child interpreters, so we can't do the following.
# (result would be error: invalid hidden command name "file")
return [uplevel [linsert $args 0 $child invokehidden file $cmd]]
}
copy -
delete -
rename -
link {
set idx [lsearch $args "--"]
if { $idx >= 0 } {
set paths [lrange $args [expr {$idx+1}] end]
} else {
if { [string index [lindex $args 0] 0] eq "-" } {
set paths [lrange $args 1 end]
} else {
set paths $args
}
}
foreach path $paths {
if { ![Allowed $child $path] } {
return -code error "Access to $path denied."
}
}
return [uplevel [linsert $args 0 ::file $cmd]]
# file is highly restrictive in child interpreters, so we can't do the following.
return [uplevel [linsert $args 0 $child invokehidden file $cmd]]
}
mkdir {
foreach path $args {
if { ![Allowed $child $path] } {
return -code error "Access to $path denied."
}
}
return [uplevel [linsert $args 0 ::file $cmd]]
# file is highly restrictive in child interps, so we can't do the following.
return [uplevel [linsert $args 0 $child invokehidden file $cmd]]
}
}
}
proc Open { child args } {
#*** !doctools
#[call [fun Open] [arg child] [arg args]]
#[para] Parses the options and arguments to the open command to discover which
#[para] paths it tries to access and only return the results of its execution
#[para] when these path are within the allowed islands of the filesystem.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter
# [arg_def string args] Arguments to the open subcommand
# [list_end]
set fname [lindex $args 0]
if { [string index [string trim $fname] 0] eq "|" } {
return -code error "Execution of external programs disabled."
}
if { [Allowed $child $fname] } {
return [uplevel [list $child invokehidden open {*}$args]]
} else {
return -code error "Access to $fname denied."
}
}
proc Expose { child cmd args } {
#*** !doctools
#[call [fun Expose] [arg child] [arg cmd] [arg args]]
#[para] This procedure allows to callback a command that would typically have
#[para] been hidden from a child interpreter. It does not "interp expose" but
#[para] rather calls the hidden command, so we can easily revert back.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter
# [arg_def string cmd] Hidden command to call
# [arg_def string args] Arguments to the command
# [list_end]
return [uplevel 1 [list $child invokehidden $cmd {*}$args]]
}
proc Glob { child args } {
#*** !doctools
#[call [fun Glob] [arg child] [arg args]]
#[para] Parses the options and arguments to the glob command to discover which
#[para] paths it tries to access and only return the results of its execution
#[para] when these path are within the allowed islands of the filesystem.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter
# [arg_def string args] Arguments to the glob command
# [list_end]
set noargs [list -join -nocomplain -tails ]
set within ""
set flags [list]
set is_join 0 ;#manually handle join
for {set i 0} {$i < [llength $args]} {incr i} {
set itm [lindex $args $i]
if { $itm eq "--" } {
incr i; break
} elseif { [string index $itm 0] eq "-" } {
# Segregates between options that take a value and options that
# have no arguments and are booleans.
if { [lsearch $noargs $itm] < 0 } {
incr i; # Jump over argument
switch -glob -- $itm {
"-dir*" {
set within [lindex $args $i]
append within /
#don't add to flags - will be added back in below if necessary
}
"-path*" {
set within [lindex $args $i]
#don't add to flags
}
default {
#e.g -type -types
lappend flags $itm [lindex $args $i]
}
}
} else {
if {[string match "-j*" $itm]} {
set is_join 1
} else {
lappend flags [lindex $args $i]
}
}
} else {
break
}
}
set paths [dict create]
set what [list]
if {$is_join} {
set patterns [list [join [lrange $args $i end] /]]
} else {
set patterns [lrange $args $i end]
}
foreach ptn $patterns {
set path ${within}$ptn
#look for leading safe tokens of form $p(:digits:) only and detokenize so island can test
set re {(\$p\(:[0-9]*:\))(.*)}
if {[regexp $re $path _all tok tailpattern]} {
set tailpattern [string trim $tailpattern {/}] ;#review
set detok [uplevel [list safe::DetokPath $child $tok]]
set fullpathpattern [string map [list $tok $detok] $path]
set dir $detok
} else {
set fullpathpattern $path
set dir $within
set tailpattern $ptn
set tok "" ;#doesn't apply - we could lookup to see if one happens to correspond? review
}
set island_allowed [Allowed $child $fullpathpattern]
dict set paths $path [list islandok [Allowed $child $fullpathpattern] fullpathpattern $fullpathpattern dir $dir tok $tok tailpattern $tailpattern] ;#store bool against each path for whether island allows
#if { ![Allowed $child $path] } {
# #return -code error "Access to $path denied."
#}
}
#return [uplevel [list safe::AliasGlob $child {*}$args]]
#As at 2024, The safe::AliasGlob version of glob requires the -directory option.
#ie it doesn't support things like: glob {$p(:208:)/*}
#This would instead have to be glob -directory {$p(:208:)} *
#It also doesn't support shortened versions such as -dir instead of -directory
set entries [list]
dict for {path pathinfo} $paths {
puts "------------->path: $path"
puts " >pathinfo: $pathinfo"
puts " >flags: $flags"
puts " >args: $args"
set islandok [dict get $pathinfo islandok]
if {$islandok} {
puts stderr "[a+ web-red]XXX ->[list $child invokehidden glob {*}$flags [dict get $pathinfo fullpathpattern]][a]"
#return spuds
#lappend entries [uplevel 1 [list $child invokehidden glob {*}$flags [dict get $pathinfo fullpathpattern]]]
lappend entries [uplevel 1 [list ::glob {*}$flags [dict get $pathinfo fullpathpattern]]]
} else {
#only pass paths with tokens to safe - or we will get in a loop
set tok [dict get $pathinfo tok]
if {$tok ne ""} {
puts stderr "============ tok:$tok tailpattern:[dict get $pathinfo tailpattern]"
#dir is detokenised - but we should use the token for safe::AliasGlob
lappend entries {*}[uplevel [list safe::AliasGlob $child {*}$flags -directory $tok [dict get $pathinfo tailpattern]]]
} else {
puts stderr "****============ no-token tailpattern:[dict get $pathinfo tailpattern]"
lappend entries [uplevel 1 [list $child invokehidden glob {*}$flags [dict get $pathinfo fullpathpattern]]]
}
}
}
#dedup?
if {$islandok} {
puts stderr "[a+ web-green]$entries[a]"
}
return $entries
#return [uplevel [list $child invokehidden glob {*}$args]]
}
proc Init { child } {
#*** !doctools
#[call [fun Init] [arg child] ]
#[para] Initialise child interpreter so that it will be able to perform some
#[para] file operations, but only within some islands of the filesystem.
#[para] Arguments:
# [list_begin arguments]
# [arg_def string child] Identifier of the child interpreter
# [list_end]
$child alias file ::punk::island::system::File $child
$child alias glob ::punk::island::system::Glob $child
# Allow to open some of the files, and since we did, arrange to be able to
# fconfigure them once opened.
$child alias open ::punk::island::system::Open $child
$child alias fconfigure ::punk::island::system::Expose $child fconfigure
$child alias pwd ::punk::island::system::Expose $child pwd
$child alias cd ::punk::island::system::Expose $child cd ;# warning: cd affects whole process - generally not something desirable in a safe interp
}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::island::system ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::island [namespace eval punk::island {
variable pkg punk::island
variable version
set version 999999.0a1.0
}]
return
#*** !doctools
#[manpage_end]

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

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

730
src/modules/punk/lib-999999.0a1.0.tm

@ -96,6 +96,57 @@ namespace eval punk::lib::class {
} }
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::lib::ensemble {
#wiki.tcl-lang.org/page/ensemble+extend
# extend an ensemble-like routine with the routines in some namespace
proc extend {routine extension} {
if {![string match ::* $routine]} {
set resolved [uplevel 1 [list ::namespace which $routine]]
if {$resolved eq {}} {
error [list {no such routine} $routine]
}
set routine $resolved
}
set routinens [namespace qualifiers $routine]
if {$routinens eq {::}} {
set routinens {}
}
set routinetail [namespace tail $routine]
if {![string match ::* $extension]} {
set extension [uplevel 1 [
list [namespace which namespace] current]]::$extension
}
if {![namespace exists $extension]} {
error [list {no such namespace} $extension]
}
set extension [namespace eval $extension [
list [namespace which namespace] current]]
namespace eval $extension [
list [namespace which namespace] export *]
while 1 {
set renamed ${routinens}::${routinetail}_[info cmdcount]
if {[namespace which $renamed] eq {}} break
}
rename $routine $renamed
namespace eval $extension [
list namespace ensemble create -command $routine -unknown [
list apply {{renamed ensemble routine args} {
list $renamed $routine
}} $renamed
]
]
return $routine
}
}
namespace eval punk::lib::compat { namespace eval punk::lib::compat {
#*** !doctools #*** !doctools
#[subsection {Namespace punk::lib::compat}] #[subsection {Namespace punk::lib::compat}]
@ -228,6 +279,46 @@ namespace eval punk::lib::compat {
return $result return $result
} }
#tcl8.7/9 compatibility for 8.6
if {[info commands ::tcl::string::insert] eq ""} {
#https://wiki.tcl-lang.org/page/string+insert
# Pure Tcl implementation of [string insert] command.
proc ::tcl::string::insert {string index insertString} {
# Convert end-relative and TIP 176 indexes to simple integers.
if {[regexp -expanded {
^(end(?![\t\n\v\f\r ]) # "end" is never followed by whitespace
|[\t\n\v\f\r ]*[+-]?\d+) # m, with optional leading whitespace
(?:([+-]) # op, omitted when index is "end"
([+-]?\d+))? # n, omitted when index is "end"
[\t\n\v\f\r ]*$ # optional whitespace (unless "end")
} $index _ m op n]} {
# Convert first index to an integer.
switch $m {
end {set index [string length $string]}
default {scan $m %d index}
}
# Add or subtract second index, if provided.
switch $op {
+ {set index [expr {$index + $n}]}
- {set index [expr {$index - $n}]}
}
} elseif {![string is integer -strict $index]} {
# Reject invalid indexes.
return -code error "bad index \"$index\": must be\
integer?\[+-\]integer? or end?\[+-\]integer?"
}
# Concatenate the pre-insert, insertion, and post-insert strings.
string cat [string range $string 0 [expr {$index - 1}]] $insertString\
[string range $string $index end]
}
# Bind [string insert] to [::tcl::string::insert].
namespace ensemble configure string -map [dict replace\
[namespace ensemble configure string -map]\
insert ::tcl::string::insert]
}
#*** !doctools #*** !doctools
#[list_end] [comment {--- end definitions namespace punk::lib::compat ---}] #[list_end] [comment {--- end definitions namespace punk::lib::compat ---}]
} }
@ -244,6 +335,28 @@ namespace eval punk::lib {
#[para] Core API functions for punk::lib #[para] Core API functions for punk::lib
#[list_begin definitions] #[list_begin definitions]
proc range {from to args} {
if {[info commands lseq] ne ""} {
#tcl 8.7+ lseq significantly faster for larger ranges
return [lseq $from $to]
}
set count [expr {($to -$from) + 1}]
incr from -1
return [lmap v [lrepeat $count 0] {incr from}]
}
proc is_list_all_in_list {small large} {
package require struct::list
package require struct::set
set small_in_large [lsort [struct::set intersect [lsort -unique $small] $large ]]
return [struct::list equal [lsort $small] $small_in_large]
}
proc is_list_all_ni_list {a b} {
package require struct::set
set i [struct::set intersect $a $b]
return [expr {[llength $i] == 0}]
}
#The closure-like behaviour is *very* slow especially when called from a context such as the global namespace with lots of vars and large arrays such as ::env #The closure-like behaviour is *very* slow especially when called from a context such as the global namespace with lots of vars and large arrays such as ::env
proc lmapflat_closure {varnames list script} { proc lmapflat_closure {varnames list script} {
set result [list] set result [list]
@ -548,16 +661,14 @@ namespace eval punk::lib {
if {[llength $argopts]%2 !=0} { if {[llength $argopts]%2 !=0} {
error "[namespace current]::hex2dec arguments prior to list_largeHex must be option/value pairs - received '$argopts'" error "[namespace current]::hex2dec arguments prior to list_largeHex must be option/value pairs - received '$argopts'"
} }
set defaults [dict create\ set opts [dict create\
-validate 1\ -validate 1\
-empty_as_hex "INVALID set -empty_as_hex to a hex string e.g FF if empty values should be replaced"\ -empty_as_hex "INVALID set -empty_as_hex to a hex string e.g FF if empty values should be replaced"\
] ]
set known_opts [dict keys $defaults] set known_opts [dict keys $opts]
set fullopts [dict create] foreach {k v} $argopts {
dict for {k v} $argopts { dict set opts [tcl::prefix match -message "options for hex2dec. Unexpected option" $known_opts $k] $v
dict set fullopts [tcl::prefix match -message "options for hex2dec. Unexpected option" $known_opts $k] $v
} }
set opts [dict merge $defaults $fullopts]
# -- --- --- --- # -- --- --- ---
set opt_validate [dict get $opts -validate] set opt_validate [dict get $opts -validate]
set opt_empty [dict get $opts -empty_as_hex] set opt_empty [dict get $opts -empty_as_hex]
@ -606,7 +717,7 @@ namespace eval punk::lib {
] ]
set known_opts [dict keys $defaults] set known_opts [dict keys $defaults]
set fullopts [dict create] set fullopts [dict create]
dict for {k v} $argopts { foreach {k v} $argopts {
dict set fullopts [tcl::prefix match -message "options for [namespace current]::dec2hex. Unexpected option" $known_opts $k] $v dict set fullopts [tcl::prefix match -message "options for [namespace current]::dec2hex. Unexpected option" $known_opts $k] $v
} }
set opts [dict merge $defaults $fullopts] set opts [dict merge $defaults $fullopts]
@ -1050,10 +1161,13 @@ namespace eval punk::lib {
return [join $lines $joinchar] return [join $lines $joinchar]
} }
proc list_as_lines2 {args} { proc list_as_lines2 {args} {
#eat or own dogfood version - shows the implementation is simpler - but unfortunately not suitable for a simple function like this which should be as fast as possible #eat or own dogfood version - shows the implementation is simpler - but unfortunately not suitable for a simple function like this which should be as fast as possible?
lassign [dict values [punk::lib::opts_values -minvalues 1 -maxvalues 1 { lassign [dict values [punk::args::get_dict {
-joinchar -default \n -joinchar -default \n
*values -min 1 -max 1
} $args]] opts values } $args]] opts values
puts "opts:$opts"
puts "values:$values"
return [join [dict get $values 0] [dict get $opts -joinchar]] return [join [dict get $values 0] [dict get $opts -joinchar]]
} }
@ -1089,7 +1203,8 @@ namespace eval punk::lib {
#-anyopts 1 avoids having to know what to say if odd numbers of options passed etc #-anyopts 1 avoids having to know what to say if odd numbers of options passed etc
#we don't have to decide what is an opt vs a value #we don't have to decide what is an opt vs a value
#even if the caller provides the argument -block without a value the next function's validation will report a reasonable error because there is now nothing in $values (consumed by -block) #even if the caller provides the argument -block without a value the next function's validation will report a reasonable error because there is now nothing in $values (consumed by -block)
lassign [dict values [punk::lib::opts_values -anyopts 1 { lassign [dict values [punk::args::get_dict {
*opts -any 1
-block -default {} -block -default {}
} $args]] opts valuedict } $args]] opts valuedict
tailcall linelist {*}$opts {*}[dict values $valuedict] tailcall linelist {*}$opts {*}[dict values $valuedict]
@ -1107,22 +1222,23 @@ namespace eval punk::lib {
set text [string map [list \r\n \n] $text] ;#review - option? set text [string map [list \r\n \n] $text] ;#review - option?
set arglist [lrange $args 0 end-1] set arglist [lrange $args 0 end-1]
set defaults [dict create\ set opts [dict create\
-block {trimhead1 trimtail1}\ -block {trimhead1 trimtail1}\
-line {}\ -line {}\
-commandprefix ""\ -commandprefix ""\
-ansiresets auto\ -ansiresets auto\
-ansireplays 0\ -ansireplays 0\
] ]
dict for {o v} $arglist { foreach {o v} $arglist {
switch -- $o { switch -- $o {
-block - -line - -commandprefix - -ansiresets - -ansireplays {} -block - -line - -commandprefix - -ansiresets - -ansireplays {
dict set opts $o $v
}
default { default {
error "linelist: Unrecognized option '$o' usage:$usage" error "linelist: Unrecognized option '$o' usage:$usage"
} }
} }
} }
set opts [dict merge $defaults $arglist]
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_block [dict get $opts -block] set opt_block [dict get $opts -block]
if {[llength $opt_block]} { if {[llength $opt_block]} {
@ -1157,9 +1273,20 @@ namespace eval punk::lib {
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_line [dict get $opts -line] set opt_line [dict get $opts -line]
set tl_left 0
set tl_right 0
set tl_both 0
foreach lo $opt_line { foreach lo $opt_line {
switch -- $lo { switch -- $lo {
trimline - trimleft - trimright {} trimline {
set tl_both 1
}
trimleft {
set tl_left 1
}
trimright {
set tl_right 1
}
default { default {
set known_lineopts [list trimline trimleft trimright] set known_lineopts [list trimline trimleft trimright]
error "linelist: unknown -line option value: $lo known values: $known_lineopts" error "linelist: unknown -line option value: $lo known values: $known_lineopts"
@ -1167,8 +1294,9 @@ namespace eval punk::lib {
} }
} }
#normalize trimleft trimright combo #normalize trimleft trimright combo
if {"trimleft" in $opt_line && "trimright" in $opt_line} { if {$tl_left && $tl_right} {
set opt_line [list "trimline"] set opt_line [list "trimline"]
set tl_both 1
} }
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_commandprefix [dict get $opts -commandprefix] set opt_commandprefix [dict get $opts -commandprefix]
@ -1192,13 +1320,17 @@ namespace eval punk::lib {
set linelist $nlsplit set linelist $nlsplit
#lappend linelist {*}$nlsplit #lappend linelist {*}$nlsplit
} else { } else {
foreach ln $nlsplit {
#already normalized trimleft+trimright to trimline #already normalized trimleft+trimright to trimline
if {"trimline" in $opt_line} { if {$tl_both} {
foreach ln $nlsplit {
lappend linelist [string trim $ln] lappend linelist [string trim $ln]
} elseif {"trimleft" in $opt_line} { }
} elseif {$tl_left} {
foreach ln $nlsplit {
lappend linelist [string trimleft $ln] lappend linelist [string trimleft $ln]
} elseif {"trimright" in $opt_line} { }
} elseif {$tl_right} {
foreach ln $nlsplit {
lappend linelist [string trimright $ln] lappend linelist [string trimright $ln]
} }
} }
@ -1397,544 +1529,6 @@ namespace eval punk::lib {
return $linelist return $linelist
} }
#maintenance - take over from punk::args - or put back in punk::args once fixed to support pipeline argument order
#possible improvements - after the 1st call, replace the callsite in the calling proc with an inline script to process and validate the arguments as specified in optionspecs
#This would require a tcl parser .. and probably lots of other work
#It would also probably only be practical if there are no dynamic entries in the optionspecs. An option for opts_values to indicate the caller wants this optimisation would probably be best.
#generally we expect values to contain leading dashes only if -- specified. Otherwise no reliable way determine difference between bad flags and values
#If no eopts (--) specified we stop looking for opts at the first nondash encountered in a position we'd expect a dash - so without eopt, values could contain dashes - but not in first position after flags.
#only supports -flag val pairs, not solo options
#If an option is supplied multiple times - only the last value is used.
proc opts_values {args} {
#*** !doctools
#[call [fun opts_values] [opt {option value...}] [arg optionspecs] [arg rawargs] ]
#[para]Parse rawargs as a sequence of zero or more option-value pairs followed by zero or more values
#[para]Returns a dict of the form: opts <options_dict> values <values_dict>
#[para]ARGUMENTS:
#[list_begin arguments]
#[arg_def multiline-string optionspecs]
#[para] This a block of text with records delimited by newlines (lf or crlf) - but with multiline values allowed if properly quoted/braced
#[para]'info complete' is used to determine if a record spans multiple lines due to multiline values
#[para]Each optionspec line must be of the form:
#[para]-optionname -key val -key2 val2...
#[para]where the valid keys for each option specification are: -default -type -range -choices -optional
#[arg_def list rawargs]
#[para] This is a list of the arguments to parse. Usually it will be the \$args value from the containing proc
#[list_end]
#[para]
#consider line-processing example below for we need info complete to determine record boundaries
#punk::lib::opt_values {
# -opt1 -default {}
# -opt2 -default {
# etc
# } -multiple 1
#} $args
#-- cannot be used to allow opts_values itself to accept rawargs as separate values - so it doesn't serve much purpose other than as an indicator of intention
#For consistency we support it anyway.
#we have to be careful with end-of-options flag --
#It may legitimately be the only value in the rawargs list (which is a bit odd - but possible) or it may occur immediately before optionspecs and rawargs
#if there is more than one entry in rawargs - we won't find it anyway - so that's ok
set eopts_posn [lsearch $args --]
if {$eopts_posn == ([llength $args]-1)} {
#sole argument in rawargs - not the one we're looking for
set eopts_posn -1
}
if {$eopts_posn >= 0} {
set ov_opts [lrange $args 0 $eopts_posn-1]
set ov_vals [lrange $args $eopts_posn+1 end]
} else {
set ov_opts [lrange $args 0 end-2]
set ov_vals [lrange $args end-1 end]
}
if {[llength $ov_vals] < 2 || [llength $ov_opts] %2 != 0} {
error "opts_args wrong # args: should be opts_values ?opt val?... optionspecs rawargs_as_list
}
set optionspecs [lindex $ov_vals 0]
set optionspecs [string map [list \r\n \n] $optionspecs]
set rawargs [lindex $ov_vals 1]
set optspec_defaults [dict create\
-optional 1\
-allow_ansi 1\
-validate_without_ansi 0\
-strip_ansi 0\
-nocase 0\
]
set required_opts [list]
set required_vals [list]
set arg_info [dict create]
set defaults_dict_opts [dict create]
set defaults_dict_values [dict create]
#first process dashed and non-dashed argspecs without regard to whether non-dashed are at the beginning or end
set value_names [list]
set records [list]
set linebuild ""
foreach rawline [split $optionspecs \n] {
set recordsofar [string cat $linebuild $rawline]
if {![info complete $recordsofar]} {
append linebuild [string trimleft $rawline] \n
} else {
lappend records [string cat $linebuild $rawline]
set linebuild ""
}
}
foreach ln $records {
set trimln [string trim $ln]
switch -- [string index $trimln 0] {
"" - # {continue}
}
set argname [lindex $trimln 0]
set argspecs [lrange $trimln 1 end]
if {[llength $argspecs] %2 != 0} {
error "punk::lib::opts_values - bad optionspecs line for argument '$argname' Remaining items on line must be in paired option-value format - received '$argspecs'"
}
if {[string match -* $argname]} {
dict set argspecs -ARGTYPE option
set is_opt 1
} else {
dict set argspecs -ARGTYPE value
lappend value_names $argname
set is_opt 0
}
dict for {spec specval} $argspecs {
switch -- $spec {
-default - -type - -range - -choices - -nocase - -optional - -multiple - -validate_without_ansi - -allow_ansi - -strip_ansi - -ARGTYPE {}
default {
set known_argspecs [list -default -type -range -choices -nocase -optional -multiple -validate_without_ansi -allow_ansi -strip_ansi -ARGTYPE]
error "punk::lib::opts_values - unrecognised key '$spec' in specifications for argument '$argname' Known option specification keys: $known_argspecs"
}
}
}
set argspecs [dict merge $optspec_defaults $argspecs]
dict set arg_info $argname $argspecs
if {![dict get $argspecs -optional]} {
if {$is_opt} {
lappend required_opts $argname
} else {
lappend required_vals $argname
}
}
if {[dict exists $arg_info $argname -default]} {
if {$is_opt} {
dict set defaults_dict_opts $argname [dict get $arg_info $argname -default]
} else {
dict set defaults_dict_values $argname [dict get $arg_info $argname -default]
}
}
}
#puts "--> [info frame -2] <--"
set cmdinfo [dict get [info frame -2] cmd]
#we can't treat cmdinfo as a list - it may be something like {command {*}$args} in which case lindex $cmdinfo 0 won't work
#hopefully first word is a plain proc name if this function was called in the normal manner - directly from a proc
#we will break at first space and assume the lhs of that will give enough info to be reasonable - (alternatively we could use entire cmdinfo - but it might be big and ugly)
set caller [regexp -inline {\S+} $cmdinfo]
#if called from commandline or some other contexts such as outside of a proc in a namespace - caller may just be "namespace"
if {$caller eq "namespace"} {
set caller "punk::lib::opts_values called from namespace"
}
# ------------------------------
if {$caller ne "punk::lib::opts_values"} {
#1) check our caller's call to us - recursive version - perhaps more elegant to eat our own dogfood - but maybe too much overhead for a script-based args processor which is already quite heavy :/
#lassign [punk::lib::opts_values "-anyopts -default 0 -type integer\n -minvalues -default 0 -type integer\n -maxvalues -default -1 -type integer" $args] _o ownopts _v ownvalues
#if {[dict size $ownvalues] != 2} {
# error "punk::lib::opts_values expected: a multiline text block of option-specifications, a list of args and at most three option pairs -minvalues <int>, -maxvalues <int>, -anyopts true|false - got extra arguments: '$ownvalues'"
#}
#set opt_minvalues [dict get $ownopts -minvalues]
#set opt_maxvalues [dict get $ownopts -maxvalues]
#set opt_anyopts [dict get $ownopts -anyopts]
#2) Quick and dirty - but we don't need much validation
set defaults [dict create\
-minvalues 0\
-maxvalues -1\
-anyopts 0\
]
dict for {k v} $ov_opts {
if {$k ni {-minvalues -maxvalues -anyopts}} {
error "punk::lib::opts_values unrecognised option $k. Known values [dict keys $defaults]"
}
if {![string is integer -strict $v]} {
error "punk::lib::opts_values argument $k must be of type integer"
}
}
set ov_opts [dict merge $defaults $ov_opts]
set opt_minvalues [dict get $ov_opts -minvalues]
set opt_maxvalues [dict get $ov_opts -maxvalues]
set opt_anyopts [dict get $ov_opts -anyopts]
} else {
#don't recurse ie don't check our own args if we called ourself
set opt_minvalues 2
set opt_maxvalues 2
set opt_anyopts 0
}
# ------------------------------
if {[set eopts [lsearch $rawargs "--"]] >= 0} {
set values [lrange $rawargs $eopts+1 end]
set arglist [lrange $rawargs 0 $eopts-1]
} else {
if {[lsearch $rawargs -*] >= 0} {
#to support option values with leading dash e.g -offset -1 , we can't just take the last flagindex
set i 0
foreach {k v} $rawargs {
if {![string match -* $k]} {
break
}
if {$i+1 >= [llength $rawargs]} {
#no value for last flag
error "bad options for $caller. No value supplied for last option $k"
}
incr i 2
}
set arglist [lrange $rawargs 0 $i-1]
set values [lrange $rawargs $i end]
} else {
set arglist [list]
set values $rawargs ;#no -flags detected
}
}
#confirm any valnames before last don't have -multiple key
foreach valname [lrange $value_names 0 end-1] {
if {[dict exists $arg_info $valname -multiple ]} {
error "bad key -multiple on argument spec for '$valname'. Only the last value argument specification can be marked -multiple"
}
}
set values_dict [dict create]
set validx 0
set in_multiple ""
foreach valname $value_names val $values {
if {$validx+1 > [llength $values]} {
break
}
if {$valname ne ""} {
if {[dict exists $arg_info $valname -multiple] && [dict get $arg_info $valname -multiple]} {
dict lappend values_dict $valname $val
set in_multiple $valname
} else {
dict set values_dict $valname $val
}
} else {
if {$in_multiple ne ""} {
dict lappend values_dict $in_multiple $val
} else {
dict set values_dict $validx $val
}
}
incr validx
}
if {$opt_maxvalues == -1} {
#only check min
if {[llength $values] < $opt_minvalues} {
error "bad number of trailing values for $caller. Got [llength $values] values. Expected at least $opt_minvalues"
}
} else {
if {[llength $values] < $opt_minvalues || [llength $values] > $opt_maxvalues} {
if {$opt_minvalues == $opt_maxvalues} {
error "bad number of trailing values for $caller. Got [llength $values] values. Expected exactly $opt_minvalues"
} else {
error "bad number of trailing values for $caller. Got [llength $values] values. Expected between $opt_minvalues and $opt_maxvalues inclusive"
}
}
}
#opts explicitly marked as -optional 0 must be present - regardless of -anyopts (which allows us to ignore additional opts to pass on to next call)
#however - if -anyopts is true, there is a risk we will treat a shortened option name as matching our default - when it was intended for the next call
#We will always require exact matches for all required opts to avoid this risk, even though an ultimately-called function may not require the full-length option-name REVIEW
#The aim is to allow a wrapper function to specify a default value for an option (and/or other changes/restrictions to a particular option or two) - without having to re-specify all the options for the underlying function.
#without full respecification in the wrapper - we can't know that a supplied prefix is unambiguous at the next level
#For this reason we need to pass on full-length opts for any defined options in the wrapper even if anyopts is true
set argnamespresent [dict keys $arglist]
foreach r $required_opts {
if {$r ni $argspresent} {
error "Required option missing for $caller. '$r' is marked with -optional false - so must be present in its full-length form"
}
}
set valuenamespresent [dict keys $values_dict]
foreach r $required_vals {
if {$r ni $valuenamespresent} {
error "Required value missing for $caller. '$r' is marked with -optional false - so must be present"
}
}
if {!$opt_anyopts} {
set checked_args [dict create]
for {set i 0} {$i < [llength $arglist]} {incr i} {
#allow this to error out with message indicating expected flags
set val [lindex $arglist $i+1]
set fullopt [tcl::prefix match -message "options for $caller. Unexpected option" [dict keys $arg_info] [lindex $arglist $i]]
if {[dict exists $arg_info $fullopt -multiple] && [dict get $arg_info $fullopt -multiple]} {
dict lappend checked_args $fullopt $val
} else {
dict set checked_args $fullopt $val
}
incr i ;#skip val
}
} else {
#still need to use tcl::prefix match to normalize - but don't raise an error
set checked_args [dict create]
dict for {k v} $arglist {
if {![catch {tcl::prefix::match [dict keys $arg_info] $k} fullopt]} {
if {[dict exists $arg_info $fullopt -multiple] && [dict get $arg_info $fullopt -multiple]} {
dict lappend checked_args $fullopt $v
} else {
dict set checked_args $fullopt $v
}
} else {
#opt was unspecified
dict set checked_args $k $v
}
}
}
set opts [dict merge $defaults_dict_opts $checked_args]
#assertion - checked_args keys are full-length option names if -anyopts was false or if the supplied option as a shortname matched one of our defined options
set values [dict merge $defaults_dict_values $values_dict]
#todo - allow defaults outside of choices/ranges
#check types,ranges,choices
set opts_and_values [concat $opts $values]
set combined_defaults [concat $defaults_dict_values $defaults_dict_opts] ;#can be no key collisions - we don't allow a value key beginning with dash - opt names must begin with dash
dict for {o v} $opts_and_values {
if {[dict exists $arg_info $o -multiple] && [dict get $arg_info $o -multiple]} {
set vlist $v
} else {
set vlist [list $v]
}
if {[dict exists $arg_info $o -validate_without_ansi] && [dict get $arg_info $o -validate_without_ansi]} {
set validate_without_ansi 1
package require punk::ansi
} else {
set validate_without_ansi 0
}
if {[dict exists $arg_info $o -allow_ansi] && [dict get $arg_info $o -allow_ansi]} {
set allow_ansi 1
} else {
#ironically - we need punk::ansi to detect and disallow - but we don't need it if ansi is allowed
package require punk::ansi
set allow_ansi 0
}
if {!$allow_ansi} {
#detect should work fine directly on whole list
if {[punk::ansi::ta::detect $vlist]} {
error "Option $o for $caller contains ansi - but -allow_ansi is false. Received: [ansistring VIEW $vlist]"
}
#foreach e $vlist {
# if {[punk::ansi::ta::detect $e]} {
# error "Option $o for $caller contains ansi - but -allow_ansi is false. Received: '$e'"
# }
#}
}
set vlist_check [list]
foreach e $vlist {
#could probably stripansi entire list safely in one go? - review
if {$validate_without_ansi} {
lappend vlist_check [punk::ansi::stripansi $e]
} else {
lappend vlist_check $e
}
}
set is_default 0
foreach e $vlist e_check $vlist_check {
if {[dict exists $combined_defaults $o] && ($e_check eq [dict get $combined_defaults $o])} {
incr is_default
}
}
if {$is_default eq [llength $vlist]} {
set is_default true
}
#we want defaults to pass through - even if they don't pass the checks that would be required for a specified value
#If the caller manually specified a value that happens to match the default - we don't detect that as any different from an unspecified value - Review.
if {!$is_default} {
if {[dict exists $arg_info $o -type]} {
set type [dict get $arg_info $o -type]
set ltype [string tolower $type]
switch -- $type {
int -
integer -
double {
switch -- $ltype {
int -
integer {
foreach e $vlist e_check $vlist_check {
if {![string is integer -strict $e_check]} {
error "Option $o for $caller requires type 'integer'. Received: '$e'"
}
}
}
double {
foreach e $vlist e_check $vlist_check {
if {![string is double -strict $e_check]} {
error "Option $o for $caller requires type 'double'. Received: '$e'"
}
}
}
}
#todo - small-value double comparisons with error-margin? review
if {[dict exists $arg_info $o -range]} {
lassign [dict get $arg_info $o -range] low high
foreach e $vlist e_check $vlist_check {
if {$e_check < $low || $e_check > $high} {
error "Option $o for $caller must be between $low and $high. Received: '$e'"
}
}
}
}
bool -
boolean {
foreach e $vlist e_check $vlist_check {
if {![string is boolean -strict $e_check]} {
error "Option $o for $caller requires type 'boolean'. Received: '$e'"
}
}
}
alnum -
alpha -
ascii -
control -
digit -
graph -
lower -
print -
punct -
space -
upper -
wordchar -
xdigit {
foreach e $vlist e_check $vlist_check {
if {![string is [string tolower $type] $e_check]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e'"
}
}
}
file -
directory -
existingfile -
existingdirectory {
foreach e $vlist e_check $vlist_check {
if {!([string length $e_check]>0 && ![regexp {[\"*?<>\;]} $e_check])} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which doesn't look like it could be a file or directory"
}
}
if {[string tolower $type] in {existingfile}} {
foreach e $vlist e_check $vlist_check {
if {![file exists $e_check]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which is not an existing file"
}
}
} elseif {[string tolower $type] in {existingdirectory}} {
foreach e $vlist e_check $vlist_check {
if {![file isdirectory $e_check]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which is not an existing directory"
}
}
}
}
char -
character {
foreach e $vlist e_check $vlist_check {
if {[string length != 1]} {
error "Option $o for $caller requires type '[string tolower $type]'. Received: '$e' which is not a single character"
}
}
}
}
}
if {[dict exists $arg_info $o -choices]} {
set choices [dict get $arg_info $o -choices]
set nocase [dict get $arg_info $o -nocase]
foreach e $vlist e_check $vlist_check {
if {$nocase} {
set casemsg "(case insensitive)"
set choices_test [string tolower $choices]
set v_test [string tolower $e_check]
} else {
set casemsg "(case sensitive)"
set v_test $e_check
set choices_test $choices
}
if {$v_test ni $choices_test} {
error "Option $o for $caller must be one of the listed values $choices $casemsg. Received: '$e'"
}
}
}
}
if {[dict exists $arg_info $o -strip_ansi] && [dict get $arg_info $o -strip_ansi]} {
set stripped_list [list]
foreach e $vlist {
lappend stripped_list [punk::ansi::stripansi $e]
}
if {[dict exists $arg_info $o -multiple] && [dict get $arg_info $o -multiple]} {
if {[dict get $arg_info $o -ARGTYPE] eq "option"} {
dict set opts $o $stripped_list
} else {
dict set values $o $stripped_list
}
} else {
if {[dict get $arg_info $o -ARGTYPE] eq "option"} {
dict set opts $o [lindex $stripped_list 0]
} else {
dict set values [lindex $stripped_list 0]
}
}
}
}
#maintain order of opts $opts values $values as caller may use lassign.
return [dict create opts $opts values $values]
}
#tcl8.7/9 compatibility for 8.6
if {[info commands ::tcl::string::insert] eq ""} {
#https://wiki.tcl-lang.org/page/string+insert
# Pure Tcl implementation of [string insert] command.
proc ::tcl::string::insert {string index insertString} {
# Convert end-relative and TIP 176 indexes to simple integers.
if {[regexp -expanded {
^(end(?![\t\n\v\f\r ]) # "end" is never followed by whitespace
|[\t\n\v\f\r ]*[+-]?\d+) # m, with optional leading whitespace
(?:([+-]) # op, omitted when index is "end"
([+-]?\d+))? # n, omitted when index is "end"
[\t\n\v\f\r ]*$ # optional whitespace (unless "end")
} $index _ m op n]} {
# Convert first index to an integer.
switch $m {
end {set index [string length $string]}
default {scan $m %d index}
}
# Add or subtract second index, if provided.
switch $op {
+ {set index [expr {$index + $n}]}
- {set index [expr {$index - $n}]}
}
} elseif {![string is integer -strict $index]} {
# Reject invalid indexes.
return -code error "bad index \"$index\": must be\
integer?\[+-\]integer? or end?\[+-\]integer?"
}
# Concatenate the pre-insert, insertion, and post-insert strings.
string cat [string range $string 0 [expr {$index - 1}]] $insertString\
[string range $string $index end]
}
# Bind [string insert] to [::tcl::string::insert].
namespace ensemble configure string -map [dict replace\
[namespace ensemble configure string -map]\
insert ::tcl::string::insert]
}
interp alias {} errortime {} punk::lib::errortime interp alias {} errortime {} punk::lib::errortime
proc errortime {script groupsize {iters 2}} { proc errortime {script groupsize {iters 2}} {
@ -2051,6 +1645,26 @@ namespace eval punk::lib::system {
#[para] Internal functions that are not part of the API #[para] Internal functions that are not part of the API
#[list_begin definitions] #[list_begin definitions]
proc has_script_var_bug {} {
set script {set j [list spud] ; list}
append script \n
uplevel #0 $script
set rep1 [tcl::unsupported::representation $::j]
set script ""
set rep2 [tcl::unsupported::representation $::j]
set nostring1 [string match "*no string" $rep1]
set nostring2 [string match "*no string" $rep2]
#we assume it should have no string rep in either case
#Review: check Tcl versions for behaviour/consistency
if {!$nostring2} {
return true
} else {
return false
}
}
proc mostFactorsBelow {n} { proc mostFactorsBelow {n} {
##*** !doctools ##*** !doctools
#[call [fun mostFactorsBelow] [arg n]] #[call [fun mostFactorsBelow] [arg n]]

17
src/modules/punk/mix-0.1.tm

@ -1,9 +1,10 @@
package provide punk::mix [namespace eval punk::mix {
variable version
set version 0.1
}]
namespace eval punk::mix { namespace eval punk::mix {
package require punk::lib
package require punk::mix_custom
proc runcli {args} { proc runcli {args} {
if {![llength $args]} { if {![llength $args]} {
tailcall punk::mix::clicommands help tailcall punk::mix::clicommands help
@ -43,8 +44,6 @@ namespace eval punk::mix::clicommands {
} }
} }
package require punk
package require punk::mix_custom
punk::ensemble::extend punk::mix::clicommands punk::mix_custom punk::ensemble::extend punk::mix::clicommands punk::mix_custom
@ -80,3 +79,9 @@ namespace eval punk::mix::clicommands {
return $helpstr return $helpstr
} }
} }
package provide punk::mix [namespace eval punk::mix {
variable version
set version 0.1
}]

2
src/modules/punk/mix/base-0.1.tm

@ -740,7 +740,7 @@ namespace eval punk::mix::base {
proc cksum_filter_opts {args} { proc cksum_filter_opts {args} {
set ck_opt_names [dict keys [cksum_default_opts]] set ck_opt_names [dict keys [cksum_default_opts]]
set ck_opts [dict create] set ck_opts [dict create]
dict for {k v} $args { foreach {k v} $args {
if {$k in $ck_opt_names} { if {$k in $ck_opt_names} {
dict set ck_opts $k $v dict set ck_opts $k $v
} }

56
src/modules/punk/mix/cli-0.3.tm

@ -24,7 +24,8 @@ package require punkcheck ;#checksum and/or timestamp records
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#review
#deck - rename to dev
namespace eval punk::mix::cli { namespace eval punk::mix::cli {
namespace eval temp_import { namespace eval temp_import {
} }
@ -101,11 +102,6 @@ namespace eval punk::mix::cli {
#interp alias {} ::punk::mix::cli::project.new {} ::punk::mix::cli::new #interp alias {} ::punk::mix::cli::project.new {} ::punk::mix::cli::new
proc make {args} { proc make {args} {
set startdir [pwd] set startdir [pwd]
set project_base "" ;#empty for unknown set project_base "" ;#empty for unknown
@ -209,17 +205,20 @@ namespace eval punk::mix::cli {
} }
proc validate_modulename {modulename args} { proc validate_modulename {modulename args} {
set defaults [list\ set opts [list\
-errorprefix validate_modulename\ -errorprefix validate_modulename\
] ]
if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"} if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"}
set known_opts [dict keys $defaults] foreach {k v} $args {
foreach k [dict keys $args] { switch -- $k {
if {$k ni $known_opts} { -errorprefix {
error "validate_modulename error: unknown option $k. known options: $known_opts" dict set opts $k $v
}
default {
error "validate_modulename error: unknown option '$k'. known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_errorprefix [dict get $opts -errorprefix] set opt_errorprefix [dict get $opts -errorprefix]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
@ -264,17 +263,20 @@ namespace eval punk::mix::cli {
return $projectname return $projectname
} }
proc validate_name_not_empty_or_spaced {name args} { proc validate_name_not_empty_or_spaced {name args} {
set defaults [list\ set opts [list\
-errorprefix projectname\ -errorprefix projectname\
] ]
if {[llength $args] %2 != 0} {error "validate_modulename args must be name-value pairs: received '$args'"} if {[llength $args] %2 != 0} {error "validate_name_not_empty_or_spaced args must be name-value pairs: received '$args'"}
set known_opts [dict keys $defaults] foreach {k v} $args {
foreach k [dict keys $args] { switch -- $k {
if {$k ni $known_opts} { -errorprefix {
error "validate_modulename error: unknown option $k. known options: $known_opts" dict set opts $k $v
}
default {
error "validate_name_not_empty_or_spaced error: unknown option $k. known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
set opt_errorprefix [dict get $opts -errorprefix] set opt_errorprefix [dict get $opts -errorprefix]
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- --- --- ---
@ -759,10 +761,9 @@ namespace eval punk::mix::cli {
} }
proc kettle_call {calltype args} { proc kettle_call {calltype args} {
variable kettle_reset_bodies variable kettle_reset_bodies
if {$calltype ni [list lib shell]} { switch -- $calltype {
error "deck kettle_call 1st argument must be one of: 'lib' for direct use of kettle module or 'shell' to call as separate process" lib {}
} shell {
if {$calltype eq "shell"} {
set kettleappfile [file dirname [info nameofexecutable]]/kettle set kettleappfile [file dirname [info nameofexecutable]]/kettle
set kettlebatfile [file dirname [info nameofexecutable]]/kettle.bat set kettlebatfile [file dirname [info nameofexecutable]]/kettle.bat
@ -778,6 +779,10 @@ namespace eval punk::mix::cli {
} }
} }
} }
default {
error "deck kettle_call 1st argument must be one of: 'lib' for direct use of kettle module or 'shell' to call as separate process"
}
}
set startdir [pwd] set startdir [pwd]
if {![file exists $startdir/build.tcl]} { if {![file exists $startdir/build.tcl]} {
error "deck kettle must be run from a folder containing build.tcl (cwd: [pwd])" error "deck kettle must be run from a folder containing build.tcl (cwd: [pwd])"
@ -901,7 +906,12 @@ namespace eval punk::mix::cli {
variable default_command help variable default_command help
package require punk::mix::base package require punk::mix::base
package require punk::overlay package require punk::overlay
if {[catch {
punk::overlay::custom_from_base [namespace current] ::punk::mix::base punk::overlay::custom_from_base [namespace current] ::punk::mix::base
} errM]} {
puts stderr "punk::mix::cli load error: Failed to overlay punk::mix::base $errM"
error "punk::mix::cli error: $errM"
}
} }

1
src/modules/punk/mix/commandset/doc-999999.0a1.0.tm

@ -33,6 +33,7 @@ namespace eval punk::mix::commandset::doc {
puts "documentation subsystem" puts "documentation subsystem"
puts "commands: doc.build" puts "commands: doc.build"
puts " build documentation from src/doc to src/embedded using the kettle build tool" puts " build documentation from src/doc to src/embedded using the kettle build tool"
puts "commands: doc.status"
} }
proc build {} { proc build {} {

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

@ -354,10 +354,10 @@ namespace eval punk::mix::commandset::module {
#it is nevertheless useful information - and not the only way developer-machine/build-machine paths can leak #it is nevertheless useful information - and not the only way developer-machine/build-machine paths can leak
#for now the user has the option to override any templates and remove %moduletemplate% if it is a security/privacy concern #for now the user has the option to override any templates and remove %moduletemplate% if it is a security/privacy concern
#Don't put litera %x% in the code for the commandset::module itself - to stop them being seen by layout scanner as replacable tokens #Don't put literal %x% in the code for the commandset::module itself - to stop them being seen by layout scanner as replacable tokens
set tagnames [list moduletemplate $moduletemplate project $projectname pkg $modulename year $year license $opt_license version $infile_version] set tagnames [list moduletemplate $moduletemplate project $projectname pkg $modulename year $year license $opt_license version $infile_version]
set strmap [list] set strmap [list]
dict for {tag val} $tagnames { foreach {tag val} $tagnames {
lappend strmap %$tag% $val lappend strmap %$tag% $val
} }
set template_filedata [string map $strmap $template_filedata] set template_filedata [string map $strmap $template_filedata]

18
src/modules/punk/mix/commandset/project-999999.0a1.0.tm

@ -390,7 +390,7 @@ namespace eval punk::mix::commandset::project {
set tagmap [list [lib::template_tag project] $projectname] set tagmap [list [lib::template_tag project] $projectname]
if {[llength $templatefiles]} { if {[llength $templatefiles]} {
puts stdout "Filling template file placeholders with the following tag map:" puts stdout "Filling template file placeholders with the following tag map:"
dict for {placeholder value} $tagmap { foreach {placeholder value} $tagmap {
puts stdout " $placeholder -> $value" puts stdout " $placeholder -> $value"
} }
} }
@ -586,10 +586,14 @@ namespace eval punk::mix::commandset::project {
set col6_dupids [list] set col6_dupids [list]
set col7_pdescs [list] set col7_pdescs [list]
set codes [dict create] set codes [dict create]
set file_idx 0
foreach dbfile $col1_dbfiles { foreach dbfile $col1_dbfiles {
set project_name "" set project_name ""
set project_code "" set project_code ""
set project_desc "" set project_desc ""
set db_error ""
if {[file exists $dbfile]} {
if {[catch {
sqlite3 dbp $dbfile sqlite3 dbp $dbfile
dbp eval {select name,value from config where name like 'project-%';} r { dbp eval {select name,value from config where name like 'project-%';} r {
if {$r(name) eq "project-name"} { if {$r(name) eq "project-name"} {
@ -600,11 +604,21 @@ namespace eval punk::mix::commandset::project {
set project_desc $r(value) set project_desc $r(value)
} }
} }
dbp close } errM]} {
set db_error $errM
}
catch {dbp close}
} else {
set db_error "fossil file $dbfile missing"
}
lappend col4_pnames $project_name lappend col4_pnames $project_name
lappend col5_pcodes $project_code lappend col5_pcodes $project_code
dict lappend codes $project_code $dbfile dict lappend codes $project_code $dbfile
lappend col7_pdescs $project_desc lappend col7_pdescs $project_desc
if {$db_error ne ""} {
lset col1_dbfiles $file_idx "[a+ web-red]$dbfile[a]"
}
incr file_idx
} }
set setid 1 set setid 1

50
src/modules/punk/mix/commandset/scriptwrap-999999.0a1.0.tm

@ -117,18 +117,21 @@ namespace eval punk::mix::commandset::scriptwrap {
} }
set crlf_lf_replacements [list \uFFFF \uFFFE] ;#defaults - if already exist in file - error out with message set crlf_lf_replacements [list \uFFFF \uFFFE] ;#defaults - if already exist in file - error out with message
# -ignore_rems 1 allows testing of alignment state if rems were stripped - todo - lf/crlf-preserving rem strip function # -ignore_rems 1 allows testing of alignment state if rems were stripped - todo - lf/crlf-preserving rem strip function
set defaults [dict create\ set opts [dict create\
-ignore_rems 0\ -ignore_rems 0\
-substitutionmap {}\ -substitutionmap {}\
-crlf_lf_replacements $crlf_lf_replacements\ -crlf_lf_replacements $crlf_lf_replacements\
] ]
set known_opts [dict keys $defaults]
foreach {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
error "checkfile error - unknown option '$k'. Known options: $known_opts" -ignore_rems - -substitutionmap - -crlf_lf_replacements {
dict set opts $k $v
}
default {
error "checkfile error - unknown option '$k'. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- # -- --- --- --- --- --- ---
set opt_ignore_rems [dict get $opts -ignore_rems] set opt_ignore_rems [dict get $opts -ignore_rems]
set opt_substitutionmap [dict get $opts -substitutionmap] set opt_substitutionmap [dict get $opts -substitutionmap]
@ -756,20 +759,25 @@ namespace eval punk::mix::commandset::scriptwrap {
#specific filepath to just wrap one script at the xxx-pre-launch-suprocess site #specific filepath to just wrap one script at the xxx-pre-launch-suprocess site
#scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf #scriptset name to substiture multiple scriptset.xxx files at the default locations - or as specified in scriptset.wrapconf
proc multishell {filepath_or_scriptset args} { proc multishell {filepath_or_scriptset args} {
set defaults [dict create\ set opts [dict create\
-askme 1\ -askme 1\
-outputfolder "\uFFFF"\ -outputfolder "\uFFFF"\
-template "\uFFFF"\ -template "\uFFFF"\
-returnextra 0\ -returnextra 0\
-force 0\ -force 0\
] ]
set known_opts [dict keys $defaults] #set known_opts [dict keys $defaults]
dict for {k v} $args { foreach {k v} $args {
if {$k ni $known_opts} { switch -- $k {
-askme - -outputfolder - -template - -returnextra - -force {
error "punk::mix::commandset::scriptwrap error. Unrecognized option '$k'. Known-options: $known_opts" dict set opts $k $v
}
default {
error "punk::mix::commandset::multishell error. Unrecognized option '$k'. Known-options: [dict keys $opts]"
}
} }
} }
set usage "" set usage ""
append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n append usage "Use directly with the script file to wrap, or supply the name of a scriptset" \n
append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n append usage "The scriptset name will be used to search for yourname.sh|tcl|ps1 or names as you specify in yourname.wrapconfig if it exists" \n
@ -779,7 +787,6 @@ namespace eval punk::mix::commandset::scriptwrap {
puts stderr $usage puts stderr $usage
return false return false
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- ---
set opt_askme [dict get $opts -askme] set opt_askme [dict get $opts -askme]
set opt_template [dict get $opts -template] set opt_template [dict get $opts -template]
@ -1190,11 +1197,22 @@ namespace eval punk::mix::commandset::scriptwrap {
proc get_wrapper_folders {args} { proc get_wrapper_folders {args} {
set opts [dict get [punk::get_leading_opts_and_values { set argd [punk::args::get_dict {
-scriptpath "" #*** !doctools
} $args -maxvalues 0] opts] #[call [fun get_wrapper_folders] [arg args] ]
#[para] Return list of dicts representing wrapper folders. keys: basefolder sourceinfo
#[para] Arguments:
# [list_begin arguments]
# [arg_def string args] name-value pairs -scriptpath <path>
# [list_end]
*proc -name get_wrapper_folders
*opts -anyopts 0
-scriptpath -default ""
*values -minvalues 0 -maxvalues 0
} $args]
# -- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- ---
set opt_scriptpath [dict get $opts -scriptpath] set opt_scriptpath [dict get $argd opts -scriptpath]
# -- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- ---
set wrapper_template_bases [list] set wrapper_template_bases [list]

4
src/modules/punk/mix/templates/modules/template_module-0.0.1.tm

@ -97,7 +97,7 @@ namespace eval %pkg%::class {
# Base namespace # Base namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval %pkg% { namespace eval %pkg% {
namespace export * namespace export {[a-z]*}; # Convention: export all lowercase
#variable xyz #variable xyz
#*** !doctools #*** !doctools
@ -127,7 +127,7 @@ namespace eval %pkg% {
# Secondary API namespace # Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ # ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval %pkg%::lib { namespace eval %pkg%::lib {
namespace export * namespace export {[a-z]*}; # Convention: export all lowercase
namespace path [namespace parent] namespace path [namespace parent]
#*** !doctools #*** !doctools
#[subsection {Namespace %pkg%::lib}] #[subsection {Namespace %pkg%::lib}]

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

@ -591,7 +591,7 @@ namespace eval punk::ns {
#REVIEW - ansi codes can be *very* confusing to the user when trying to handle lists etc.. #REVIEW - ansi codes can be *very* confusing to the user when trying to handle lists etc..
proc get_nslist {args} { proc get_nslist {args} {
set known_types [list children commands exported imported aliases procs ensembles ooclasses ooobjects] set known_types [list children commands exported imported aliases procs ensembles ooclasses ooobjects ooprivateobjects ooprivateclasses native coroutines interps zlibstreams]
set defaults [dict create\ set defaults [dict create\
-match ""\ -match ""\
-types $known_types\ -types $known_types\
@ -605,9 +605,9 @@ namespace eval punk::ns {
set types $requested_types set types $requested_types
if {"all" in $requested_types} { if {"all" in $requested_types} {
foreach t $known_types { foreach known $known_types {
if {$t ni $types} { if {$known ni $types} {
lappend types $t lappend types $known
} }
} }
} }
@ -618,13 +618,20 @@ namespace eval punk::ns {
if {"ooobjects" ni $types} { if {"ooobjects" ni $types} {
lappend types "ooobjects" lappend types "ooobjects"
} }
if {"ooprivateobjects" ni $types} {
lappend types "ooprivateobjects"
}
if {"ooprivateclasses" ni $types} {
lappend types "ooprivateclasses"
}
} }
foreach t $types { foreach t $types {
if {$t in [list "oo" "all"]} { switch -- $t {
continue oo - all -
children - commands - exported - imported - aliases - procs - ensembles - ooclasses - ooobjects - ooprivateobjects - ooprivateclasses - native - coroutines - interps - zlibstreams {}
default {
error "Unrecognised namespace member type: $t known types: $known_types oo all"
} }
if {$t ni $known_types} {
error "Unrecognised namespace member type: $t known types: $known_types"
} }
} }
@ -645,6 +652,12 @@ namespace eval punk::ns {
set ensembles [list] set ensembles [list]
set ooclasses [list] set ooclasses [list]
set ooobjects [list] set ooobjects [list]
set ooprivateobjects [list]
set ooprivateclasses [list]
set native [list]
set interps [list]
set coroutines [list]
set zlibstreams [list]
if {$opt_nsdict eq ""} { if {$opt_nsdict eq ""} {
set nsmatches [get_ns_dicts $fq_glob -allbelow 0] set nsmatches [get_ns_dicts $fq_glob -allbelow 0]
@ -678,27 +691,49 @@ namespace eval punk::ns {
} }
if {"commands" in $types} { if {"commands" in $types} {
set commands [dict get $contents commands] set commands [dict get $contents commands]
if {"exported" in $types} { foreach t $types {
switch -- $t {
exported {
set exported [dict get $contents exported] set exported [dict get $contents exported]
} }
if {"imported" in $types} { imported {
set imported [dict get $contents imported] set imported [dict get $contents imported]
} }
if {"aliases" in $types} { aliases {
set aliases [dict get $contents aliases] set aliases [dict get $contents aliases]
} }
if {"procs" in $types} { procs {
set procs [dict get $contents procs] set procs [dict get $contents procs]
} }
if {"ensembles" in $types} { ensembles {
set ensembles [dict get $contents ensembles] set ensembles [dict get $contents ensembles]
} }
if {"ooclasses" in $types} { ooclasses {
set ooclasses [dict get $contents ooclasses] set ooclasses [dict get $contents ooclasses]
} }
if {"ooobjects" in $types} { ooobjects {
set ooobjects [dict get $contents ooobjects] set ooobjects [dict get $contents ooobjects]
} }
ooprivateobjects {
set ooprivateobjects [dict get $contents ooprivateobjects]
}
ooprivateclasses {
set ooprivateclasses [dict get $contents ooprivateclasses]
}
native {
set native [dict get $contents native]
}
interps {
set interps [dict get $contents interps]
}
coroutines {
set coroutines [dict get $contents coroutines]
}
zlibstreams {
set zlibstreams [dict get $contents zlibstreams]
}
}
}
} }
set numchildren [llength $children] set numchildren [llength $children]
@ -719,11 +754,12 @@ namespace eval punk::ns {
set seencmds [list] set seencmds [list]
set masked [list] ;# set masked [list] ;#
set cmdsets [concat $procs $ensembles $ooclasses $ooobjects $ooprivateobjects $ooprivateclasses $native $interps $coroutines $zlibstreams]
foreach a $aliases { foreach a $aliases {
if {[list c $a] in $elements} { if {[list c $a] in $elements} {
#possibly an ordinary alias - or a renamed alias that is masked by a proc/ensemble/oo #possibly an ordinary alias - or a renamed alias that is masked by a proc/ensemble/oo
#we can detect masking by proc/ensemble/oo - but not by a binary extension loaded after the rename: REVIEW #we can detect masking by proc/ensemble/oo - but not by a binary extension loaded after the rename: REVIEW
if {$a in [concat $procs $ensembles $ooclasses $ooobjects]} { if {$a in $cmdsets} {
#we have an alias that is also a known other command-type #we have an alias that is also a known other command-type
lappend elements [list c $a] ;#add in twice so we can display both. lappend elements [list c $a] ;#add in twice so we can display both.
lappend masked $a lappend masked $a
@ -776,10 +812,17 @@ namespace eval punk::ns {
set col3 [string repeat " " [expr {$cmdwidest1 + 8}]] set col3 [string repeat " " [expr {$cmdwidest1 + 8}]]
set col4 [string repeat " " [expr {$cmdwidest2 + 8}]] set col4 [string repeat " " [expr {$cmdwidest2 + 8}]]
set col5 [string repeat " " [expr {$cmdwidest3 + 8}]] set col5 [string repeat " " [expr {$cmdwidest3 + 8}]]
set a [a+ purple bold] set a [a+ bold purple]
set e [a+ yellow bold] set e [a+ bold yellow]
set o [a+ cyan bold] set p [a+ bold white]
set p [a+ white bold] set c_nat [a+ web-gray] ;#native
set c_int [a+ web-orange] ;#interps
set c_cor [a+ web-hotpink] ;#coroutines
set c_ooo [a+ bold cyan] ;#object
set c_ooc [a+ web-aquamarine] ;#class
set c_ooO [a+ web-dodgerblue] ;#privateObject
set c_ooC [a+ web-lightskyblue] ;#privateClass
set c_zst [a+ web-yellow] ;#zlibstreams
set a1 [a][a+ cyan] set a1 [a][a+ cyan]
foreach ch1 $children1 ch2 $children2 cmd1 $elements1 cmd2 $elements2 cmd3 $elements3 cmd4 $elements4 { foreach ch1 $children1 ch2 $children2 cmd1 $elements1 cmd2 $elements2 cmd3 $elements3 cmd4 $elements4 {
@ -804,6 +847,7 @@ namespace eval punk::ns {
if {$cmd in $exported} { if {$cmd in $exported} {
set c [a+ green bold] set c [a+ green bold]
} }
#keep oooobjects below ooclasses, ooprivateclasses, ooprivateobjects
if {$cmd in $aliases && $cmd in $seencmds} { if {$cmd in $aliases && $cmd in $seencmds} {
#masked commandless-alias #masked commandless-alias
#assertion member of masked - but we use seencmds instead to detect. #assertion member of masked - but we use seencmds instead to detect.
@ -812,14 +856,26 @@ namespace eval punk::ns {
set prefix [overtype::right $prefix "-R"] set prefix [overtype::right $prefix "-R"]
} elseif {$cmd in $procs} { } elseif {$cmd in $procs} {
set prefix "${p}prc " set prefix "${p}prc "
} elseif {$cmd in $native} {
set prefix "${c_nat}nat "
} elseif {$cmd in $ensembles} { } elseif {$cmd in $ensembles} {
set prefix "${e}ens " set prefix "${e}ens "
} elseif {$cmd in $ooclasses} { } elseif {$cmd in $ooclasses} {
set prefix "${o}ooc " set prefix "${c_ooc}ooc "
} elseif {$cmd in $ooprivateobjects} {
set prefix "${c_ooO}ooO "
} elseif {$cmd in $ooprivateclasses} {
set prefix "${c_ooC}ooC "
} elseif {$cmd in $ooobjects} { } elseif {$cmd in $ooobjects} {
set prefix "${o}ooo " set prefix "${c_ooo}ooo "
} elseif {$cmd in $aliases} { } elseif {$cmd in $aliases} {
set prefix "${a}als " set prefix "${a}als "
} elseif {$cmd in $interps} {
set prefix "${c_int}int "
} elseif {$cmd in $coroutines} {
set prefix "${c_cor}cor "
} elseif {$cmd in $zlibstreams} {
set prefix "${c_zst}zst "
} else { } else {
} }
if {$cmd in $imported} { if {$cmd in $imported} {
@ -937,6 +993,14 @@ namespace eval punk::ns {
return [get_ns_dicts $ns_absolute {*}$args] return [get_ns_dicts $ns_absolute {*}$args]
} }
#info cmdtype available in 8.7+
proc cmdtype {cmd} {
if {[info commands ::tcl::info::cmdtype] ne ""} {
tailcall info cmdtype $cmd
}
#we could examine namespaces to determine - but would be duplicating work already done/available in get_ns_dicts which is usually the caller
return na
}
#non-contextual - but impure due to state-retrieval from the passed-in namespace part of the fq_glob #non-contextual - but impure due to state-retrieval from the passed-in namespace part of the fq_glob
#returns a list of dicts even if only one ns matched #returns a list of dicts even if only one ns matched
#glob chars at last segment match contents/children of namespaces #glob chars at last segment match contents/children of namespaces
@ -1042,9 +1106,15 @@ namespace eval punk::ns {
#set allprocs [nseval $location {::info procs}] #set allprocs [nseval $location {::info procs}]
set childtails [lmap v $allchildren {nstail $v}] set childtails [lmap v $allchildren {nstail $v}]
set allaliases [list] set allaliases [list]
set allnative [list]
set allensembles [list] set allensembles [list]
set allinterps [list]
set allcoroutines [list]
set allzlibstreams [list]
set allooobjects [list] set allooobjects [list]
set allooclasses [list] set allooclasses [list]
set allooprivateobjects [list]
set allooprivateclasses [list]
set allimported [list] set allimported [list]
set allundetermined [list] set allundetermined [list]
set interp_aliases [interp aliases ""] set interp_aliases [interp aliases ""]
@ -1070,7 +1140,11 @@ namespace eval punk::ns {
# #which_alias hack from wiki relies on trace and executing the command - which we don't want to do. # #which_alias hack from wiki relies on trace and executing the command - which we don't want to do.
# lappend allaliases $cmd # lappend allaliases $cmd
#} #}
set ctype [cmdtype ${location}::$cmd]
switch -- $ctype {
na {
#tcl 8.6 (info cmdtype unavailable)
#todo - use catch tcl::unsupported::corotype to see if coroutine
if {![catch {namespace ensemble configure ${location}::$cmd} ensemble_info]} { if {![catch {namespace ensemble configure ${location}::$cmd} ensemble_info]} {
lappend allensembles $cmd lappend allensembles $cmd
} elseif {[info object isa object ${location}::$cmd]} { } elseif {[info object isa object ${location}::$cmd]} {
@ -1079,7 +1153,6 @@ namespace eval punk::ns {
lappend allooclasses $cmd lappend allooclasses $cmd
} }
} }
if {[catch { if {[catch {
if {$cmd eq ""} { if {$cmd eq ""} {
#empty command was previously marked as "::" - too confusing - nslist updated to properly display empty string. #empty command was previously marked as "::" - too confusing - nslist updated to properly display empty string.
@ -1099,6 +1172,64 @@ namespace eval punk::ns {
} }
} }
} }
default {
if {$ctype eq "imported"} {
set cmdorigin [namespace origin [nsjoin $location $cmd]]
#even if cmd was already imported to another ns and then reimported from there, namespace origin will show the original source
#ie we don't need to follow a chain of 'imported' results.
set mixedtype i-[info cmdtype $cmdorigin]
} else {
set mixedtype $ctype
}
#assert ctype != imported
#review - we don't have a way to mark as both native and ensemble
switch -- $ctype {
i-native - native {
lappend allnative $cmd
}
i-ensemble - ensemble {
lappend allensembles $cmd
}
i-alias - alias {
#review
lappend allaliases $cmd
}
i-object - object {
if {[info object isa object ${location}::$cmd]} {
lappend allooobjects $cmd
if {[info object isa class ${location}::$cmd]} {
lappend allooclasses $cmd
}
}
}
i-privateObject - privateObject {
lappend allooobjects $cmd
lappend allooprivateobjects $cmd
}
i-privateClass - privateClass {
lappend allooobjects $cmd
lappend allooprivateclasses $cmd
}
i-interp - interp {
lappend allinterps $cmd
}
i-coroutine - coroutine {
lappend allcoroutines $cmd
}
i-zlibStream - zlibStream {
lappend allzlibstreams $cmd
}
default {
#there may be other registered types
#(extensible with Tcl_RegisterCommandTypeName)
lappend allothers $cmd
}
}
}
}
}
if {$glob ne "*"} { if {$glob ne "*"} {
set childtailmatches [lsearch -all -inline $childtails $glob] set childtailmatches [lsearch -all -inline $childtails $glob]
#set fqchildren [lmap v $childtailmatches {lindex ${location}::$v}] ;#lindex without indices is fast equivalent of 'val' or string cat #set fqchildren [lmap v $childtailmatches {lindex ${location}::$v}] ;#lindex without indices is fast equivalent of 'val' or string cat
@ -1107,6 +1238,12 @@ namespace eval punk::ns {
set procs [lsearch -all -inline $allprocs $glob] set procs [lsearch -all -inline $allprocs $glob]
#set aliases [lsearch -all -inline $allaliases $glob] #set aliases [lsearch -all -inline $allaliases $glob]
set ensembles [lsearch -all -inline $allensembles $glob] set ensembles [lsearch -all -inline $allensembles $glob]
set native [lsearch -all -inline $allnative $glob]
set coroutines [lsearch -all -inline $allcoroutines $glob]
set interps [lsearch -all -inline $allinterps $glob]
set zlibstreams [lsearch -all -inline $allzlibstreams $glob]
set ooprivateobjects [lsearch -all -inline $allooprivateobjects $glob]
set ooprivateclasses [lsearch -all -inline $allooprivateclasses $glob]
set ooobjects [lsearch -all -inline $allooobjects $glob] set ooobjects [lsearch -all -inline $allooobjects $glob]
set ooclasses [lsearch -all -inline $allooclasses $glob] set ooclasses [lsearch -all -inline $allooclasses $glob]
set imported [lsearch -all -inline $allimported $glob] set imported [lsearch -all -inline $allimported $glob]
@ -1118,8 +1255,14 @@ namespace eval punk::ns {
set procs $allprocs set procs $allprocs
#set aliases $allaliases #set aliases $allaliases
set ensembles $allensembles set ensembles $allensembles
set native $allnative
set coroutines $allcoroutines
set interps $allinterps
set zlibstreams $allzlibstreams
set ooobjects $allooobjects set ooobjects $allooobjects
set ooclasses $allooclasses set ooclasses $allooclasses
set ooprivateobjects $allooprivateobjects
set ooprivateclasses $allooprivateclasses
set imported $allimported set imported $allimported
set undetermined $allundetermined set undetermined $allundetermined
} }
@ -1150,8 +1293,14 @@ namespace eval punk::ns {
imported $imported\ imported $imported\
aliases $aliases\ aliases $aliases\
ensembles $ensembles\ ensembles $ensembles\
native $native\
coroutines $coroutines\
interps $interps\
zlibstreams $zlibstreams\
ooobjects $ooobjects\ ooobjects $ooobjects\
ooclasses $ooclasses\ ooclasses $ooclasses\
ooprivateobjects $ooprivateobjects\
ooprivateclasses $ooprivateclasses\
namespacexport $exportpatterns\ namespacexport $exportpatterns\
undetermined $undetermined\ undetermined $undetermined\
namespacepath $nspathdict\ namespacepath $nspathdict\
@ -1644,9 +1793,10 @@ namespace eval punk::ns {
set argspecs { set argspecs {
-targetnamespace -default "" -optional 1 -targetnamespace -default "" -optional 1
-prefix -default "" -optional 1 -prefix -default "" -optional 1
*values -min 1 -max 1
sourcepattern -type string -optional 0 sourcepattern -type string -optional 0
} }
lassign [punk::args::opts_values $argspecs $args -minvalues 1 -maxvalues 1] _o opts _v values lassign [dict values [punk::args::get_dict $argspecs $args]] opts values
set sourcepattern [dict get $values sourcepattern] set sourcepattern [dict get $values sourcepattern]
set source_ns [namespace qualifiers $sourcepattern] set source_ns [namespace qualifiers $sourcepattern]

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

@ -156,14 +156,17 @@ namespace eval punk::path {
#[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah) #[para] ie - the driveletter alone in paths such as c:/etc will still be case insensitive. (ie c:/ETC/* will match C:/ETC/blah but not C:/etc/blah)
#[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter. #[para] Explicitly specifying -nocase 0 will require the entire case to match including the driveletter.
set defaults [dict create\ set opts [dict create\
-nocase \uFFFF\ -nocase \uFFFF\
] ]
set known_opts [dict keys $defaults] foreach {k v} $args {
set opts [dict merge $defaults $args] switch -- $k {
dict for {k v} $args { -nocase {
if {$k ni $known_opts} { dict set opts $k $v
error "Unrecognised options $k - known options: $known_opts" }
default {
error "Unrecognised option '$k'. Known-options: [dict keys $opts]"
}
} }
} }
# -- --- --- --- --- --- # -- --- --- --- --- ---

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

File diff suppressed because it is too large Load Diff

255
src/modules/punk/repl/codethread-999999.0a1.0.tm

@ -0,0 +1,255 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'pmix make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.2.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) 2024
#
# @@ Meta Begin
# Application punk::repl::codethread 999999.0a1.0
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin shellspy_module_punk::repl::codethread 0 999999.0a1.0]
#[copyright "2024"]
#[titledesc {Module API}] [comment {-- Name section and table of contents description --}]
#[moddesc {-}] [comment {-- Description at end of page heading --}]
#[require punk::repl::codethread]
#[keywords module]
#[description]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Overview]
#[para] overview of punk::repl::codethread
#[subsection Concepts]
#[para] -
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[subsection dependencies]
#[para] packages used by punk::repl::codethread
#[list_begin itemized]
package require Tcl 8.6-
package require punk::config
#*** !doctools
#[item] [package {Tcl 8.6}]
# #package require frobz
# #*** !doctools
# #[item] [package {frobz}]
#*** !doctools
#[list_end]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section API]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::repl::codethread::class {
#*** !doctools
#[subsection {Namespace punk::repl::codethread::class}]
#[para] class definitions
if {[info commands [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
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::repl::codethread {
namespace export *
variable replthread
variable replthread_cond
variable running 0
variable output_stdout ""
variable output_stderr ""
#variable xyz
#*** !doctools
#[subsection {Namespace punk::repl::codethread}]
#[para] Core API functions for punk::repl::codethread
#[list_begin definitions]
#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"
#}
proc is_running {} {
variable running
return $running
}
proc runscript {script} {
#puts stderr "->runscript"
variable replthread_cond
variable output_stdout ""
variable output_stderr ""
#expecting to be called from a thread::send in parent repl - ie in the toplevel interp so that the sub-interp "code" is available
#if a thread::send is done from the commandline in a codethread - Tcl will
if {"code" ni [interp children] || ![info exists replthread_cond]} {
#in case someone tries calling from codethread directly - don't do anything or change any state
#(direct caller could create an interp named code at the level "" -> "code" -"code" and add a replthread_cond value to avoid this check - but it probably won't do anything useful)
#if called directly - the context will be within the first 'code' interp.
#inappropriate caller could add superfluous entries to shellfilter stack if function errors out
#inappropriate caller could affect tsv vars (if their interp allows that anyway)
puts stderr "runscript is meant to be called from the parent repl thread via a thread::send to the codethread"
return
}
upvar ::punk::config::running running_config
if {[string length [dict get $running_config color_stdout]] && [punk::console::colour]} {
lappend outstack [shellfilter::stack::add stdout ansiwrap -settings [list -colour [dict get $running_config color_stdout]]]
}
lappend outstack [shellfilter::stack::add stdout tee_to_var -settings {-varname ::punk::repl::codethread::output_stdout}]
if {[string length [dict get $running_config color_stderr]] && [punk::console::colour]} {
#lappend errstack [shellfilter::stack::add stderr ansiwrap -settings [list -colour [dict get $running_config color_stderr]]]
lappend errstack [shellfilter::stack::add stderr ansiwrap -settings [list -colour cyan]]
}
lappend errstack [shellfilter::stack::add stderr tee_to_var -settings {-varname ::punk::repl::codethread::output_stderr}]
#an experiment
#set errhandle [shellfilter::stack::item_tophandle stderr]
#interp transfer "" $errhandle code
set scope [interp eval code [list set ::punk::ns::ns_current]]
set status [catch {
interp eval code [list namespace inscope $scope $script]
} result]
flush stdout
flush stderr
#interp transfer code $errhandle ""
#flush $errhandle
set lastoutchar [string index [punk::ansi::stripansi $output_stdout] end]
set lasterrchar [string index [punk::ansi::stripansi $output_stderr] end]
#puts stderr "-->[ansistring VIEW -lf 1 $lastoutchar$lasterrchar]"
set tid [thread::id]
tsv::set codethread_$tid info [list lastoutchar $lastoutchar lasterrchar $lasterrchar]
tsv::set codethread_$tid status $status
tsv::set codethread_$tid result $result
tsv::set codethread_$tid errorcode $::errorCode
foreach s [lreverse $outstack] {
shellfilter::stack::remove stdout $s
}
foreach s [lreverse $errstack] {
shellfilter::stack::remove stderr $s
}
thread::cond notify $replthread_cond
}
#*** !doctools
#[list_end] [comment {--- end definitions namespace punk::repl::codethread ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punk::repl::codethread::lib {
namespace export *
namespace path [namespace parent]
#*** !doctools
#[subsection {Namespace punk::repl::codethread::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::repl::codethread::lib ---}]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[section Internal]
namespace eval punk::repl::codethread::system {
#*** !doctools
#[subsection {Namespace punk::repl::codethread::system}]
#[para] Internal functions that are not part of the API
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::repl::codethread [namespace eval punk::repl::codethread {
variable pkg punk::repl::codethread
variable version
set version 999999.0a1.0
}]
return
#*** !doctools
#[manpage_end]

3
src/modules/punk/repl/codethread-buildversion.txt

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

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

@ -134,9 +134,13 @@ namespace eval punk::repo {
} }
interp alias "" fossil "" punk::repo::fossil_proxy interp alias "" fossil "" punk::repo::fossil_proxy
#safe interps can't call auto_execok
#At least let them load the package even though much of it may be unusable depending on the safe configuration
catch {
if {[auto_execok fossil] ne ""} { if {[auto_execok fossil] ne ""} {
interp alias "" FOSSIL "" {*}[auto_execok fossil] interp alias "" FOSSIL "" {*}[auto_execok fossil]
} }
}
proc askuser {question} { proc askuser {question} {
if {![catch {package require punk::lib}]} { if {![catch {package require punk::lib}]} {
@ -841,7 +845,7 @@ namespace eval punk::repo {
} }
} }
proc fossil_get_repository_folder_for_project {projectname args} { proc fossil_get_repository_folder_for_project {projectname args} {
set defaults [list\ set opts [list\
-parentfolder \uFFFF\ -parentfolder \uFFFF\
-extrachoices \uFFFF\ -extrachoices \uFFFF\
-askpath 0\ -askpath 0\
@ -852,12 +856,16 @@ namespace eval punk::repo {
if {[llength $args] % 2 != 0} { if {[llength $args] % 2 != 0} {
error "fossil_get_repository_folder requires args to be option-value pairs. Received '$args'" error "fossil_get_repository_folder requires args to be option-value pairs. Received '$args'"
} }
dict for {k v} $args { foreach {k v} $args {
if {$k ni [dict keys $defaults]} { switch -- $k {
error "fossil_get_repository_folder unrecognised option $k. Known options: [dict keys $defaults]" -parentfolder - -extrachoices - -askpath - -ansi - -ansi_prompt - -ansi_warning {
dict set opts $k $v
}
default {
error "fossil_get_repository_folder unrecognised option $k. Known options: [dict keys $opts]"
}
} }
} }
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_parentfolder [dict get $opts -parentfolder] set opt_parentfolder [dict get $opts -parentfolder]
if {$opt_parentfolder eq "\uFFFF"} { if {$opt_parentfolder eq "\uFFFF"} {

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

@ -65,7 +65,7 @@
#[para] packages used by punk::sshrun #[para] packages used by punk::sshrun
#[list_begin itemized] #[list_begin itemized]
package require Tcl 8.6 package require Tcl 8.6-
package require cmdline package require cmdline
#*** !doctools #*** !doctools
#[item] [package {Tcl 8.6}] #[item] [package {Tcl 8.6}]

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

@ -45,7 +45,7 @@
#[para] packages used by punk::uc #[para] packages used by punk::uc
#[list_begin itemized] #[list_begin itemized]
package require Tcl 8.6 package require Tcl 8.6-
#*** !doctools #*** !doctools
#[item] [package {Tcl 8.6}] #[item] [package {Tcl 8.6}]

6
src/modules/punk/unixywindows-999999.0a1.0.tm

@ -37,7 +37,7 @@ namespace eval punk::unixywindows {
set result [exec cygpath -m /] ;# -m gives result with forward-slashes - which is ok for windows paths in a Tcl context. set result [exec cygpath -m /] ;# -m gives result with forward-slashes - which is ok for windows paths in a Tcl context.
set cachedunixyroot [punk::objclone $result] set cachedunixyroot [punk::objclone $result]
file pathtype $cachedunixyroot; #this call causes the int-rep to be path file pathtype $cachedunixyroot; #this call causes the int-rep to be path
set ::punk::last_run_display [list] ;#hack - review shouldn't really be necessary.. but because we call winpath from ./ - the repl looks for last_run_display #set ::punk::last_run_display [list] ;#hack - review shouldn't really be necessary.. but because we call winpath from ./ - the repl looks for last_run_display
} errM]} { } errM]} {
} else { } else {
@ -81,7 +81,7 @@ namespace eval punk::unixywindows {
#REVIEW high-coupling #REVIEW high-coupling
proc cdwin {path} { proc cdwin {path} {
set path [towinpath $path] set path [towinpath $path]
if {$::repl::running} { if {[package provide punk::repl::codethread] ne "" && [punk::repl::codethread::is_running]} {
if {[llength [info commands ::punk::console::titleset]]} { if {[llength [info commands ::punk::console::titleset]]} {
::punk::console::titleset $path ::punk::console::titleset $path
} }
@ -90,7 +90,7 @@ namespace eval punk::unixywindows {
} }
proc cdwindir {path} { proc cdwindir {path} {
set path [towinpath $path] set path [towinpath $path]
if {$::repl::running} { if {[package provide punk::repl::codethread] ne "" && [punk::repl::codethread::is_running]} {
if {[llength [info commands ::punk::console::titleset]]} { if {[llength [info commands ::punk::console::titleset]]} {
::punk::console::titleset $path ::punk::console::titleset $path
} }

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

Loading…
Cancel
Save