Browse Source

ansi work - sauce,binarytext

master
Julian Noble 5 days ago
parent
commit
f658fbee63
  1. 3
      src/bootsupport/modules/punk/ansi-0.1.1.tm
  2. 9
      src/bootsupport/modules/punk/lib-0.1.5.tm
  3. 6
      src/bootsupport/modules/punk/path-0.1.0.tm
  4. 3
      src/bootsupport/modules/textblock-0.1.3.tm
  5. 73
      src/modules/overtype-999999.0a1.0.tm
  6. 18
      src/modules/punk-0.1.tm
  7. 420
      src/modules/punk/ansi-999999.0a1.0.tm
  8. 573
      src/modules/punk/ansi/sauce-999999.0a1.0.tm
  9. 3
      src/modules/punk/ansi/sauce-buildversion.txt
  10. 19
      src/modules/punk/lib-999999.0a1.0.tm
  11. 109
      src/modules/punk/nav/fs-999999.0a1.0.tm
  12. 302
      src/modules/punk/nav/ns-999999.0a1.0.tm
  13. 3
      src/modules/punk/nav/ns-buildversion.txt
  14. 145
      src/modules/punk/ns-999999.0a1.0.tm
  15. 34
      src/modules/punk/repl-999999.0a1.0.tm
  16. 15
      src/modules/punk/repl/codethread-999999.0a1.0.tm
  17. 3
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm
  18. 9
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/lib-0.1.5.tm
  19. 6
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm
  20. 3
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/textblock-0.1.3.tm
  21. 3
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm
  22. 9
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/lib-0.1.5.tm
  23. 6
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm
  24. 3
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/textblock-0.1.3.tm
  25. BIN
      src/testansi/AT2DEMO.ANS.ZIP
  26. BIN
      src/testansi/acdu0692.zip
  27. BIN
      src/testansi/ansitoon.zip
  28. 148
      src/vendormodules/dictn-0.1.2.tm
  29. 3
      src/vfs/_vfscommon.vfs/modules/punk/ansi-0.1.1.tm
  30. 9
      src/vfs/_vfscommon.vfs/modules/punk/lib-0.1.5.tm
  31. 6
      src/vfs/_vfscommon.vfs/modules/punk/path-0.1.0.tm
  32. 12
      src/vfs/_vfscommon.vfs/modules/punk/safe-0.1.0.tm
  33. 3
      src/vfs/_vfscommon.vfs/modules/textblock-0.1.3.tm

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

@ -4072,7 +4072,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
# \033 - octal. equivalently \x1b in hex which is more common in documentation
# empty list [a] should do reset - same for [a nonexistant]
# explicit reset at beginning of parameter list for a= (as opposed to a+)
set t [linsert $t[unset t] 0 0]
#set t [linsert $t[unset t] 0 0]
ledit t -1 -1 0
if {![llength $e]} {
set result "\x1b\[[join $t {;}]m"
} else {

9
src/bootsupport/modules/punk/lib-0.1.5.tm

@ -765,7 +765,7 @@ namespace eval punk::lib {
struct::list swap doesn't support 'end' offsets, and only
sometimes appears to support basic expressions, depending on the
expression compared to the list length."
@values -min 1 -max 1
@values -min 3 -max 3
lvar -type string -help\
"name of list variable"
a -type indexexpression
@ -995,11 +995,8 @@ namespace eval punk::lib {
e.g lzip {a b c d e} {1 2 3 4} {x y z}
-> {a 1 x} {b 2 y} {c 3 z} {d 4 {}} {3 {} {}}
"
@values -min 1 -max 1
lvar -type string -help\
"name of list variable"
a -type indexexpression
z -type indexexpression
@values -min 0 -max -1
list -type list -multiple 1 -optional 1
}]
}
proc lzip {args} {

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

@ -294,7 +294,8 @@ namespace eval punk::path {
}
} elseif {[lindex $parts 0] ne ""} {
#relpath a/b/c
set parts [linsert $parts 0 .]
#set parts [linsert $parts 0 .]
ledit parts -1 -1 .
set rootindex 0
#allow backtracking arbitrarily for leading .. entries - simplify where possible
#also need to stop possible conversion to absolute path
@ -1091,7 +1092,8 @@ namespace eval punk::path {
# loc is: ref/sub = sub
while {$reference_len > 0} {
set location [linsert $location 0 ..]
#set location [linsert $location 0 ..]
ledit location -1 -1 ..
incr reference_len -1
}
set location [file join {*}$location]

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

@ -5400,7 +5400,8 @@ tcl::namespace::eval textblock {
l-2 {
if {$lnum == 0} {
if {[lindex $line_chunks 0] eq ""} {
set line_chunks [linsert $line_chunks 2 $pad]
#set line_chunks [linsert $line_chunks 2 $pad]
ledit line_chunks 2 1 $pad
} else {
#set line_chunks [linsert $line_chunks 0 $pad]
ledit line_chunks -1 -1 $pad

73
src/modules/overtype-999999.0a1.0.tm

@ -258,6 +258,7 @@ tcl::namespace::eval overtype {
-wrap -default 0 -type boolean
-info -default 0 -type boolean -help\
"When set to 1, return a dictionary (experimental)"
-binarytext -default "" -type string -choices {"" bios ice}
-console -default {stdin stdout stderr} -type list
@values -min 1 -max 2
@ -329,6 +330,7 @@ tcl::namespace::eval overtype {
-insert_mode 0\
-wrap 0\
-info 0\
-binarytext ""\
-console {stdin stdout stderr}\
]
#expand_right is perhaps consistent with the idea of the page_size being allowed to grow horizontally..
@ -349,7 +351,7 @@ tcl::namespace::eval overtype {
- -expand_right - -appendlines
- -reverse_mode - -crm_mode - -insert_mode
- -cp437
- -info - -console {
- -info - -binarytext - -console {
tcl::dict::set opts $k $v
}
-wrap - -autowrap_mode {
@ -389,6 +391,7 @@ tcl::namespace::eval overtype {
# -- --- --- --- --- ---
set opt_cp437 [tcl::dict::get $opts -cp437]
set opt_info [tcl::dict::get $opts -info]
set opt_binarytext [tcl::dict::get $opts -binarytext]
@ -534,11 +537,44 @@ tcl::namespace::eval overtype {
}
4 {
set inputchunks [list]
foreach ln [split $overblock \n] {
lappend inputchunks [list mixed $ln\n]
}
if {[llength $inputchunks]} {
lset inputchunks end 1 [tcl::string::range [lindex $inputchunks end 1] 0 end-1]
switch -- $opt_binarytext {
"" {
foreach ln [split $overblock \n] {
lappend inputchunks [list mixed $ln\n]
}
if {[llength $inputchunks]} {
lset inputchunks end 1 [tcl::string::range [lindex $inputchunks end 1] 0 end-1]
}
}
bios {
#16 fg, 8 fg + possible blink
set input ""
set ansisplit [list ""]
set charpair 0
foreach {ch at} [split $overblock ""] {
#review - does binarytext only apply to cp437??? we need to know the original encoding
set at [encoding convertto cp437 $at]
if {[catch {punk::ansi::colour::byteAnsi $at} code]} {
puts stderr "renderspace err at charpair: $charpair [punk::ansi::ansistring VIEW ${ch}${at}]"
#append input [punk::ansi::a+ brightred White] \uFFef
set code [punk::ansi::a+ brightred White]
set ch \uFFeF
}
append input $code $ch
lappend ansisplit $code $ch
incr charpair
}
#lappend inputchunks [list mixed $input]
lappend inputchunks [list ansisplit $ansisplit]
}
ice {
#16 fg, 16 bg (no blink)
set input ""
foreach {ch at} [split $overblock ""] {
append input [punk::ansi::colour::byteAnsiIce $at]$ch
}
lappend inputchunks [list mixed $input]
}
}
}
}
@ -2299,8 +2335,12 @@ tcl::namespace::eval overtype {
set i_u -1 ;#underlay may legitimately be empty
set undercols [list]
set u_codestack [list]
#-------------
#u_gx_stack probably isn't really a stack - I don't know if g0 g1 can stack or not - for now we support only g0 anyway
set u_gx_stack [list] ;#separate stack for g0 (g1 g2 g3?) graphics on and off (DEC special graphics)
#
#-------------
#set pt_underchars "" ;#for string_columns length calculation for expand_right 0 truncation
set remainder [list] ;#for returnextra
foreach {pt code} $undermap {
@ -2325,6 +2365,7 @@ tcl::namespace::eval overtype {
#review - 0 and 1?
incr i_u $ptlen
lappend understacks {*}[lrepeat $ptlen $u_codestack]
#we need to store the gx0 state per column - as characters with or without gx0 can be overlayed anywhere
lappend understacks_gx {*}[lrepeat $ptlen $u_gx_stack]
lappend undercols {*}[lrepeat $ptlen $p1]
} else {
@ -2505,24 +2546,6 @@ tcl::namespace::eval overtype {
}
if 0 {
# -----------------
# if we aren't extending understacks & understacks_gx each time we incr idx above the undercols length.. this doesn't really serve a purpose
# Review.
# -----------------
#replay code for last overlay position in input line
# whether or not we get that far - we need to return it for possible replay on next line
if {[llength $understacks]} {
lappend understacks $u_codestack
lappend understacks_gx $u_gx_stack
} else {
#in case overlay onto emptystring as underlay
lappend understacks [list]
lappend understacks_gx [list]
}
# -----------------
}
#trailing codes in effect for underlay
if {[llength $u_codestack]} {
#set replay_codes_underlay [join $u_codestack ""]
@ -2750,7 +2773,7 @@ tcl::namespace::eval overtype {
set o_codestack [list $temp_cursor_saved]
lappend overlay_grapheme_control_list [list other $code]
} else {
#review
#review - gx0 should just be a flag like autowrap_mode and insert_mode?
if {[punk::ansi::codetype::is_gx_open $code]} {
set o_gxstack [list "gx0_on"]
lappend overlay_grapheme_control_list [list gx0 gx0_on] ;#don't store code - will complicate debugging if we spit it out and jump character sets

18
src/modules/punk-0.1.tm

@ -8049,21 +8049,9 @@ namespace eval punk {
# punk::nav::fs
package require punk::nav::fs
interp alias {} ./ {} punk::nav::fs::d/
interp alias {} ../ {} punk::nav::fs::dd/
interp alias {} d/ {} punk::nav::fs::d/
interp alias {} dd/ {} punk::nav::fs::dd/
interp alias {} vwd {} punk::nav::fs::vwd ;#return punk::nav::fs::VIRTUAL_CWD - and report to stderr pwd if different
interp alias {} dirlist {} punk::nav::fs::dirlist
interp alias {} dirfiles {} punk::nav::fs::dirfiles
interp alias {} dirfiles_dict {} punk::nav::fs::dirfiles_dict
interp alias {} ./new {} punk::nav::fs::d/new
interp alias {} d/new {} punk::nav::fs::d/new
interp alias {} ./~ {} punk::nav::fs::d/~
interp alias {} d/~ {} punk::nav::fs::d/~
interp alias "" x/ "" punk::nav::fs::x/
package require punk::nav::ns
variable pshell_path ""
# ----------------------------------------

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

@ -119,17 +119,39 @@ tcl::namespace::eval punk::ansi::class {
#todo - store rendered and allow partial rendering of new data lines?
return $o_rendered
}
method rendertest {{dimensions ""}} {
if {$dimensions eq ""} {
set dimensions $o_render_dimensions
}
if {![regexp {^([0-9]+)[xX]([0-9]+)$} $dimensions _m w h]} {
lappend ::punk::ansi::class::PUNKARGS [list {
@id -id "::punk::ansi::class::class_ansi rendertest"
@cmd -name "punk::ansi::class::class_ansi rendertest" -help\
""
@opts
-width -type integer -default ""
-height -type integer -default ""
-crm_mode -type boolean -default 0
-binarytext -type string -default "" -choices {"" bios ice}
@values -min 0 -max 0
}]
method rendertest {args} {
set argd [punk::args::parse $args withid "::punk::ansi::class::class_ansi rendertest"]
set opt_width [dict get $argd opts -width]
set opt_height [dict get $argd opts -height]
set opt_crm_mode [dict get $argd opts -crm_mode]
set opt_binarytext [dict get $argd opts -binarytext]
set existing_dimensions $o_render_dimensions
if {![regexp {^([0-9]+)[xX]([0-9]+)$} $existing_dimensions _m w h]} {
error "class_ansi::render dimensions must be of the form <width>x<height>"
}
set o_dimensions $dimensions
if {$opt_width ne ""} {
set w $opt_width
}
if {$opt_height ne ""} {
set h $opt_height
}
set o_render_dimensions ${w}x${h}
set rendered [overtype::renderspace -cp437 1 -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
set rendered [overtype::renderspace -binarytext $opt_binarytext -cp437 1 -crm_mode $opt_crm_mode -expand_right 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
return $rendered
}
@ -414,6 +436,9 @@ tcl::namespace::eval punk::ansi {
tcl::dict::set cp437_map \u001E \u25B2 ;#up arrow triangle
tcl::dict::set cp437_map \u001F \u25BC ;#down arrow triangle
#del control character
tcl::dict::set cp437_map \u007F \u2302 ;#House
variable map_special_graphics
#DEC Special Graphics set https://en.wikipedia.org/wiki/DEC_Special_Graphics
#AKA IBM Code page 1090
@ -561,7 +586,175 @@ tcl::namespace::eval punk::ansi {
}
return $obj
}
proc ansicat {fname args} {
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::ansi::sauce
@cmd -name punk::ansi::sauce -summary\
"SAUCE info from file"\
-help\
"Wrapper for punk::ansi::sauce::from_file to display SAUCE block data."
-encoding -default iso8859-1 -type string -help\
"The default iso8859-1 is equivalent to binary ans should
work in the usual case.
If the entire file including the trailing SAUCE block was encoded
in another manner, -encoding may be supplied to decode prior to
examining SAUCE data.
(unimplemented)"
-return -type string -default tables -choices {dict string}
@values -min 1 -max 1
filename -type string
}]
}
proc sauce {args} {
set argd [punk::args::parse $args withid ::punk::ansi::sauce]
lassign [dict values $argd] leaders opts values
set filename [dict get $values filename]
set opt_return [dict get $opts -return]
package require punk::ansi::sauce
set sdict [punk::ansi::sauce::from_file $filename]
set result ""
if {[dict size $sdict]} {
if {$opt_return eq "dict"} {
return $sdict
}
if {[dict exists $sdict commentlines]} {
set clines [dict get $sdict commentlines]
set cblock [join $clines \n]
append result [textblock::frame -title "SAUCE comments" $cblock]
}
dict unset sdict commentlines
append result \n [punk::lib::showdict $sdict]
}
return $result
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::ansi::ansicat
@cmd -name punk::ansi::ansicat -help\
"Display ANSI image - using SAUCE data if any to determine width and encoding."
-encoding -type string -help\
"Force a particular encoding eg utf-8 or cp437.
Default is cp437 - or as specified in any SAUCE data."
-dimensions -type string -help\
"Force specific COLxROW dimensions
e.g 82x30
Default is 80x24 when no SAUCE data exists.
If SAUCE data specifies dimensions, they will
be used if this value is not supplied.
"
-crm_mode -type binary -default 0
-sauce -type none -help\
"Display SAUCE and comments after image"
@values -min 1 -max 1
filename -type string
}]
}
proc ansicat {args} {
set argd [punk::args::parse $args withid ::punk::ansi::ansicat]
lassign [dict values $argd] leaders opts values received
set fname [dict get $values filename]
if {[dict exists $received -encoding]} {
set encoding [dict get $opts -encoding]
set encnames [encoding names]
if {$encoding ni $encnames} {
error "punk::ansi::ansicat unknown encoding $encoding should be one of the values from 'encoding names'"
}
} else {
set encoding ""
}
if {[dict exists $received -dimensions]} {
set dimensions [dict get $opts -dimensions]
if {![regexp {[0-9]+(?:x|X)[0-9]+} $dimensions]} {
error "punk::ansi::ansicat bad dimension specification $a should be of form WxH"
}
} else {
set dimensions ""
}
set opt_crm_mode [dict get $opts -crm_mode]
#if SAUCE data is present - it may give an indication of encoding as well as number of columns/lines
package require punk::ansi::sauce
set binarytext ""
if {[catch {punk::ansi::sauce::from_file $fname} sdict]} {
#no 128 Byte SAUCE record at end of file
set sdict [dict create]
}
if {![dict size $sdict]} {
if {[string tolower [file extension $fname]] eq ".bin"} {
#In the absence of SAUCE data - assume .bin is binary text
set binarytext bios ;#16 fg, 8 bg + blink
}
}
if {[dict exists $sdict datatype_name]} {
if {[dict get $sdict datatype_name] eq "binarytext"} {
#todo - SAUCE ANSiFlags - ice vs default bios
set binarytext bios
}
}
if {$encoding eq ""} {
if {[dict exists $sdict codepage]} {
set encoding [dict get $sdict codepage]
} else {
#default
set encoding cp437
}
}
if {$dimensions eq ""} {
# defaults
set cols 80
set rows 24
if {[dict exists $sdict columns]} {
set c [dict get $sdict columns]
if {$c > 0} {
set cols $c
}
}
if {[dict exists $sdict rows]} {
set r [dict get $sdict rows]
if {$r > 0} {
set rows $r
}
}
set dimensions ${cols}x${rows}
}
lassign [split $dimensions x] cols rows
#set ansidata [fcat -encoding $encoding $fname]
set filedata [fcat -translation binary $fname]
set parts [split $filedata \x1a]
set ansidata [lindex $parts 0]
#hack
#if {$binarytext eq ""} {
set ansidata [encoding convertfrom $encoding $ansidata]
#}
set obj [punk::ansi::class::class_ansi new $ansidata]
if {$encoding eq "cp437"} {
set result [$obj rendertest -binarytext $binarytext -width $cols -height $rows -crm_mode $opt_crm_mode]
} else {
set result [$obj render $dimensions]
}
$obj destroy
if {[dict exists $received -sauce] && [dict size $sdict]} {
if {[dict exists $sdict commentlines]} {
set clines [dict get $sdict commentlines]
dict unset sdict commentlines
set cblock [join $clines \n]
append result \n [textblock::frame -title "SAUCE comments" $cblock]
}
append result \n [punk::lib::showdict $sdict]
}
return $result
}
proc ansicat1 {fname args} {
set encnames [encoding names]
set encoding ""
set dimensions ""
@ -574,6 +767,9 @@ tcl::namespace::eval punk::ansi {
}
}
}
#if SAUCE data is present - it may give an indication of encoding as well as number of columns/lines
package require punk::ansi::sauce
if {$encoding eq ""} {
set encoding cp437
}
@ -581,11 +777,12 @@ tcl::namespace::eval punk::ansi {
if {$dimensions eq ""} {
set dimensions 80x24
}
lassign [split $dimensions x] cols rows
set ansidata [fcat -encoding $encoding $fname]
set obj [punk::ansi::class::class_ansi new $ansidata]
if {$encoding eq "cp437"} {
set result [$obj rendertest $dimensions]
set result [$obj rendertest -width $cols -height $rows]
} else {
set result [$obj render $dimensions]
}
@ -8841,7 +9038,19 @@ namespace eval punk::ansi::colour {
#https://sourceforge.net/p/irrational-numbers/code/HEAD/tree/pkgs/Colors/trunk/colors.tcl#l159
# classic formula for luminance (0.0 .. 100.0)
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id "::punk::ansi::colour::luminance"
@cmd -name "punk::ansi::colour::luminance" -help\
"Classic formula for luminance (0.0 .. 1.0)
8bit colour is assumed."
@opts
@values -min 3 -max 3
R -type int -range {0 255}
G -type int -range {0 255}
B -type int -range {0 255}
}]
}
proc luminance {R G B} {
return [expr {(0.3*$R + 0.59*$G + 0.11*$B)/255.0}]
}
@ -9017,6 +9226,195 @@ namespace eval punk::ansi::colour {
return [list $hue $sat $lum]
}
variable byte_to_ansi
variable byte_to_ansi_ice
for {set i 0} {$i <= 255} {incr i} {
#foreground
if {$i & 4 && $i & 2 && $i & 1} {
# 111 white
if {$i & 8} {
set fg rgb-255-255-255
} else {
#low intensity (Light Gray)
set fg rgb-170-170-170 ;#or 192-192-192
}
} elseif {$i & 4 && $i & 2} {
# 110 yellow
if {$i & 8} {
set fg rgb-255-255-0
} else {
set fg rgb-170-85-0 ;#or 128-128-0
}
} elseif {$i & 4 && $i & 1} {
# 101 magenta
if {$i & 8} {
set fg rgb-255-0-255
} else {
set fg rgb-170-0-170 ;#or 128-0-128
}
} elseif {$i & 4} {
# 100 red
if {$i & 8} {
set fg rgb-255-0-0
} else {
set fg rgb-170-0-0 ;#or 128-0-0
}
} elseif {$i & 2 && $i & 1} {
# 011 cyan
if {$i & 8} {
set fg rgb-0-255-255
} else {
set fg rgb-0-170-170 ;#or 0-128-128
}
} elseif {$i & 2} {
# 010 green
if {$i & 8} {
set fg rgb-0-255-0
} else {
set fg rgb-0-170-0 ;#or 0-128-0
}
} elseif {$i & 1} {
# 001 blue
if {$i & 8} {
set fg rgb-0-0-255
} else {
set fg rgb-0-0-170 ;#or 0-0-128
}
} else {
# 000 black
if {$i & 8} {
#high intensity (Dark Gray)
set fg rgb-85-85-85
} else {
set fg rgb-0-0-0
}
}
#non-iCE background colours are the 8 low-intensity colours
set blink noblink
set bg "Rgb-0-0-0"
set ibg Rgb-0-0-0
if {$i > 15} {
if {$i & 64 && $i & 32 && $i & 16} {
# 111 white
if {$i & 128} {
set ibg Rgb-255-255-255
set blink blink
} else {
#low intensity (Light Gray)
set ibg Rgb-170-170-170 ;#or 192-192-192
}
set bg Rgb-170-170-170
} elseif {$i & 64 && $i & 32} {
# 110 yellow
if {$i & 128} {
set ibg Rgb-255-255-0
set blink blink
} else {
set ibg Rgb-170-85-0 ;#or 128-128-0
}
set bg Rgb-170-85-0
} elseif {$i & 64 && $i & 16} {
# 101 magenta
if {$i & 128} {
set ibg Rgb-255-0-255
set blink blink
} else {
set ibg Rgb-170-0-170 ;#or 128-0-128
}
set bg Rgb-170-0-170
} elseif {$i & 64} {
# 100 red
if {$i & 128} {
set ibg Rgb-255-0-0
set blink blink
} else {
set ibg Rgb-170-0-0 ;#or 128-0-0
}
set bg Rgb-170-0-0
} elseif {$i & 32 && $i & 16} {
# 011 cyan
if {$i & 128} {
set ibg Rgb-0-255-255
set blink blink
} else {
set ibg Rgb-0-170-170 ;#or 0-128-128
}
set bg Rgb-0-170-170
} elseif {$i & 32} {
# 010 green
if {$i & 128} {
set ibg Rgb-0-255-0
set blink blink
} else {
set ibg Rgb-0-170-0 ;#or 0-128-0
}
set bg Rgb-0-170-0
} elseif {$i & 16} {
# 001 blue
if {$i & 128} {
set ibg Rgb-0-0-255
set blink blink
} else {
set ibg Rgb-0-0-170 ;#or 0-0-128
}
set bg Rgb-0-0-170
} else {
# 000 black
#high intensity (Dark Gray)
set ibg Rgb-85-85-85
}
}
dict set byte_to_ansi [format %c $i] [punk::ansi::a+ {*}$blink $fg $bg]
dict set byte_to_ansi_ice [format %c $i] [punk::ansi::a+ $fg $ibg]
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id "::punk::ansi::colour::byteAnsi"
@cmd -name "punk::ansi::colour::byteAnsi" -summary\
"ANSI/BIOS colour codes from attribute byte."\
-help\
"Convert an attribute-byte (character) to ANSI SGR
foreground and background colour.
This is allows 16 foreground colours and only 8
background colours, with the highest bit being
used to set 'blink' on.
Use the byteAnsiIce for 16 background colours."
@opts
@values -min 1 -max 1
char -type char
}]
}
proc byteAnsi {char} {
variable byte_to_ansi
dict get $byte_to_ansi $char
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id "::punk::ansi::colour::byteAnsiIce"
@cmd -name "punk::ansi::colour::byteAnsiIce" -summary\
"iCE colour codes from attribute byte."\
-help\
"Convert an attribute-byte (character) to ANSI SGR
foreground and background colour.
This is allows 16 foreground colours and 16
background colours. (no blink capability)
Use the byteAnsi for ANSI/BIOS 16 foreground,
8 background colours with blink capability."
@opts
@values -min 1 -max 1
char -type char
}]
}
proc byteAnsiIce {char} {
variable byte_to_ansi_ice
dict get $byte_to_ansi_ice $char
}
}
tcl::namespace::eval punk::ansi::internal {
proc splitn {str {len 1}} {
@ -9115,7 +9513,7 @@ interp alias {} ansistring {} ::punk::ansi::ansistring
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::ansi ::punk::ansi::argdoc ::punk::ansi::class ::punk::ansi::ta
lappend ::punk::args::register::NAMESPACES ::punk::ansi ::punk::ansi::colour ::punk::ansi::argdoc ::punk::ansi::class ::punk::ansi::ta
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++

573
src/modules/punk/ansi/sauce-999999.0a1.0.tm

@ -0,0 +1,573 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'dev make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.4.tm
#
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem.
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository.
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# (C) 2025
#
# @@ Meta Begin
# Application punk::ansi::sauce 999999.0a1.0
# Meta platform tcl
# Meta license MIT
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
package require Tcl 8.6-
tcl::namespace::eval punk::ansi::sauce {
variable PUNKARGS
namespace eval argdoc {
variable PUNKARGS
#non-colour SGR codes
set I "\x1b\[3m" ;# [a+ italic]
set NI "\x1b\[23m" ;# [a+ noitalic]
set B "\x1b\[1m" ;# [a+ bold]
set N "\x1b\[22m" ;# [a+ normal]
set T "\x1b\[1\;4m" ;# [a+ bold underline]
set NT "\x1b\[22\;24m\x1b\[4:0m" ;# [a+ normal nounderline]
}
proc from_file {fname} {
if {[file size $fname] < 128} {
return
}
set fd [open $fname r]
chan conf $fd -translation binary
chan seek $fd -128 end
set srec [read $fd]
set srec_len 128 ;#This is the normal length of a SAUCE record - we may need to set it shorter if truncation detected
if {[catch {set sdict [to_dict $srec]}]} {
#review - have seen truncated SAUCE records < 128 bytes
#we could search for SAUCE00 in the tail and see what records can be parsed?
#specifically publicdomain roysac images sometimes only 99 Bytes of sauce - suspect remaining were null \x0 padded and trimmed
set sauceposn [string first SAUCE00 $srec]
if {$sauceposn <= 0} {
close $fd
return
}
#emit something to give user an indication something isn't right
puts stderr "punk::ansi::sauce::from_file WARNING SAUCE record seems to be truncated - padding rhs with nulls and trying again.."
#SAUCE00 is not at the beginning
#pad the tail with nulls and try again
set srec [string range $srec $sauceposn end]
set srec_len [string length $srec]
set srec ${srec}[string repeat \x0 [expr {128 - [string length $srec]}]]
if {[catch {set sdict [to_dict $srec]}]} {
close $fd
return
}
dict set sdict warning "SAUCE truncation to $srec_len bytes detected"
}
if {[dict exists $sdict comments] && [dict get $sdict comments] > 0} {
set clines [dict get $sdict comments]
#Use srec_len instead of 128 - in case we had truncated source record which we padded and were able to parse
set offset [expr {-1 *($srec_len + ($clines * 64) + 5)}]
chan seek $fd $offset end
set tag [chan read $fd 5]
if {$tag eq "COMNT"} {
#'character' data - shouldn't be null terminated c-style string - but can be
set commentlines [list]
for {set c 0} {$c < $clines} {incr c} {
set rawline [chan read $fd 64]
if {![catch {binary scan $rawline C* str} errM]} {
set ln [format %-64s $str]
} else {
set ln [string repeat " " 64]
}
if {![catch {encoding convertfrom cp437 $ln} line]} {
lappend commentlines $line
} else {
catch {
package require punk::ansi
puts stderr "punk::ansi::sauce::from_file failed to decode (from cp437) comment line:[punk::ansi::ansistring VIEW $ln]"
}
lappend commentlines [string repeat " " 64]
}
}
dict set sdict commentlines $commentlines
}
}
close $fd
return $sdict
}
set datatypes [dict create]
dict set datatypes 0 none
dict set datatypes 1 character
dict set datatypes 2 bitmap
dict set datatypes 3 vector
dict set datatypes 4 audio
dict set datatypes 5 binarytext
dict set datatypes 6 xbin
dict set datatypes 7 archive
dict set datatypes 8 executable
set filetypes [dict create]
#Character
dict set filetypes 1 0 [list name "ASCII" description "Plain ASCII text file with no formatting codes or color codes."]
dict set filetypes 1 1 [list name "ANSi" description "A file with ANSi coloring codes and cursor positioning."]
dict set filetypes 1 2 [list name "ANSiMation" description "Like an ANSi file, but it relies on a fixed screensize."]
dict set filetypes 1 3 [list name "RIP script" description "Remote Imaging Protocol Graphics."]
dict set filetypes 1 4 [list name "PCBoard" description "A file with PCBoard color codes and macros, and ANSi codes."]
dict set filetypes 1 5 [list name "Avatar" description "A file with Avatar color codes, and ANSi codes."]
dict set filetypes 1 6 [list name "HTML" description "HyperText Markup Language."]
dict set filetypes 1 7 [list name "Source" description "Source code for some programming language.\nThe file extension should determine the programming language."]
dict set filetypes 1 8 [list name "TundraDraw" description "A TundraDraw file.\nLike ANSi, but with a custom palette."]
#Bitmap
dict set filetypes 2 0 [list name "GIF" description "CompuServe Graphics Interchange Format"]
dict set filetypes 2 1 [list name "PCX" description "ZSoft Paintbrush PCX"]
dict set filetypes 2 2 [list name "LBM/IFF" description "DeluxePaint LBM/IFF"]
dict set filetypes 2 3 [list name "TGA" description "Targa Truecolor"]
dict set filetypes 2 4 [list name "FLI" description "Autodesk FLI animation"]
dict set filetypes 2 5 [list name "FLC" description "Autodesk FLC animation"]
dict set filetypes 2 6 [list name "BMP" description "Windows or OS/2 Bitmap"]
dict set filetypes 2 7 [list name "GL" description "Grasp GL Animation"]
dict set filetypes 2 8 [list name "DL" description "DL Animation"]
dict set filetypes 2 9 [list name "WPG" description "Wordperfect Bitmap"]
dict set filetypes 2 10 [list name "PNG" description "Portable Network Graphics"]
dict set filetypes 2 11 [list name "JPG/JPeg" description "JPeg image (any subformat)"]
dict set filetypes 2 12 [list name "MPG" description "MPeg video (any subformat)"]
dict set filetypes 2 12 [list name "AVI" description "Audio Video Interleave (any subformat)"]
#vector
dict set filetypes 3 0 [list name "DXF" description "CAD Drawing eXchange Format"]
dict set filetypes 3 1 [list name "DWG" description "AutoCAD Drawing File"]
dict set filetypes 3 2 [list name "WPG" description "WordPerfect or DrawPerfect vector graphics"]
dict set filetypes 3 3 [list name "3DS" description "3D Studio"]
#Audio
dict set filetypes 4 0 [list name "MOD" description "4, 6 or 8 channel MOD (Noise Tracker)"]
dict set filetypes 4 1 [list name "669" description "Renaissance 8 channel 669"]
dict set filetypes 4 2 [list name "STM" description "Future Crew 4 channel ScreamTracker"]
dict set filetypes 4 3 [list name "S3M" description "Future Crew variable channel ScreamTracker 3"]
dict set filetypes 4 4 [list name "MTM" description "Renaissance variable channel MultiTracker"]
dict set filetypes 4 5 [list name "FAR" description "Farandole composer"]
dict set filetypes 4 6 [list name "ULT" description "UltraTracker"]
dict set filetypes 4 7 [list name "AMF" description "DMP/DSMI Advanced Module Format"]
dict set filetypes 4 8 [list name "DMF" description "Delusion Digital Music Format (XTracker)"]
dict set filetypes 4 9 [list name "OKT" description "Oktalyser"]
dict set filetypes 4 10 [list name "ROL" description "AdLib ROL file (FM audio)"]
dict set filetypes 4 11 [list name "CMF" description "Creative Music File (FM Audio)"]
dict set filetypes 4 12 [list name "MID" description "MIDI (Musical Instrument Digital Interface)"]
dict set filetypes 4 13 [list name "SADT" description "SAdT composer (FM Audio)"]
dict set filetypes 4 14 [list name "VOC" description "Creative Voice File"]
dict set filetypes 4 15 [list name "WAV" description "Waveform Audio File Format"]
dict set filetypes 4 16 [list name "SMP8" description "Raw, single channel 8 bit sample"]
dict set filetypes 4 17 [list name "SMP8S" description "Raw, stereo 8 bit sample"]
dict set filetypes 4 18 [list name "SMP16" description "Raw, single channel 16 bit sample"]
dict set filetypes 4 19 [list name "SMP16S" description "Raw, stereo 16 bit sample"]
dict set filetypes 4 20 [list name "PATCH8" description "8 Bit patch file"]
dict set filetypes 4 21 [list name "PATCH16" description "16 Bit patch file"]
dict set filetypes 4 22 [list name "XM" description "FastTracker \]\[ module"]
dict set filetypes 4 23 [list name "HSC" description "HSC Tracker (FM Audio)"]
dict set filetypes 4 24 [list name "IT" description "Impulse Tracker"]
#Archive
dict set filetypes 7 0 [list name "ZIP" description "PKWare Zip"]
dict set filetypes 7 1 [list name "ARJ" description "Archive Robert K. Jung"]
dict set filetypes 7 2 [list name "LZH" description "Haruyasu Yoshizaki (Yoshi)"]
dict set filetypes 7 3 [list name "ARC" description "S.E.A"]
dict set filetypes 7 4 [list name "TAR" description "Unix TAR"]
dict set filetypes 7 5 [list name "ZOO" description "ZOO"]
dict set filetypes 7 6 [list name "RAR" description "RAR"]
dict set filetypes 7 7 [list name "UC2" description "UC2"]
dict set filetypes 7 8 [list name "PAK" description "PAK"]
dict set filetypes 7 9 [list name "SQZ" description "SQZ"]
#review
#map sauce encodings to those that exist by default in Tcl 'encoding names'
set encodings [dict create]
dict set encodings 437 cp437
dict set encodings 720 cp1256 ;#Arabic
dict set encodings 737 cp737
dict set encodings 775 cp775
dict set encodings 819 iso8859-1 ;#Latin-1 Supplemental - review
dict set encodings 850 cp850
dict set encodings 852 cp852
dict set encodings 855 cp855
dict set encodings 857 cp857
#dict set encodings 858 "" ;#???
dict set encodings 860 cp860 ;#Porguguese
dict set encodings 861 cp861 ;#Icelandic
dict set encodings 862 cp862 ;#Hebrew
dict set encodings 863 cp863 ;#French Canada
dict set encodings 864 cp864
dict set encodings 865 cp865
dict set encodings 866 cp866 ;#Cyrillic
dict set encodings 869 cp869
#dict set encodings 872 "" ;#Cyrillic - cp855? macCyrillic?
#dict set encodings KAM "" ;#cp867,cp895 ?
#dict set encodings MAZ "" ;#cp667 cp790 ?
dict set encodings MIK cp866 ;#Cyrillic
#todo - fontName - which can also specify e.g code page 437
## Font name [1] Font size Resolution [2] Aspect ratio [3] Vertical stretch [6] Description
## Display [4] Pixel [5]
set fontnames [dict create]
## IBM VGA 9×16 [7] 720×400 4:3 20:27 (1:1.35) 35% Standard hardware font on VGA cards for 80×25 text mode (code page 437)
dict set fontnames "IBM VGA" [list fontsize "9x16" resolution "720x400" aspect_ratio_display "4:3" aspect_ratio_pixel "20:27 (1:1.35)" vertical_stretch "35%" description "Standard hardware font on VGA cards for 80×25 text mode (code page 437)"]
## IBM VGA ### [8] 9×16 [7] 720×400 4:3 20:27 (1:1.35) 35% Software installed code page font for VGA 80×25 text mode
# - where ### is placeholder for 437,720,737 etc
## IBM VGA50 ### [8] 9×8 [7] 720×400 4:3 20:27 (1:1.35) 35% Software installed code page font for VGA condensed 80×50 text mode
## IBM VGA25G ### [8] 8×19 640×480 4:3 1:1 0% Custom font for emulating 80×25 in VGA graphics mode 12 (640×480 16 color).
## 8×16 640×400 4:3 6:5 (1:1.2) 20% Modified stats when using an 8 pixel wide version of "IBM VGA" or code page variant.
## IBM VGA50 9×8 [7] 720×400 4:3 20:27 (1:1.35) 35% Standard hardware font on VGA cards for condensed 80×50 text mode (code page 437)
## 8×8 640×400 4:3 5:6 (1:1.2) 20% Modified stats when using an 8 pixel wide version of "IBM VGA50" or code page variant.
## IBM VGA25G 8×19 640×480 4:3 1:1 0% Custom font for emulating 80×25 in VGA graphics mode 12 (640×480 16 color) (code page 437).
## IBM EGA 8×14 640×350 4:3 35:48 (1:1.3714) 37.14% Standard hardware font on EGA cards for 80×25 text mode (code page 437)
## IBM EGA43 8×8 640×350 4:3 35:48 (1:1.3714) 37.14% Standard hardware font on EGA cards for condensed 80×43 text mode (code page 437)
## IBM EGA ### [8] 8×14 640×350 4:3 35:48 (1:1.3714) 37.14% Software installed code page font for EGA 80×25 text mode
## IBM EGA43 ### [8] 8×8 640×350 4:3 35:48 (1:1.3714) 37.14% Software installed code page font for EGA condensed 80×43 text mode
## Amiga Topaz 1 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Original Amiga Topaz Kickstart 1.x font. (A500, A1000, A2000)
## Amiga Topaz 1+ 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Modified Amiga Topaz Kickstart 1.x font. (A500, A1000, A2000)
## Amiga Topaz 2 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Original Amiga Topaz Kickstart 2.x font (A600, A1200, A4000)
## Amiga Topaz 2+ 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Modified Amiga Topaz Kickstart 2.x font (A600, A1200, A4000)
## Amiga P0T-NOoDLE 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Original P0T-NOoDLE font.
## Amiga MicroKnight 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Original MicroKnight font.
## Amiga MicroKnight+ 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Modified MicroKnight font.
## Amiga mOsOul 8×8 [9] 640×200 4:3 5:12 (1:2.4) 140% Original mOsOul font.
## C64 PETSCII unshifted 8×8 [10] 320×200 4:3 5:6 (1:1.2) 20% Original Commodore PETSCII font (PET, VIC-20, C64, CBM-II, Plus/4, C16, C116 and C128) in the unshifted mode. Unshifted mode (graphics) only has uppercase letters and additional graphic characters. This is the normal boot font.
## C64 PETSCII shifted 8×8 [10] 320×200 4:3 5:6 (1:1.2) 20% Original PETSCII font in shifted mode. Shifted mode (text) has both uppercase and lowercase letters. This mode is actuated by pressing Shift+Commodore key.
## Atari ATASCII 8×8 [11] 320×192 4:3 4:5 (1:1.25) 25% Original ATASCII font (Atari 400, 800, XL, XE)
#expect a 128 Byte sauce record
#Some sauce records may have been padded with null bytes - and been truncated by some process
proc to_dict {saucerecord} {
variable datatypes
variable filetypes
variable encodings
if {[string length $saucerecord] != 128} {
error "punk::ansi::sauce::to_dict: Unable to interpret data as a SAUCE record - length != 128"
}
if {![string match "SAUCE*" $saucerecord]} {
error "punk::ansi::sauce::to_dict: Unable to interpret data as a SAUCE record - does not begin with 'SAUCE'"
}
#tcl binary scan: cu - unsigned 8-bit, su - unsigned 16-bit, iu - unsigned 32bit,
set sdict [dict create]
dict set sdict version [string range $saucerecord 5 6] ;#2bytes
#sauce spec says 'character' type is a string encoded according to code page 437 (IBM PC / OEM ASCII)
# - in the wild - string may be terminated with null and have following garbage
# - 'binary scan $rawchars C* str' to get null-terminated string and pad rhs with spaces to cater for this possibility
#dict set sdict title [string range $saucerecord 7 41] ;#35 bytes 'character'
set rawtitle [string range $saucerecord 7 41] ;#35 bytes 'character'
if {![catch {binary scan $rawtitle C* str} errM]} {
dict set sdict title [format %-35s $str]
} else {
dict set sdict title [string repeat " " 35]
}
#dict set sdict author [string range $saucerecord 42 61] ;#20 bytes 'character'
set rawauthor [string range $saucerecord 42 61] ;#20 bytes 'character'
if {![catch {binary scan $rawauthor C* str} errM]} {
dict set sdict author [format %-20s $str]
} else {
dict set sdict author [string repeat " " 20]
}
#dict set sdict group [string range $saucerecord 62 81] ;#20 bytes 'character'
set rawgroup [string range $saucerecord 62 81] ;#20 bytes 'character'
if {![catch {binary scan $rawgroup C* str} errM]} {
dict set sdict group [format %-20s $str]
} else {
dict set sdict group [string repeat " " 20]
}
#dict set sdict date [string range $saucerecord 82 89] ;#8 bytes 'character'
set rawdata [string range $saucerecord 82 89] ;#8 bytes 'character'
if {![catch {binary scan $rawdate C* str} errM]} {
dict set sdict date [format %-8s $str]
} else {
dict set sdict date [string repeat " " 8]
}
if {[binary scan [string range $saucerecord 90 93] iu v]} {
#4 bytes - unsigned littlendian
dict set sdict filesize $v
} else {
dict set sdict filesize ""
}
if {[binary scan [string range $saucerecord 94 94] cu v]} {
#1 byte - unsigned
dict set sdict datatype $v
if {[dict exists $datatypes [dict get $sdict datatype]]} {
dict set sdict datatype_name [dict get $datatypes [dict get $sdict datatype]]
} else {
dict set sdict datatype_name unrecognised
}
} else {
dict set sdict datatype ""
dict set sdict datatype_name failed ;#unrecognised??
}
if {[binary scan [string range $saucerecord 95 95] cu v]} {
#1 byte - unsigned
dict set sdict filetype $v
if {[dict exists $filetypes [dict get $sdict datatype] $v]} {
dict set sdict filetype_name [dict get $filetypes [dict get $sdict datatype] $v name]
} else {
dict set sdict filetype_name ""
}
} else {
dict set sdict filetype ""
dict set sdict filetype_name ""
}
if {[binary scan [string range $saucerecord 96 97] su v]} {
dict set sdict tinfo1 $v
} else {
dict set sdict tinfo1 ""
}
if {[binary scan [string range $saucerecord 98 99] su v]} {
dict set sdict tinfo2 $v
} else {
dict set sdict tinfo2 ""
}
if {[binary scan [string range $saucerecord 100 101] su v]} {
dict set sdict tinfo3 $v
} else {
dict set sdict tinfo3 ""
}
if {[binary scan [string range $saucerecord 102 103] su v]} {
dict set sdict tinfo4 $v
} else {
dict set sdict tinfo4 ""
}
if {[binary scan [string range $saucerecord 104 104] cu v]} {
#1 byte - unsigned
dict set sdict comments $v
} else {
dict set sdict comments 0
}
if {[binary scan [string range $saucerecord 105 105] cu v]} {
dict set sdict tflags $v
} else {
dict set sdict tflags ""
}
set rawzstring [string range $saucerecord 106 127]
#Null terminated string use C to terminate at first null
if {[binary scan $rawzstring C* str]} {
dict set sdict tinfos $str
} else {
dict set sdict tinfos ""
}
switch -- [string tolower [dict get $sdict filetype_name]] {
ansi - ascii - pcboard - avatar {
dict set sdict columns [dict get $sdict tinfo1]
dict set sdict rows [dict get $sdict tinfo2]
dict set sdict fontname [dict get $sdict tinfos]
}
ansimation {
dict set sdict columns [dict get $sdict tinfo1]
#review - fixed screen height?
dict set sdict rows [dict get $sdict tinfo2]
dict set sdict fontname [dict get $sdict tinfos]
}
}
switch -- [dict get $sdict datatype] {
5 {
#binarytext
#filetype represents half the characterwidth (only widths with multiples of 2 can be specified)
set cols [expr {2*[dict get $sdict filetype]}]
dict set sdict columns $cols
#rows must be calculated from file size
#rows = (filesize - sauceinfosize)/ filetype * 2 * 2
#(time additional 2 due to character/attribute pairs)
#todo - calc filesize from total size of file - EOF - comment - sauce rather than rely on stored filesize?
dict set sdict rows [expr {[dict get $sdict filesize]/($cols * 2)}]
}
6 {
#xbin - only filtype is 0
#https://web.archive.org/web/20120204063040/http://www.acid.org/info/xbin/x_spec.htm
dict set sdict columns [dict get $sdict tinfo1]
dict set sdict rows [dict get $sdict tinfo2]
dict set sdict fontname [dict get $sdict tinfos]
}
}
if {[dict exists $sdict fontname]} {
set fname [dict get $sdict fontname]
#IBM VGA and IBM EGA variants are all cp437 - unless a 3 letter code specifying otherwise follows
switch -- [string range $fname 0 6] {
"IBM EGA" - "IBM VGA" {
lassign $fname _ibm _ code
set cp ""
if {$code eq ""} {
set cp "cp437"
} else {
if {[dict exists $encodings $code]} {
set cp [dict get $encodings $code]
}
}
if {$cp ne ""} {
dict set sdict codepage $cp
}
}
}
}
return $sdict
}
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::ansi::sauce::lib {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
tcl::namespace::path [tcl::namespace::parent]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#tcl::namespace::eval punk::ansi::sauce::system {
#}
# == === === === === === === === === === === === === === ===
# Sample 'about' function with punk::args documentation
# == === === === === === === === === === === === === === ===
tcl::namespace::eval punk::ansi::sauce {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
variable PUNKARGS
variable PUNKARGS_aliases
lappend PUNKARGS [list {
@id -id "(package)punk::ansi::sauce"
@package -name "punk::ansi::sauce" -help\
"Basic support for SAUCE format
Standard Architecture for Universal Comment Extensions
https://www.acid.org/info/sauce/sauce.htm "
}]
namespace eval argdoc {
#namespace for custom argument documentation
proc package_name {} {
return punk::ansi::sauce
}
proc about_topics {} {
#info commands results are returned in an arbitrary order (like array keys)
set topic_funs [info commands [namespace current]::get_topic_*]
set about_topics [list]
foreach f $topic_funs {
set tail [namespace tail $f]
lappend about_topics [string range $tail [string length get_topic_] end]
}
#Adjust this function or 'default_topics' if a different order is required
return [lsort $about_topics]
}
proc default_topics {} {return [list Description *]}
# -------------------------------------------------------------
# get_topic_ functions add more to auto-include in about topics
# -------------------------------------------------------------
proc get_topic_Description {} {
punk::args::lib::tstr [string trim {
package punk::ansi::sauce
ANSI SAUCE block processor
} \n]
}
proc get_topic_License {} {
return "MIT"
}
proc get_topic_Version {} {
return "$::punk::ansi::sauce::version"
}
proc get_topic_Contributors {} {
set authors {{"Julian Noble" <julian@precisium.com.au>}}
set contributors ""
foreach a $authors {
append contributors $a \n
}
if {[string index $contributors end] eq "\n"} {
set contributors [string range $contributors 0 end-1]
}
return $contributors
}
proc get_topic_custom-topic {} {
punk::args::lib::tstr -return string {
A custom
topic
etc
}
}
# -------------------------------------------------------------
}
# we re-use the argument definition from punk::args::standard_about and override some items
set overrides [dict create]
dict set overrides @id -id "::punk::ansi::sauce::about"
dict set overrides @cmd -name "punk::ansi::sauce::about"
dict set overrides @cmd -help [string trim [punk::args::lib::tstr {
About punk::ansi::sauce
}] \n]
dict set overrides topic -choices [list {*}[punk::ansi::sauce::argdoc::about_topics] *]
dict set overrides topic -choicerestricted 1
dict set overrides topic -default [punk::ansi::sauce::argdoc::default_topics] ;#if -default is present 'topic' will always appear in parsed 'values' dict
set newdef [punk::args::resolved_def -antiglobs -package_about_namespace -override $overrides ::punk::args::package::standard_about *]
lappend PUNKARGS [list $newdef]
proc about {args} {
package require punk::args
#standard_about accepts additional choices for topic - but we need to normalize any abbreviations to full topic name before passing on
set argd [punk::args::parse $args withid ::punk::ansi::sauce::about]
lassign [dict values $argd] _leaders opts values _received
punk::args::package::standard_about -package_about_namespace ::punk::ansi::sauce::argdoc {*}$opts {*}[dict get $values topic]
}
}
# end of sample 'about' function
# == === === === === === === === === === === === === === ===
# -----------------------------------------------------------------------------
# register namespace(s) to have PUNKARGS,PUNKARGS_aliases variables checked
# -----------------------------------------------------------------------------
# variable PUNKARGS
# variable PUNKARGS_aliases
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::ansi::sauce
}
# -----------------------------------------------------------------------------
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::ansi::sauce [tcl::namespace::eval punk::ansi::sauce {
variable pkg punk::ansi::sauce
variable version
set version 999999.0a1.0
}]
return

3
src/modules/punk/ansi/sauce-buildversion.txt

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

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

@ -140,6 +140,16 @@ tcl::namespace::eval punk::lib::check {
set bug [expr {![catch {regexp {} [error should_error]}]}]
return [dict create bug $bug bugref cb03e57a description {regexp emptystring first argument over-optimised - difference in compiled vs traced behaviour.} level minor]
}
proc has_tclbug_lsearch_sorted_inline_subindices {} {
if {[catch {lsearch -sorted -subindices -inline -index 0 {{a 1} {a 2} {b 3} {c 4} {c 5}} b} result]} {
#probably tcl version doesn't support all options
set bug 0
} else {
set bug [expr {$result ne "b"}]
}
set description "lsearch -sorted with -subindices -inline - incorrect result."
return [dict create bug $bug bugref bc4ac0 description $description level minor]
}
proc has_tclbug_script_var {} {
set script {set j [list spud] ; list}
@ -765,7 +775,7 @@ namespace eval punk::lib {
struct::list swap doesn't support 'end' offsets, and only
sometimes appears to support basic expressions, depending on the
expression compared to the list length."
@values -min 1 -max 1
@values -min 3 -max 3
lvar -type string -help\
"name of list variable"
a -type indexexpression
@ -995,11 +1005,8 @@ namespace eval punk::lib {
e.g lzip {a b c d e} {1 2 3 4} {x y z}
-> {a 1 x} {b 2 y} {c 3 z} {d 4 {}} {3 {} {}}
"
@values -min 1 -max 1
lvar -type string -help\
"name of list variable"
a -type indexexpression
z -type indexexpression
@values -min 0 -max -1
list -type list -multiple 1 -optional 1
}]
}
proc lzip {args} {

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

@ -171,7 +171,7 @@ tcl::namespace::eval punk::nav::fs {
#It also seems common to cd when loading certain packages e.g tls from starkit.
#While in most/normal cases the library will cd back to the remembered working directory after only a brief time - there seem to be many opportunities for issues
#if the repl is used to launch/run a number of things in the one process
proc d/ {args} {
proc d/ {v args} {
variable VIRTUAL_CWD
set is_win [expr {"windows" eq $::tcl_platform(platform)}]
@ -211,17 +211,17 @@ tcl::namespace::eval punk::nav::fs {
#result for glob is count of matches - use dirfiles etc for script access to results
set result [list location $location dircount $dircount filecount $filecount symlinks $symlinkcount]
set resultsummary [list location $location dircount $dircount filecount $filecount symlinks $symlinkcount]
set filesizes [dict get $matchinfo filesizes]
if {[llength $filesizes]} {
set filesizes [lsearch -all -inline -not $filesizes na]
set filebytes [tcl::mathop::+ {*}$filesizes]
lappend result filebytes [punk::lib::format_number $filebytes]
lappend resultsummary filebytes [punk::lib::format_number $filebytes]
}
if {[punk::nav::fs::system::codethread_is_running]} {
if {[llength [info commands ::punk::console::titleset]]} {
#if ansi is off - punk::console::titleset will try 'local' api method - which can fail
catch {::punk::console::titleset [lrange $result 1 end]}
catch {::punk::console::titleset [lrange $resultsummary 1 end]}
}
}
if {[string match //zipfs:/* $location]} {
@ -229,21 +229,32 @@ tcl::namespace::eval punk::nav::fs {
} else {
set stripbase 1
}
if {$v eq "/"} {
#hack
dict set matchinfo files {}
dict set matchinfo filesizes {}
}
set out [dirfiles_dict_as_lines -stripbase $stripbase $matchinfo]
set chunklist [list]
lappend chunklist [list stdout "[punk::ansi::a+ brightwhite]$out[punk::ansi::a]\n"]
#set chunklist [list]
#lappend chunklist [list stdout "[punk::ansi::a+ brightwhite]$out[punk::ansi::a]\n"]
set result "[punk::ansi::a+ brightwhite]$out[punk::ansi::a]\n"
append result $resultsummary
if {[file normalize $VIRTUAL_CWD] ne [pwd]} {
lappend chunklist [list stderr "[punk::ansi::a+ red]PWD:[pwd] VIRTUAL_CWD:$VIRTUAL_CWD[punk::ansi::a]"]
}
lappend chunklist [list result $result]
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::nav::fs::system::emit_chunklist $chunklist
#lappend chunklist [list stderr "[punk::ansi::a+ red]PWD:[pwd] VIRTUAL_CWD:$VIRTUAL_CWD[punk::ansi::a]"]
puts stderr "[punk::ansi::a+ red]PWD:[pwd] VIRTUAL_CWD:$VIRTUAL_CWD[punk::ansi::a]"
}
#lappend chunklist [list result $result]
#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::nav::fs::system::emit_chunklist $chunklist
#}
#puts stdout "-->[ansistring VIEW $result]"
return $result
} else {
@ -258,7 +269,7 @@ tcl::namespace::eval punk::nav::fs {
if {$VIRTUAL_CWD eq "//zipfs:/" && ![string match //zipfs:/* [pwd]]} {
#exit back to last nonzipfs path that was in use
set VIRTUAL_CWD [pwd]
tailcall punk::nav::fs::d/
tailcall punk::nav::fs::d/ $v
}
#we need to use normjoin to allow navigation to //server instead of just to //server/share (//server browsing unimplemented - review)
@ -277,7 +288,7 @@ tcl::namespace::eval punk::nav::fs {
cd $up1
#set VIRTUAL_CWD [file normalize $a1]
}
tailcall punk::nav::fs::d/
tailcall punk::nav::fs::d/ $v
}
}
@ -287,7 +298,7 @@ tcl::namespace::eval punk::nav::fs {
if {[file type $a1] eq "directory"} {
cd $a1
#set VIRTUAL_CWD $a1
tailcall punk::nav::fs::d/
tailcall punk::nav::fs::d/ $v
}
}
}
@ -297,7 +308,7 @@ tcl::namespace::eval punk::nav::fs {
if {[file type $a1] eq "directory"} {
cd $a1
#set VIRTUAL_CWD [file normalize $a1]
tailcall punk::nav::fs::d/
tailcall punk::nav::fs::d/ $v
}
}
@ -321,7 +332,7 @@ tcl::namespace::eval punk::nav::fs {
set VIRTUAL_CWD $target
}
}
tailcall punk::nav::fs::d/
tailcall punk::nav::fs::d/ $v
}
set curdir $VIRTUAL_CWD
} else {
@ -334,7 +345,7 @@ tcl::namespace::eval punk::nav::fs {
set searchspec [lindex $args 0]
set result ""
set chunklist [list]
#set chunklist [list]
#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)
@ -389,7 +400,7 @@ tcl::namespace::eval punk::nav::fs {
#emit previous result
if {[dict size $this_result]} {
dict set this_result filebytes [punk::lib::format_number [dict get $this_result filebytes]]
lappend chunklist [list result $this_result]
#lappend chunklist [list result $this_result]
if {$result ne ""} {
append result \n
}
@ -424,33 +435,41 @@ tcl::namespace::eval punk::nav::fs {
}
set out [dirfiles_dict_as_lines -stripbase $stripbase $matchinfo]
lappend chunklist [list stdout "[punk::ansi::a+ brightwhite]$out[punk::ansi::a]\n"]
#lappend chunklist [list stdout "[punk::ansi::a+ brightwhite]$out[punk::ansi::a]\n"]
if {$result ne ""} {
append result \n
}
append result "[punk::ansi::a+ brightwhite]$out[punk::ansi::a]\n"
set last_location $location
}
#process final result
if {[dict size $this_result]} {
dict set this_result filebytes [punk::lib::format_number [dict get $this_result filebytes]]
lappend chunklist [list result $this_result]
#lappend chunklist [list result $this_result]
if {$result ne ""} {
append result \n
}
append result $this_result
}
if {[file normalize $VIRTUAL_CWD] ne [pwd]} {
lappend chunklist [list stderr "[punk::ansi::a+ red]PWD:[pwd] VIRTUAL_CWD:$VIRTUAL_CWD[punk::ansi::a]"]
#lappend chunklist [list stderr "[punk::ansi::a+ red]PWD:[pwd] VIRTUAL_CWD:$VIRTUAL_CWD[punk::ansi::a]"]
puts stderr "[punk::ansi::a+ red]PWD:[pwd] VIRTUAL_CWD:$VIRTUAL_CWD[punk::ansi::a]"
}
if {[punk::nav::fs::system::codethread_is_running]} {
if {![tsv::llength repl runchunks-$repl_runid]} {
#set ::punk::last_run_display $chunklist
tsv::lappend repl runchunks-$repl_runid {*}$chunklist
}
}
if {$repl_runid == 0} {
punk::nav::fs::system::emit_chunklist $chunklist
}
#if {[punk::nav::fs::system::codethread_is_running]} {
# if {![tsv::llength repl runchunks-$repl_runid]} {
# #set ::punk::last_run_display $chunklist
# tsv::lappend repl runchunks-$repl_runid {*}$chunklist
# }
#}
#if {$repl_runid == 0} {
# punk::nav::fs::system::emit_chunklist $chunklist
#}
return $result
}
}
@ -1479,6 +1498,26 @@ tcl::namespace::eval punk::nav::fs::system {
}
}
interp alias {} ./ {} punk::nav::fs::d/ /
interp alias {} d/ {} punk::nav::fs::d/ /
interp alias {} .// {} punk::nav::fs::d/ //
interp alias {} d// {} punk::nav::fs::d/ //
interp alias {} ../ {} punk::nav::fs::dd/
interp alias {} dd/ {} punk::nav::fs::dd/
interp alias {} vwd {} punk::nav::fs::vwd ;#return punk::nav::fs::VIRTUAL_CWD - and report to stderr pwd if different
interp alias {} dirlist {} punk::nav::fs::dirlist
interp alias {} dirfiles {} punk::nav::fs::dirfiles
interp alias {} dirfiles_dict {} punk::nav::fs::dirfiles_dict
interp alias {} ./new {} punk::nav::fs::d/new
interp alias {} d/new {} punk::nav::fs::d/new
interp alias {} ./~ {} punk::nav::fs::d/~
interp alias {} d/~ {} punk::nav::fs::d/~
interp alias {} x/ {} punk::nav::fs::x/
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::nav::fs [tcl::namespace::eval punk::nav::fs {

302
src/modules/punk/nav/ns-999999.0a1.0.tm

@ -0,0 +1,302 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use punkshell 'dev make' or bin/punkmake to update from <pkg>-buildversion.txt
# module template: shellspy/src/decktemplates/vendor/punk/modules/template_module-0.0.4.tm
#
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem.
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository.
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# (C) 2025
#
# @@ Meta Begin
# Application punk::nav::ns 999999.0a1.0
# Meta platform tcl
# Meta license MIT
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
package require Tcl 8.6-
tcl::namespace::eval punk::nav::ns {
variable PUNKARGS
variable ns_current
#allow presetting
if {![info exists ::punk::nav::ns::ns_current]} {
set ns_current ::
}
namespace path {::punk::ns}
proc ns/ {v {ns_or_glob ""} args} {
variable ns_current ;#change active ns of repl by setting ns_current
set ns_caller [uplevel 1 {::tcl::namespace::current}]
#puts stderr "ns_cur:$ns_current ns_call:$ns_caller"
set types [list all]
set nspathcommands 0
if {$v eq "/"} {
set types [list children]
}
if {$v eq "///"} {
set nspathcommands 1
}
set ns_or_glob [string map {:::: ::} $ns_or_glob]
#todo - cooperate with repl?
set out ""
if {$ns_or_glob eq ""} {
set is_absolute 1
set ns_queried $ns_current
set out [nslist -types $types -nspathcommands $nspathcommands [nsjoin $ns_current *]]
} else {
set is_absolute [string match ::* $ns_or_glob]
set has_globchars [regexp {[*?]} $ns_or_glob] ;#basic globs only?
if {$is_absolute} {
if {!$has_globchars} {
if {![nsexists $ns_or_glob]} {
error "cannot change to namespace $ns_or_glob"
}
set ns_current $ns_or_glob
set ns_queried $ns_current
tailcall ns/ $v ""
} else {
set ns_queried $ns_or_glob
set out [nslist -types $types -nspathcommands $nspathcommands $ns_or_glob]
}
} else {
if {!$has_globchars} {
set nsnext [nsjoin $ns_current $ns_or_glob]
if {![nsexists $nsnext]} {
error "cannot change to namespace $ns_or_glob"
}
set ns_current $nsnext
set ns_queried $nsnext
set out [nslist -types $types -nspathcommands $nspathcommands [nsjoin $nsnext *]]
} else {
set ns_queried [nsjoin $ns_current $ns_or_glob]
set out [nslist -types $types -nspathcommands $nspathcommands [nsjoin $ns_current $ns_or_glob]]
}
}
}
set ns_display "\n$ns_queried"
if {$ns_current eq $ns_queried} {
if {$ns_current in [info commands $ns_current] } {
if {![catch [list tcl::namespace::ensemble configure $ns_current] ensemble_info]} {
if {[llength $ensemble_info] > 0} {
#this namespace happens to match ensemble command.
#todo - keep cache of encountered ensembles from commands.. and examine namespace in the configure info.
set ns_display "\n[a+ yellow bold]$ns_current (ensemble)[a+]"
}
}
}
}
append out $ns_display
return $out
}
#create possibly nested namespace structure - but only if not already existant
proc n/new {args} {
variable ns_current
if {![llength $args]} {
error "usage: :/new <ns> \[<ns> ...\]"
}
set a1 [lindex $args 0]
set is_absolute [string match ::* $a1]
if {$is_absolute} {
set nspath [nsjoinall {*}$args]
} else {
if {[string match :* $a1]} {
puts stderr "n/new WARNING namespace with leading colon '$a1' is likely to have unexpected results"
}
set nspath [nsjoinall $ns_current {*}$args]
}
set ns_exists [nseval [nsprefix $nspath] [list ::tcl::namespace::exists [nstail $nspath] ]]
if {$ns_exists} {
error "Namespace $nspath already exists"
}
#tcl::namespace::eval [nsprefix $nspath] [list tcl::namespace::eval [nstail $nspath] {}]
nseval [nsprefix $nspath] [list ::tcl::namespace::eval [nstail $nspath] {}]
n/ $nspath
}
#nn/ ::/ nsup/ - back up one namespace level
proc nsup/ {v args} {
variable ns_current
if {$ns_current eq "::"} {
puts stderr "Already at global namespace '::'"
} else {
set out ""
set nsq [nsprefix $ns_current]
if {$v eq "/"} {
set out [get_nslist -match [nsjoin $nsq *] -types [list children]]
} else {
set out [get_nslist -match [nsjoin $nsq *] -types [list all]]
}
#set out [nslist [nsjoin $nsq *]]
set ns_current $nsq
append out "\n$ns_current"
return $out
}
}
}
#extra slash implies more verbosity (ie display commands instead of just nschildren)
interp alias {} n/ {} punk::nav::ns::ns/ /
interp alias {} n// {} punk::nav::ns::ns/ //
interp alias {} n/// {} punk::nav::ns::ns/ ///
interp alias {} n/new {} punk::nav::ns::n/new
interp alias {} nn/ {} punk::nav::ns::nsup/ /
interp alias {} nn// {} punk::nav::ns::nsup/ //
if 0 {
#we can't have ::/ without just plain / which is confusing.
interp alias {} :/ {} punk::nav::ns::ns/ /
interp alias {} :// {} punk::nav::ns::ns/ //
interp alias {} :/new {} punk::nav::ns::n/new
interp alias {} ::/ {} punk::nav::ns::nsup/ /
interp alias {} ::// {} punk::nav::ns::nsup/ //
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# Secondary API namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::nav::ns::lib {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
tcl::namespace::path [tcl::namespace::parent]
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#tcl::namespace::eval punk::nav::ns::system {
#}
# == === === === === === === === === === === === === === ===
# Sample 'about' function with punk::args documentation
# == === === === === === === === === === === === === === ===
tcl::namespace::eval punk::nav::ns {
tcl::namespace::export {[a-z]*} ;# Convention: export all lowercase
variable PUNKARGS
variable PUNKARGS_aliases
lappend PUNKARGS [list {
@id -id "(package)punk::nav::ns"
@package -name "punk::nav::ns" -help\
"Package
Description"
}]
namespace eval argdoc {
#namespace for custom argument documentation
proc package_name {} {
return punk::nav::ns
}
proc about_topics {} {
#info commands results are returned in an arbitrary order (like array keys)
set topic_funs [info commands [namespace current]::get_topic_*]
set about_topics [list]
foreach f $topic_funs {
set tail [namespace tail $f]
lappend about_topics [string range $tail [string length get_topic_] end]
}
#Adjust this function or 'default_topics' if a different order is required
return [lsort $about_topics]
}
proc default_topics {} {return [list Description *]}
# -------------------------------------------------------------
# get_topic_ functions add more to auto-include in about topics
# -------------------------------------------------------------
proc get_topic_Description {} {
punk::args::lib::tstr [string trim {
package punk::nav::ns
description to come..
} \n]
}
proc get_topic_License {} {
return "MIT"
}
proc get_topic_Version {} {
return "$::punk::nav::ns::version"
}
proc get_topic_Contributors {} {
set authors {<unspecified>}
set contributors ""
foreach a $authors {
append contributors $a \n
}
if {[string index $contributors end] eq "\n"} {
set contributors [string range $contributors 0 end-1]
}
return $contributors
}
proc get_topic_custom-topic {} {
punk::args::lib::tstr -return string {
A custom
topic
etc
}
}
# -------------------------------------------------------------
}
# we re-use the argument definition from punk::args::standard_about and override some items
set overrides [dict create]
dict set overrides @id -id "::punk::nav::ns::about"
dict set overrides @cmd -name "punk::nav::ns::about"
dict set overrides @cmd -help [string trim [punk::args::lib::tstr {
About punk::nav::ns
}] \n]
dict set overrides topic -choices [list {*}[punk::nav::ns::argdoc::about_topics] *]
dict set overrides topic -choicerestricted 1
dict set overrides topic -default [punk::nav::ns::argdoc::default_topics] ;#if -default is present 'topic' will always appear in parsed 'values' dict
set newdef [punk::args::resolved_def -antiglobs -package_about_namespace -override $overrides ::punk::args::package::standard_about *]
lappend PUNKARGS [list $newdef]
proc about {args} {
package require punk::args
#standard_about accepts additional choices for topic - but we need to normalize any abbreviations to full topic name before passing on
set argd [punk::args::parse $args withid ::punk::nav::ns::about]
lassign [dict values $argd] _leaders opts values _received
punk::args::package::standard_about -package_about_namespace ::punk::nav::ns::argdoc {*}$opts {*}[dict get $values topic]
}
}
# end of sample 'about' function
# == === === === === === === === === === === === === === ===
# -----------------------------------------------------------------------------
# register namespace(s) to have PUNKARGS,PUNKARGS_aliases variables checked
# -----------------------------------------------------------------------------
# variable PUNKARGS
# variable PUNKARGS_aliases
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::nav::ns
}
# -----------------------------------------------------------------------------
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::nav::ns [tcl::namespace::eval punk::nav::ns {
variable pkg punk::nav::ns
variable version
set version 999999.0a1.0
}]
return

3
src/modules/punk/nav/ns-buildversion.txt

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

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

@ -51,11 +51,11 @@ tcl::namespace::eval punk::ns {
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
tcl::namespace::eval punk::ns {
variable ns_current
#allow presetting
if {![info exists ::punk::ns::ns_current]} {
set ns_current ::
}
#variable ns_current
##allow presetting
#if {![info exists ::punk::ns::ns_current]} {
# set ns_current ::
#}
variable ns_re_cache [dict create] ;#cache regular expressions used in globmatchns
namespace export nsjoin nsprefix nstail nsparts nseval nschildren nsimport_noclobber corp pkguse cmdtype synopsis
@ -68,127 +68,9 @@ tcl::namespace::eval punk::ns {
#debug level punk.ns.compile 3
}
#leading colon makes it hard (impossible?) to call directly if not within the namespace
proc ns/ {v {ns_or_glob ""} args} {
variable ns_current ;#change active ns of repl by setting ns_current
set ns_caller [uplevel 1 {::tcl::namespace::current}]
#puts stderr "ns_cur:$ns_current ns_call:$ns_caller"
set types [list all]
set nspathcommands 0
if {$v eq "/"} {
set types [list children]
}
if {$v eq "///"} {
set nspathcommands 1
}
set ns_or_glob [string map {:::: ::} $ns_or_glob]
#todo - cooperate with repl?
set out ""
if {$ns_or_glob eq ""} {
set is_absolute 1
set ns_queried $ns_current
set out [nslist -types $types -nspathcommands $nspathcommands [nsjoin $ns_current *]]
} else {
set is_absolute [string match ::* $ns_or_glob]
set has_globchars [regexp {[*?]} $ns_or_glob] ;#basic globs only?
if {$is_absolute} {
if {!$has_globchars} {
if {![nsexists $ns_or_glob]} {
error "cannot change to namespace $ns_or_glob"
}
set ns_current $ns_or_glob
set ns_queried $ns_current
tailcall ns/ $v ""
} else {
set ns_queried $ns_or_glob
set out [nslist -types $types -nspathcommands $nspathcommands $ns_or_glob]
}
} else {
if {!$has_globchars} {
set nsnext [nsjoin $ns_current $ns_or_glob]
if {![nsexists $nsnext]} {
error "cannot change to namespace $ns_or_glob"
}
set ns_current $nsnext
set ns_queried $nsnext
set out [nslist -types $types -nspathcommands $nspathcommands [nsjoin $nsnext *]]
} else {
set ns_queried [nsjoin $ns_current $ns_or_glob]
set out [nslist -types $types -nspathcommands $nspathcommands [nsjoin $ns_current $ns_or_glob]]
}
}
}
set ns_display "\n$ns_queried"
if {$ns_current eq $ns_queried} {
if {$ns_current in [info commands $ns_current] } {
if {![catch [list tcl::namespace::ensemble configure $ns_current] ensemble_info]} {
if {[llength $ensemble_info] > 0} {
#this namespace happens to match ensemble command.
#todo - keep cache of encountered ensembles from commands.. and examine namespace in the configure info.
set ns_display "\n[a+ yellow bold]$ns_current (ensemble)[a+]"
}
}
}
}
append out $ns_display
return $out
}
#create possibly nested namespace structure - but only if not already existant
proc n/new {args} {
variable ns_current
if {![llength $args]} {
error "usage: :/new <ns> \[<ns> ...\]"
}
set a1 [lindex $args 0]
set is_absolute [string match ::* $a1]
if {$is_absolute} {
set nspath [nsjoinall {*}$args]
} else {
if {[string match :* $a1]} {
puts stderr "n/new WARNING namespace with leading colon '$a1' is likely to have unexpected results"
}
set nspath [nsjoinall $ns_current {*}$args]
}
set ns_exists [nseval [nsprefix $nspath] [list ::tcl::namespace::exists [nstail $nspath] ]]
if {$ns_exists} {
error "Namespace $nspath already exists"
}
#tcl::namespace::eval [nsprefix $nspath] [list tcl::namespace::eval [nstail $nspath] {}]
nseval [nsprefix $nspath] [list ::tcl::namespace::eval [nstail $nspath] {}]
n/ $nspath
}
#nn/ ::/ nsup/ - back up one namespace level
proc nsup/ {v args} {
variable ns_current
if {$ns_current eq "::"} {
puts stderr "Already at global namespace '::'"
} else {
set out ""
set nsq [nsprefix $ns_current]
if {$v eq "/"} {
set out [get_nslist -match [nsjoin $nsq *] -types [list children]]
} else {
set out [get_nslist -match [nsjoin $nsq *] -types [list all]]
}
#set out [nslist [nsjoin $nsq *]]
set ns_current $nsq
append out "\n$ns_current"
return $out
}
}
#todo - walk up each ns - testing for possibly weirdly named namespaces
#needed to use n/ to change to an oddly named namespace such as ":x"
@ -7152,7 +7034,7 @@ y" {return quirkykeyscript}
tailcall apply [list args $scriptblock $ns] {*}$arglist
}
} else {
set out [punk::ns::ns/ / $ns]
set out [punk::nav::ns::ns/ / $ns]
append out \n $ver
return $out
}
@ -7317,21 +7199,6 @@ y" {return quirkykeyscript}
interp alias {} cmdtype {} punk::ns::cmdtype
interp alias {} cmdtrace {} punk::ns::cmdtrace
#extra slash implies more verbosity (ie display commands instead of just nschildren)
interp alias {} n/ {} punk::ns::ns/ /
interp alias {} n// {} punk::ns::ns/ //
interp alias {} n/// {} punk::ns::ns/ ///
interp alias {} n/new {} punk::ns::n/new
interp alias {} nn/ {} punk::ns::nsup/ /
interp alias {} nn// {} punk::ns::nsup/ //
if 0 {
#we can't have ::/ without just plain / which is confusing.
interp alias {} :/ {} punk::ns::ns/ /
interp alias {} :// {} punk::ns::ns/ //
interp alias {} :/new {} punk::ns::n/new
interp alias {} ::/ {} punk::ns::nsup/ /
interp alias {} ::// {} punk::ns::nsup/ //
}
interp alias {} corp {} punk::ns::corp

34
src/modules/punk/repl-999999.0a1.0.tm

@ -429,8 +429,8 @@ proc repl::start {inchan args} {
}
incr startinstance
set loopinstance 0
if {[info exists ::punk::ns::ns_current]} {
set start_in_ns $::punk::ns::ns_current
if {[info exists ::punk::nav::ns::ns_current]} {
set start_in_ns $::punk::nav::ns::ns_current
} else {
set start_in_ns ::
}
@ -456,8 +456,8 @@ proc repl::start {inchan args} {
interp eval code {
namespace eval ::punk::repl::codethread {}
set ::punk::repl::codethread::is_running 1
namespace eval ::punk::ns::ns_current {}
set ::punk::ns::ns_current %ns1%
namespace eval ::punk::nav::ns::ns_current {}
set ::punk::nav::ns::ns_current %ns1%
}
}]
set commandstr ""
@ -2060,7 +2060,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
}
if {[chan eof $inputchan]} {
rputs stderr "todo - attempt restart of repl on input channel: $inputchan in next loop"
catch {set ::punk::ns::ns_current "::"}
catch {set ::punk::nav::ns::ns_current "::"}
#todo set flag to restart repl ?
} else {
rputs stderr "continuing.."
@ -2210,7 +2210,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
set lastrunchunks [tsv::get repl runchunks-[tsv::get repl runid]]
append info "lastrunchunks\n"
append info "chunks: [llength $lastrunchunks]\n"
append info "namespace: $::punk::ns::ns_current"
append info "namespace: $::punk::nav::ns::ns_current"
debug_repl_emit $info
} else {
proc debug_repl_emit {msg} {return}
@ -2300,7 +2300,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
#set status [catch {
# thread::send $
# uplevel 1 {namespace inscope $::punk::ns::ns_current $run_command_string}
# uplevel 1 {namespace inscope $::punk::nav::ns::ns_current $run_command_string}
#} raw_result]
}
@ -2417,18 +2417,20 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
#- lindex $command would sometimes fail
#if {[lindex $command 0] eq "runx"} {}
# set x [list\
# [string equal -length [string length "d/ "] "d/ " $commandstr] || \
# [string equal "d/\n" $commandstr] || \
# [string equal -length [string length "dd/ "] "dd/ " $commandstr] || \
# [string equal "dd/\n" $commandstr] || \
# [string equal -length [string length "./ "] "./ " $commandstr] || \
# [string equal "./\n" $commandstr] || \
# [string equal -length [string length "../ "] "../ " $commandstr] || \
# [string equal "../\n" $commandstr] || \
# ]
#temporary hack.
#todo - use happy path return options for non-primary result (like www package) ?
if {
[string equal -length [string length "d/ "] "d/ " $commandstr] || \
[string equal "d/\n" $commandstr] || \
[string equal -length [string length "dd/ "] "dd/ " $commandstr] || \
[string equal "dd/\n" $commandstr] || \
[string equal -length [string length "./ "] "./ " $commandstr] || \
[string equal "./\n" $commandstr] || \
[string equal -length [string length "../ "] "../ " $commandstr] || \
[string equal "../\n" $commandstr] || \
[string equal -length [string length "runx "] "runx " $commandstr] || \
[string equal -length [string length "sh_runx "] "sh_runx " $commandstr] || \
[string equal -length [string length "runout "] "runout " $commandstr] || \
@ -2716,7 +2718,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
}
if {[chan eof $inputchan]} {
rputs stderr "todo - attempt restart of repl on input channel: $inputchan in next loop"
catch {set ::punk::ns::ns_current "::"}
catch {set ::punk::nav::ns::ns_current "::"}
#todo set flag to restart repl ?
} else {
rputs stderr "continuing.."

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

@ -158,20 +158,21 @@ tcl::namespace::eval punk::repl::codethread {
if {[llength $::codeinterp::run_command_cache] > 2000} {
set ::codeinterp::run_command_cache [lrange $::codeinterp::run_command_cache 1750 end][unset ::codeinterp::run_command_cache]
}
if {[string first ":::" $::punk::ns::ns_current] >= 0} {
if {[string first ":::" $::punk::nav::ns::ns_current] >= 0} {
#support for browsing 'odd' (inadvisable) namespaces
#don't use 'namespace exists' - will conflate ::test::x with ::test:::x
#if {$::punk::ns::ns_current in [namespace children [punk::ns::nsprefix $::punk::ns::ns_current]} {
#if {$::punk::nav::ns::ns_current in [namespace children [punk::ns::nsprefix $::punk::nav::ns::ns_current]} {
#}
package require punk::ns
punk::ns::nseval_ifexists $::punk::ns::ns_current $::codeinterp::clonescript
package require punk::nav::ns
punk::ns::nseval_ifexists $::punk::nav::ns::ns_current $::codeinterp::clonescript
} else {
if {![namespace exists $::punk::ns::ns_current]} {
namespace eval $::punk::ns::ns_current {
puts stderr "Created namespace: $::punk::ns::ns_current"
if {![namespace exists $::punk::nav::ns::ns_current]} {
namespace eval $::punk::nav::ns::ns_current {
puts stderr "Created namespace: $::punk::nav::ns::ns_current"
}
}
tcl::namespace::inscope $::punk::ns::ns_current $::codeinterp::clonescript
tcl::namespace::inscope $::punk::nav::ns::ns_current $::codeinterp::clonescript
}
}
} result]

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

@ -4072,7 +4072,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
# \033 - octal. equivalently \x1b in hex which is more common in documentation
# empty list [a] should do reset - same for [a nonexistant]
# explicit reset at beginning of parameter list for a= (as opposed to a+)
set t [linsert $t[unset t] 0 0]
#set t [linsert $t[unset t] 0 0]
ledit t -1 -1 0
if {![llength $e]} {
set result "\x1b\[[join $t {;}]m"
} else {

9
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/lib-0.1.5.tm

@ -765,7 +765,7 @@ namespace eval punk::lib {
struct::list swap doesn't support 'end' offsets, and only
sometimes appears to support basic expressions, depending on the
expression compared to the list length."
@values -min 1 -max 1
@values -min 3 -max 3
lvar -type string -help\
"name of list variable"
a -type indexexpression
@ -995,11 +995,8 @@ namespace eval punk::lib {
e.g lzip {a b c d e} {1 2 3 4} {x y z}
-> {a 1 x} {b 2 y} {c 3 z} {d 4 {}} {3 {} {}}
"
@values -min 1 -max 1
lvar -type string -help\
"name of list variable"
a -type indexexpression
z -type indexexpression
@values -min 0 -max -1
list -type list -multiple 1 -optional 1
}]
}
proc lzip {args} {

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

@ -294,7 +294,8 @@ namespace eval punk::path {
}
} elseif {[lindex $parts 0] ne ""} {
#relpath a/b/c
set parts [linsert $parts 0 .]
#set parts [linsert $parts 0 .]
ledit parts -1 -1 .
set rootindex 0
#allow backtracking arbitrarily for leading .. entries - simplify where possible
#also need to stop possible conversion to absolute path
@ -1091,7 +1092,8 @@ namespace eval punk::path {
# loc is: ref/sub = sub
while {$reference_len > 0} {
set location [linsert $location 0 ..]
#set location [linsert $location 0 ..]
ledit location -1 -1 ..
incr reference_len -1
}
set location [file join {*}$location]

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

@ -5400,7 +5400,8 @@ tcl::namespace::eval textblock {
l-2 {
if {$lnum == 0} {
if {[lindex $line_chunks 0] eq ""} {
set line_chunks [linsert $line_chunks 2 $pad]
#set line_chunks [linsert $line_chunks 2 $pad]
ledit line_chunks 2 1 $pad
} else {
#set line_chunks [linsert $line_chunks 0 $pad]
ledit line_chunks -1 -1 $pad

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

@ -4072,7 +4072,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
# \033 - octal. equivalently \x1b in hex which is more common in documentation
# empty list [a] should do reset - same for [a nonexistant]
# explicit reset at beginning of parameter list for a= (as opposed to a+)
set t [linsert $t[unset t] 0 0]
#set t [linsert $t[unset t] 0 0]
ledit t -1 -1 0
if {![llength $e]} {
set result "\x1b\[[join $t {;}]m"
} else {

9
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/lib-0.1.5.tm

@ -765,7 +765,7 @@ namespace eval punk::lib {
struct::list swap doesn't support 'end' offsets, and only
sometimes appears to support basic expressions, depending on the
expression compared to the list length."
@values -min 1 -max 1
@values -min 3 -max 3
lvar -type string -help\
"name of list variable"
a -type indexexpression
@ -995,11 +995,8 @@ namespace eval punk::lib {
e.g lzip {a b c d e} {1 2 3 4} {x y z}
-> {a 1 x} {b 2 y} {c 3 z} {d 4 {}} {3 {} {}}
"
@values -min 1 -max 1
lvar -type string -help\
"name of list variable"
a -type indexexpression
z -type indexexpression
@values -min 0 -max -1
list -type list -multiple 1 -optional 1
}]
}
proc lzip {args} {

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

@ -294,7 +294,8 @@ namespace eval punk::path {
}
} elseif {[lindex $parts 0] ne ""} {
#relpath a/b/c
set parts [linsert $parts 0 .]
#set parts [linsert $parts 0 .]
ledit parts -1 -1 .
set rootindex 0
#allow backtracking arbitrarily for leading .. entries - simplify where possible
#also need to stop possible conversion to absolute path
@ -1091,7 +1092,8 @@ namespace eval punk::path {
# loc is: ref/sub = sub
while {$reference_len > 0} {
set location [linsert $location 0 ..]
#set location [linsert $location 0 ..]
ledit location -1 -1 ..
incr reference_len -1
}
set location [file join {*}$location]

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

@ -5400,7 +5400,8 @@ tcl::namespace::eval textblock {
l-2 {
if {$lnum == 0} {
if {[lindex $line_chunks 0] eq ""} {
set line_chunks [linsert $line_chunks 2 $pad]
#set line_chunks [linsert $line_chunks 2 $pad]
ledit line_chunks 2 1 $pad
} else {
#set line_chunks [linsert $line_chunks 0 $pad]
ledit line_chunks -1 -1 $pad

BIN
src/testansi/AT2DEMO.ANS.ZIP

Binary file not shown.

BIN
src/testansi/acdu0692.zip

Binary file not shown.

BIN
src/testansi/ansitoon.zip

Binary file not shown.

148
src/vendormodules/dictn-0.1.2.tm

@ -25,17 +25,46 @@
namespace eval dictn {
namespace export {[a-z]*}
namespace ensemble create
namespace eval argdoc {
variable PUNKARGS
#non-colour SGR codes
set I "\x1b\[3m" ;# [a+ italic]
set NI "\x1b\[23m" ;# [a+ noitalic]
set B "\x1b\[1m" ;# [a+ bold]
set N "\x1b\[22m" ;# [a+ normal]
set T "\x1b\[1\;4m" ;# [a+ bold underline]
set NT "\x1b\[22\;24m\x1b\[4:0m" ;# [a+ normal nounderline]
}
}
## ::dictn::append
#This can of course 'ruin' a nested dict if applied to the wrong element
# - i.e using the string op 'append' on an element that is itself a nested dict is analogous to the standard Tcl:
# %set list {a b {c d}}
# %append list x
# a b {c d}x
# IOW - don't do that unless you really know that's what you want.
#
tcl::namespace::eval ::dictn::argdoc {
lappend PUNKARGS [list {
@id -id ::dictn::append
@cmd -name dictn::append\
-summary\
"Append a single string to the value at dict path."\
-help\
"Append a single string to the value at a given dictionary path.
This can of course 'ruin' a nested dict if applied to the wrong element
- i.e using the string op 'append' on an element that is itself a nested dict is analogous to the standard Tcl:
%set list {a b {c d}}
%append list x
a b {c d}x
IOW - don't do that unless you really know that's what you want.
Note than unlike dict append - only a single value is accepted for appending.
"
@values -min 2 -max 3
dictvar -type string
path -type list
value -type any -default "" -optional 1
}]
}
proc ::dictn::append {dictvar path {value {}}} {
if {[llength $path] == 1} {
uplevel 1 [list dict append $dictvar $path $value]
@ -43,7 +72,7 @@ proc ::dictn::append {dictvar path {value {}}} {
upvar 1 $dictvar dvar
::set str [dict get $dvar {*}$path]
append str $val
append str $value
dict set dvar {*}$path $str
}
}
@ -73,6 +102,25 @@ proc ::dictn::for {keyvalvars dictval path body} {
proc ::dictn::get {dictval {path {}}} {
return [dict get $dictval {*}$path]
}
tcl::namespace::eval ::dictn::argdoc {
lappend PUNKARGS [list {
@id -id ::dictn::getn
@cmd -name dictn::getn\
-summary\
"Get one or more paths in a dict simultaneously."\
-help\
""
@values -min 1 -max -1
dictvar -type string
path -type list -multiple 1
}]
}
proc ::dictn::getn {dictval args} {
if {![llength $args]} {
return [::tcl::dict::get $dictval]
}
lmap path $args {::tcl::dict::get $dictval {*}$path}
}
if {[info commands ::tcl::dict::getdef] ne ""} {
@ -85,10 +133,18 @@ if {[info commands ::tcl::dict::getdef] ne ""} {
return [dict getdef $dictval {*}$path $default]
}
proc ::dictn::incr {dictvar path {increment {}} } {
if {$increment eq ""} {
::set increment 1
proc ::dictn::incr {dictvar path {increment 1} } {
upvar 1 $dictvar dvar
if {[llength $path] == 1} {
return [::tcl::dict::incr dvar $path $increment]
}
if {[::tcl::info::exists dvar]} {
::set increment [expr {[::tcl::dict::getdef $dvar {*}$path 0] + $increment}]
}
return [::tcl::dict::set dvar {*}$path $increment]
}
#test - compare disassembly
proc ::dictn::incr2 {dictvar path {increment 1} } {
if {[llength $path] == 1} {
uplevel 1 [list dict incr $dictvar $path $increment]
} else {
@ -233,6 +289,33 @@ proc ::dictn::set {dictvar path newval} {
return [dict set dvar {*}$path $newval]
}
tcl::namespace::eval ::dictn::argdoc {
lappend PUNKARGS [list {
@id -id ::dictn::setn
@cmd -name dictn::setn\
-summary\
"Set one or more paths in a dict to value(s)"\
-help\
""
@values -min 3 -max -1
dictvar -type string
path_newval -type {path newval} -multiple 1
}]
}
proc ::dictn::setn {dictvar args} {
if {[llength $args] == 0} {
error "dictn::setn requires at least one <path> <newval> pair"
}
if {[llength $args] % 2 != 0} {
error "dictn::setn requires trailing <path> <newval> pairs"
}
upvar 1 $dictvar dvar
foreach {p v} $args {
::tcl::dict::set dvar {*}$p $v
}
return $dvar
}
proc ::dictn::size {dictval {path {}}} {
return [dict size [dict get $dictval {*}$path]]
}
@ -312,6 +395,46 @@ proc ::dictn::values {dictval {path {}} {glob {}}} {
}
}
tcl::namespace::eval ::dictn::argdoc {
lappend PUNKARGS [list {
@id -id ::dictn::with
@cmd -name dictn::with\
-summary\
"Execute script for each key at dict path."\
-help\
"Execute the Tcl script in body with the value for each key within the
given key-path mapped to either variables or keys in a specified array.
If the name of an array variable is not supplied for arrayvar,
dictn with behaves like dict with, except that it accepts a list
for the possibly nested key-path instead of separate arguments.
The subkeys of the dict at the given key-path will create variables
in the calling scope.
If an arrayvar is passed, an array of that name in the calling
scope will be populated with keys and values from the subkeys and
values of the dict at the given key-path."
@form -form standard
@values -min 3 -max 3
dictvar -type string
path -type list
body -type string
@form -form array
@values -min 4 -max 4
dictvar -type string
path -type list
arrayvar -type string -help\
"Name of array variable in which key values are
stored for the given dict path.
This prevents key values being used as variable
names in the calling scope, instead capturing them
as keys in the single specified array at the calling
scope."
body -type string
}]
}
# Standard form:
#'dictn with dictVariable path body'
#
@ -351,7 +474,10 @@ proc ::dictn::with {dictvar path args} {
::tcl::namespace::eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::dictn
}

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

@ -4072,7 +4072,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
# \033 - octal. equivalently \x1b in hex which is more common in documentation
# empty list [a] should do reset - same for [a nonexistant]
# explicit reset at beginning of parameter list for a= (as opposed to a+)
set t [linsert $t[unset t] 0 0]
#set t [linsert $t[unset t] 0 0]
ledit t -1 -1 0
if {![llength $e]} {
set result "\x1b\[[join $t {;}]m"
} else {

9
src/vfs/_vfscommon.vfs/modules/punk/lib-0.1.5.tm

@ -765,7 +765,7 @@ namespace eval punk::lib {
struct::list swap doesn't support 'end' offsets, and only
sometimes appears to support basic expressions, depending on the
expression compared to the list length."
@values -min 1 -max 1
@values -min 3 -max 3
lvar -type string -help\
"name of list variable"
a -type indexexpression
@ -995,11 +995,8 @@ namespace eval punk::lib {
e.g lzip {a b c d e} {1 2 3 4} {x y z}
-> {a 1 x} {b 2 y} {c 3 z} {d 4 {}} {3 {} {}}
"
@values -min 1 -max 1
lvar -type string -help\
"name of list variable"
a -type indexexpression
z -type indexexpression
@values -min 0 -max -1
list -type list -multiple 1 -optional 1
}]
}
proc lzip {args} {

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

@ -294,7 +294,8 @@ namespace eval punk::path {
}
} elseif {[lindex $parts 0] ne ""} {
#relpath a/b/c
set parts [linsert $parts 0 .]
#set parts [linsert $parts 0 .]
ledit parts -1 -1 .
set rootindex 0
#allow backtracking arbitrarily for leading .. entries - simplify where possible
#also need to stop possible conversion to absolute path
@ -1091,7 +1092,8 @@ namespace eval punk::path {
# loc is: ref/sub = sub
while {$reference_len > 0} {
set location [linsert $location 0 ..]
#set location [linsert $location 0 ..]
ledit location -1 -1 ..
incr reference_len -1
}
set location [file join {*}$location]

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

@ -922,14 +922,18 @@ tcl::namespace::eval punk::safe::system {
set where [lsearch -exact $access_path [info library]]
if {$where < 0} {
# not found, add it.
set access_path [linsert $access_path 0 [info library]]
#set access_path [linsert $access_path 0 [info library]]
ledit access_path -1 -1 [info library]
Log $child "tcl_library was not in auto_path,\
added it to child's access_path" NOTICE
} elseif {$where != 0} {
# not first, move it first
set access_path [linsert \
[lreplace $access_path $where $where] \
0 [info library]]
#set access_path [linsert \
# [lreplace $access_path $where $where] \
# 0 [info library]]
ledit access_path $where $where
ledit access_path -1 -1 [info library]
Log $child "tcl_libray was not in first in auto_path,\
moved it to front of child's access_path" NOTICE
}

3
src/vfs/_vfscommon.vfs/modules/textblock-0.1.3.tm

@ -5400,7 +5400,8 @@ tcl::namespace::eval textblock {
l-2 {
if {$lnum == 0} {
if {[lindex $line_chunks 0] eq ""} {
set line_chunks [linsert $line_chunks 2 $pad]
#set line_chunks [linsert $line_chunks 2 $pad]
ledit line_chunks 2 1 $pad
} else {
#set line_chunks [linsert $line_chunks 0 $pad]
ledit line_chunks -1 -1 $pad

Loading…
Cancel
Save