Browse Source

ansi colour,textblock::table,textblock::frame, and repl fixes

master
Julian Noble 6 months ago
parent
commit
7fd49bb2e2
  1. 67
      src/modules/oolib-0.1.2.tm
  2. 402
      src/modules/punk/ansi-999999.0a1.0.tm
  3. 4
      src/modules/punk/basictelnet-999999.0a1.0.tm
  4. 48
      src/modules/punk/repl-0.1.tm
  5. 569
      src/modules/textblock-999999.0a1.0.tm

67
src/modules/oolib-0.1.1.tm → src/modules/oolib-0.1.2.tm

@ -2,13 +2,13 @@
#
package provide oolib [namespace eval oolib {
variable version
set version 0.1.1
set version 0.1.2
}]
namespace eval oolib {
oo::class create collection {
variable o_data ;#dict
variable o_alias
#variable o_alias
constructor {} {
set o_data [dict create]
}
@ -103,37 +103,38 @@ namespace eval oolib {
}
}
#review - see patternlib. Is the intention for aliases to be configurable independent of whether the target exists?
method alias {newAlias existingKeyOrAlias} {
if {[string is integer -strict $newAlias]} {
error "[self object] collection key alias cannot be integer"
}
if {[string length $existingKeyOrAlias]} {
set o_alias($newAlias) $existingKeyOrAlias
} else {
unset o_alias($newAlias)
}
}
method aliases {{key ""}} {
if {[string length $key]} {
set result [list]
foreach {n v} [array get o_alias] {
if {$v eq $key} {
lappend result $n $v
}
}
return $result
} else {
return [array get o_alias]
}
}
#if the supplied index is an alias, return the underlying key; else return the index supplied.
method realKey {idx} {
if {[catch {set o_alias($idx)} key]} {
return $idx
} else {
return $key
}
}
#review - what is the point of alias anyway? - why slow down other operations when a variable can hold a keyname perfectly well?
#method alias {newAlias existingKeyOrAlias} {
# if {[string is integer -strict $newAlias]} {
# error "[self object] collection key alias cannot be integer"
# }
# if {[string length $existingKeyOrAlias]} {
# set o_alias($newAlias) $existingKeyOrAlias
# } else {
# unset o_alias($newAlias)
# }
#}
#method aliases {{key ""}} {
# if {[string length $key]} {
# set result [list]
# foreach {n v} [array get o_alias] {
# if {$v eq $key} {
# lappend result $n $v
# }
# }
# return $result
# } else {
# return [array get o_alias]
# }
#}
##if the supplied index is an alias, return the underlying key; else return the index supplied.
#method realKey {idx} {
# if {[catch {set o_alias($idx)} key]} {
# return $idx
# } else {
# return $key
# }
#}
method add {value key} {
if {[string is integer -strict $key]} {
error "[self object] collection key must not be an integer. Use another structure if integer keys required"

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

@ -106,7 +106,7 @@ namespace eval punk::ansi::class {
#overflow is a different concept - perhaps not particularly congruent with the idea of the textblock as a mini terminal emulator.
#overflow effectively auto-expands the block(terminal?) width
#overflow and wrap both being true won't make sense unless we implement a max_overflow concept
set o_rendered [overtype::left -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
set o_rendered [overtype::renderspace -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
if {$cksum eq "not-done"} {
#if dimensions changed - the checksum won't have been done
set o_rendered_what [$o_ansistringobj checksum]
@ -129,7 +129,7 @@ namespace eval punk::ansi::class {
set o_dimensions $dimensions
set rendered [overtype::left -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
set rendered [overtype::renderspace -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
return $rendered
}
method render_to_input_line {args} {
@ -175,7 +175,7 @@ namespace eval punk::ansi::class {
if {$opt_minus ne "0"} {
set chunk [string range $chunk 0 end-$opt_minus]
}
set rendered [overtype::left -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" $chunk]
set rendered [overtype::renderspace -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" $chunk]
set marker ""
for {set i 1} {$i <= $w} {incr i} {
if {$i % 10 == 0} {
@ -190,13 +190,13 @@ namespace eval punk::ansi::class {
set xline [lindex $rlines $x]\n
set xlinev [ansistring VIEWSTYLE $xline]
set xlinev [string map $maplf $xlinev]
set xlinedisplay [overtype::left -wrap 1 -width $w -height 1 "" $xlinev]
set xlinedisplay [overtype::renderspace -wrap 1 -width $w -height 1 "" $xlinev]
::append rendered \n $xlinedisplay
set chunk [ansistring VIEWSTYLE $chunk]
set chunk [string map $maplf $chunk]
#keep chunkdisplay narrower - leave at 80 or it will get unwieldy for larger image widths
set chunkdisplay [overtype::left -wrap 1 -width 80 -height 1 "" $chunk]
set chunkdisplay [overtype::renderspace -wrap 1 -width 80 -height 1 "" $chunk]
set renderheight [llength [split $rendered \n]]
set chunkdisplay_lines [split $chunkdisplay \n]
set chunkdisplay_tail [lrange $chunkdisplay_lines end-$renderheight end]
@ -215,14 +215,87 @@ namespace eval punk::ansi::class {
method viewlines {} {
return [ansistring VIEW [$o_ansistringobj get]]
}
method viewcodes {} {
return [ansistring VIEWCODES [$o_ansistringobj get]]
method viewcodes {args} {
set defaults [list\
-lf 0\
-vt 0\
-width "auto"\
]
foreach {k v} $args {
switch -- $k {
-lf - -vt - -width {}
default {
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_vt [dict get $opts -vt]
set opts_width [dict get $opts -width]
if {$opts_width eq ""} {
return [ansistring VIEWCODES -lf $opts_lf -vt $opts_vt [$o_ansistringobj get]]
} elseif {$opts_width eq "auto"} {
lassign [punk::console::get_size] _cols columns _rows rows
set displaycols [expr {$columns -4}] ;#review
return [overtype::renderspace -width $displaycols -wrap 1 "" [ansistring VIEWCODES -lf $opts_lf -vt $opts_vt [$o_ansistringobj get]]]
} elseif {[string is integer -strict $opts_width] && $opts_width > 0} {
return [overtype::renderspace -width $opts_width -wrap 1 "" [ansistring VIEWCODES -lf $opts_lf -vt $opts_vt [$o_ansistringobj get]]]
} else {
error "viewcodes unrecognised value for -width. Try auto or a positive integer"
}
}
method viewchars {args} {
set defaults [list\
-width "auto"\
]
foreach {k v} $args {
switch -- $k {
-width {}
default {
error "viewchars unrecognised option '$k'. Known options [dict keys $defaults]"
}
method viewchars {} {
}
}
set opts [dict merge $defaults $args]
set opts_width [dict get $opts -width]
if {$opts_width eq ""} {
return [punk::ansi::stripansiraw [$o_ansistringobj get]]
} elseif {$opts_width eq "auto"} {
lassign [punk::console::get_size] _cols columns _rows rows
set displaycols [expr {$columns -4}] ;#review
return [overtype::renderspace -width $displaycols -wrap 1 "" [punk::ansi::stripansiraw [$o_ansistringobj get]]]
} elseif {[string is integer -strict $opts_width] && $opts_width > 0} {
return [overtype::renderspace -width $opts_width -wrap 1 "" [punk::ansi::stripansiraw [$o_ansistringobj get]]]
} else {
error "viewchars unrecognised value for -width. Try auto or a positive integer"
}
}
method viewstyle {args} {
set defaults [list\
-width "auto"\
]
foreach {k v} $args {
switch -- $k {
-width {}
default {
error "viewstyle unrecognised option '$k'. Known options [dict keys $defaults]"
}
}
}
method viewstyle {} {
set opts [dict merge $defaults $args]
set opts_width [dict get $opts -width]
if {$opts_width eq ""} {
return [ansistring VIEWSTYLE [$o_ansistringobj get]]
} elseif {$opts_width eq "auto"} {
lassign [punk::console::get_size] _cols columns _rows rows
set displaycols [expr {$columns -4}] ;#review
return [overtype::renderspace -width $displaycols -wrap 1 "" [ansistring VIEWSTYLE [$o_ansistringobj get]]]
} elseif {[string is integer -strict $opts_width] && $opts_width > 0} {
return [overtype::renderspace -width $opts_width -wrap 1 "" [ansistring VIEWSTYLE [$o_ansistringobj get]]]
} else {
error "viewstyle unrecognised value for -width. Try auto or a positive integer"
}
}
method append_noreturn {ansistring} {
$o_ansistringobj append $ansistring
@ -456,7 +529,7 @@ namespace eval punk::ansi {
set ansidata [fcat -encoding $encoding $fname]
set obj [punk::ansi::class::class_ansi new $ansidata]
if {$test_mode} {
if {$encoding eq "cp437"} {
set result [$obj rendertest $dimensions]
} else {
set result [$obj render $dimensions]
@ -600,7 +673,6 @@ namespace eval punk::ansi {
#[para]Alternate graphics modes will be stripped - exposing the raw characters as they appear without graphics mode.
#[para]ie instead of a horizontal line you may see: qqqqqq
join [::punk::ansi::ta::split_at_codes $text] ""
}
proc stripansi1 {text} {
@ -1061,7 +1133,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
dodgerblue2\
green4\
springgreen4\
turquise4\
turquoise4\
deepskyblue3\
deepskyblue3\
dodgerblue1\
@ -1459,7 +1531,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
append out [a]
return [string trimleft $out \n]
}
proc colourtable_216_names {} {
#x6 is reasonable from a width (124 screen cols) and colour viewing perspective
proc colourtable_216_names {{cols 6}} {
set out ""
#use the reverse lookup dict - the original xterm_names list has duplicates - we want the disambiguated (potentially suffixed) names
variable TERM_colour_map_reverse
@ -1470,7 +1544,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
$t configure -show_seps 0 -show_edge 0
for {set i 16} {$i <=231} {incr i} {
set cname [dict get $TERM_colour_map_reverse $i] ;#use term-cname etc instead of term$i - may as well let a+ cache the call by name as the preferred? option
if {[llength $row]== 8} {
if {[llength $row]== $cols} {
lappend rows $row
set row [list]
}
@ -1492,6 +1566,112 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
append out [a]
return [string trimleft $out \n]
}
proc colourtable_term_pastel {} {
set out ""
set rows [list]
#see https://www.hackitu.de/termcolor256/
lappend rows {59 95 131 167 174 181 188}
lappend rows {59 95 131 173 180 187 188}
lappend rows {59 95 137 179 186 187 188}
lappend rows {59 101 143 185 186 187 188}
lappend rows {59 65 107 149 186 187 188}
lappend rows {59 65 71 113 150 187 188}
lappend rows {59 65 71 77 114 151 188}
lappend rows {59 65 71 78 115 152 188}
lappend rows {59 65 72 79 116 152 188}
lappend rows {59 66 73 80 116 152 188}
lappend rows {59 60 67 74 116 152 188}
lappend rows {59 60 61 68 110 152 188}
lappend rows {59 60 61 62 104 146 188}
lappend rows {59 60 61 98 140 182 188}
lappend rows {59 60 97 134 176 182 188}
lappend rows {59 96 133 170 176 182 188}
lappend rows {59 95 132 169 176 182 188}
lappend rows {59 95 131 168 175 182 188}
set t [textblock::class::table new]
$t configure -show_seps 0 -show_edge 0
set fg "web-black"
foreach r $rows {
set rowcells [list]
foreach cnum $r {
lappend rowcells "[a+ $fg Term-$cnum][format %3s $cnum] "
}
$t add_row $rowcells
}
append out [$t print]
$t destroy
set pastel8 [list 102 138 144 108 109 103 139 145]
set p8 ""
foreach cnum $pastel8 {
append p8 "[a+ $fg Term-$cnum][format %3s $cnum] "
}
append p8 [a]\n
append out \n $p8
return $out
}
proc colourtable_term_rainbow {} {
set out ""
set rows [list]
set fgwhite [list 16 52 88 124 160 22 17 18 19 20 21 57 56 93 55 92 54 91 53 90 89 126 88 125 124 160]
#see https://www.hackitu.de/termcolor256/
lappend rows {16 52 88 124 160 196 203 210 217 224 231}
lappend rows {16 52 88 124 160 202 209 216 223 230 231}
lappend rows {16 52 88 124 166 208 215 222 229 230 231}
lappend rows {16 52 88 130 172 214 221 228 229 230 231}
lappend rows {16 52 94 136 178 220 227 227 228 230 231}
lappend rows {16 58 100 142 184 226 227 228 228 230 231}
lappend rows {16 22 64 106 148 190 227 228 229 230 231}
lappend rows {16 22 28 70 112 154 191 228 229 230 231}
lappend rows {16 22 28 34 76 118 155 192 229 230 231}
lappend rows {16 22 28 34 40 82 119 156 193 230 231}
lappend rows {16 22 28 34 40 46 83 120 157 194 231}
lappend rows {16 22 28 34 40 47 84 121 158 195 231}
lappend rows {16 22 28 34 41 48 85 122 158 195 231}
lappend rows {16 22 28 35 42 49 86 123 159 195 231}
lappend rows {16 22 29 36 43 50 87 123 159 195 231}
lappend rows {16 23 30 37 44 51 87 123 159 195 231}
lappend rows {16 17 24 31 38 45 87 123 159 195 231}
lappend rows {16 17 18 25 32 39 81 123 159 195 231}
lappend rows {16 17 18 19 26 33 75 117 159 195 231}
lappend rows {16 17 18 19 20 27 69 111 153 195 231}
lappend rows {16 17 18 19 20 21 63 105 147 189 231}
lappend rows {16 17 18 19 20 57 99 141 183 225 231}
lappend rows {16 17 18 19 56 93 135 177 219 225 231}
lappend rows {16 17 18 55 92 129 171 213 219 225 231}
lappend rows {16 17 54 91 128 165 207 213 219 225 231}
lappend rows {16 53 90 127 164 201 207 213 219 225 231}
lappend rows {16 52 89 126 163 200 207 213 219 225 231}
lappend rows {16 52 88 125 162 199 206 213 219 225 231}
lappend rows {16 52 88 124 161 198 205 212 219 225 231}
lappend rows {16 52 88 124 160 197 204 211 218 225 231}
set t [textblock::class::table new]
$t configure -show_seps 0 -show_edge 0
foreach r $rows {
set rowcells [list]
foreach cnum $r {
if {$cnum in $fgwhite} {
set fg "web-white"
} else {
set fg "web-black"
}
lappend rowcells "[a+ $fg Term-$cnum][format %3s $cnum] "
}
$t add_row $rowcells
}
append out [$t print]
$t destroy
return $out
}
#24 greys of 256
proc colourblock_24 {} {
set out ""
@ -1548,7 +1728,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
# $WEB_colour_map_gray\
#]
proc colourtable_web {{groups *}} {
set all_groupnames [list basic pink red orange yellow brown purple blue cyan green white gray]
#set all_groupnames [list basic pink red orange yellow brown purple blue cyan green white gray]
set all_groupnames [list basic brown yellow red pink orange purple blue cyan green white gray]
switch -- $groups {
"" - * {
set show_groups $all_groupnames
@ -1696,7 +1877,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
set map2 [colourmap2 $bgname]
set map2 [overtype::centre -transparent 1 $map2 "[a black $bgname]High-intensity colours[a]"]
append out [textblock::join $indent [textblock::join $map1 $map2]] \n
append out "[a+ web-white]216 colours of 256 terminal colours (To see names, use: a? term)[a]" \n
append out "[a+ web-white]216 colours of 256 terminal colours (To see names, use: a? term ?pastel? ?rainbow?)[a]" \n
append out [textblock::join $indent [colourblock_216]] \n
append out "[a+ web-white]24 Greyscale colours[a]" \n
append out [textblock::join $indent [colourblock_24]] \n
@ -1709,6 +1890,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
#dict set WEB_colour_map mediumvioletred 199-21-133 ;# #C71585
append out [textblock::join $indent "Example: \[a+ rgb-199-21-133\]text\[a] -> [a+ rgb-199-21-133]text[a]"] \n
append out [textblock::join $indent "Example: \[a+ Rgb#C71585\]text\[a] -> [a+ Rgb#C71585]text[a]"] \n
append out [textblock::join $indent "Examine a sequence: a? bold rgb-46-139-87 Rgb#C71585 "] \n
append out \n
append out "[a+ web-white]Web colours[a]" \n
append out [textblock::join $indent "To see all names use: a? web"] \n
@ -1730,12 +1912,34 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
} else {
switch -- [lindex $args 0] {
term {
set termargs [lrange $args 1 end]
foreach ta $termargs {
switch -- $ta {
pastel - rainbow {}
default {error "unrecognised term option '$ta'. Known values: pastel rainbow"}
}
}
set out "16 basic colours\n"
append out [colourtable_16_names] \n
append out "216 colours\n"
append out [colourtable_216_names] \n
append out "24 greyscale colours\n"
append out [colourtable_24_names]
foreach ta $termargs {
switch -- $ta {
pastel {
append out \n
append out "Pastel Colour Space (punk::ansi::colourtable_term_pastel)\n"
append out [colourtable_term_pastel]
}
rainbow {
append out \n
append out "Rainbow Colours (punk::ansi::colourtable_term_rainbow)\n"
append out [colourtable_term_rainbow]
}
}
}
append out "\nNote: The 256 term colours especially 0-15 may be altered by terminal pallette settings or ansi OSC 4 codes, so specific RGB values are unavailable"
return $out
}
web {
@ -1748,20 +1952,130 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
return $out
}
}
set result [list]
set map [dict merge $SGR_setting_map $SGR_colour_map]
set rmap [lreverse $map]
variable WEB_colour_map
variable X11_colour_map
variable TERM_colour_map
variable TERM_colour_map_reverse
variable SGR_map
set t [textblock::class::table new]
$t configure -show_edge 0 -show_seps 1 -show_header 0
set resultlist [list]
foreach i $args {
if {[string is integer -strict $i]} {
if {[dict exists $rmap $i]} {
lappend result $i [dict get $rmap $i]
set f4 [string range $i 0 3]
set s [a+ $i]sample
switch -- $f4 {
web- - Web- - WEB- {
set tail [string tolower [string trim [string range $i 4 end] -]]
if {[dict exists $WEB_colour_map $tail]} {
set dec [dict get $WEB_colour_map $tail]
set hex [colour_dec2hex $dec]
set descr "$hex $dec"
} else {
set descr "UNKNOWN colour for web"
}
$t add_row [list $i $descr $s [ansistring VIEW $s]]
}
term - Term {
set tail [string trim [string range $i 4 end] -]
if {[string is integer -strict $tail]} {
if {$tail < 256} {
set descr "[dict get $TERM_colour_map_reverse $tail]"
} else {
set descr "Invalid (> 255)"
}
} else {
set tail [string tolower $tail]
if {[dict exists $TERM_colour_map $tail]} {
set descr [dict get $TERM_colour_map $tail]
} else {
set descr "UNKNOWN colour for term"
}
}
$t add_row [list $i $descr $s [ansistring VIEW $s]]
}
x11- - X11- {
set tail [string tolower [string trim [string range $i 4 end] -]]
if {[dict exists $X11_colour_map $tail]} {
set dec [dict get $X11_colour_map $tail]
set hex [colour_dec2hex $dec]
set descr "$hex $dec"
} else {
set descr "UNKNOWN colour for x11"
}
$t add_row [list $i $descr $s [ansistring VIEW $s]]
}
rgb- - Rgb- - RGB- -
rgb0 - rgb1 - rgb2 - rgb3 - rgb4 - rgb5 - rgb6 - rgb7 - rgb8 - rgb9 -
Rgb0 - Rgb1 - Rgb2 - Rgb3 - Rgb4 - Rgb5 - Rgb6 - Rgb7 - Rgb8 - Rgb9 -
RGB0 - RGB1 - RGB2 - RGB3 - RGB4 - RGB5 - RGB6 - RGB7 - RGB8 - RGB9 -
rgb# - Rgb# - RGB# {
if {[string index $i 3] eq "#"} {
set tail [string range $i 4 end]
set hex $tail
set dec [colour_hex2dec $hex]
set info $dec ;#show opposite type as first line of info col
} else {
set tail [string trim [string range $i 3 end] -]
set dec $tail
set hex [colour_dec2hex $dec]
set info $hex
}
set webcolours_i [lsearch -all $WEB_colour_map $dec]
set webcolours [list]
foreach ci $webcolours_i {
lappend webcolours [lindex $WEB_colour_map $ci-1]
}
set x11colours [list]
set x11colours_i [lsearch -all $X11_colour_map $dec]
foreach ci $x11colours_i {
set c [lindex $X11_colour_map $ci-1]
if {$c ni $webcolours} {
lappend x11colours $c
}
}
foreach c $webcolours {
append info \n web-$c
}
foreach c $x11colours {
append info \n x11-$c
}
$t add_row [list $i "$info" $s [ansistring VIEW $s]]
}
default {
if {[string is integer -strict $i]} {
set rmap [lreverse $SGR_map]
$t add_row [list $i "SGR [dict get $rmap $i]" $s [ansistring VIEW $s]]
} else {
if {[dict exists $SGR_map $i]} {
$t add_row [list $i "SGR [dict get $SGR_map $i]" $s [ansistring VIEW $s]]
} else {
if {[dict exists $map $i]} {
lappend result $i [dict get $map $i]
$t add_row [list $i UNKNOWN $s [ansistring VIEW $s]]
}
}
}
}
}
set ansi [a+ {*}$args]
set s ${ansi}sample
set merged [punk::ansi::codetype::sgr_merge_singles [list $ansi]]
set s2 ${merged}sample
#lappend resultlist "RESULT: [a+ {*}$args]sample[a]"
$t add_row [list RESULT "" $s [ansistring VIEW $s]]
if {$ansi ne $merged} {
if {[string length $merged] < [string length $ansi]} {
#only refer to redundancies if shorter - merge may reorder - REVIEW
set warning "[a+ web-red Web-yellow]REDUNDANCIES FOUND"
} else {
set warning ""
}
$t add_row [list MERGED $warning $s2 [ansistring VIEW $s2]]
}
set result [$t print]
$t destroy
return $result
}
}
@ -1788,13 +2102,33 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
set sgr_cache [dict create]
return "sgr_cache cleared"
}
if {[catch {
set termwidth [dict get [punk::console::get_size] columns]
} errM]} {
set termwidth 80
}
set termwidth [expr [$termwidth -3]]
set out ""
set linelen 0
set RST [a]
set lines [list]
set line ""
#todo - terminal width? table?
dict for {key ansi} $sgr_cache {
append out "$ansi$key$RST "
set thislen [expr {[string length $key]+1}]
if {$linelen + $thislen >= $termwidth-1} {
lappend lines $line
set line "$ansi$key$RST "
set linelen $thislen
} else {
append line "$ansi$key$RST "
incr linelen $thislen
}
}
if {[string length $line]} {
lappend lines $line
}
return $out\n
return [join $lines \n]
}
proc a+ {args} {
@ -1922,7 +2256,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
switch -- $i {
Brightblack {lappend t 100}
Brightred {lappend t 101}
Brightgreen {lappend t 101}
Brightgreen {lappend t 102}
Brightyellow {lappend t 103}
Brightblue {lappend t 104}
Brightpurple {lappend t 105}
@ -2154,7 +2488,7 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
switch -- $i {
Brightblack {lappend t 100}
Brightred {lappend t 101}
Brightgreen {lappend t 101}
Brightgreen {lappend t 102}
Brightyellow {lappend t 103}
Brightblue {lappend t 104}
Brightpurple {lappend t 105}
@ -2953,10 +3287,11 @@ namespace eval punk::ansi {
set defaults [dict create\
-filter_fg 0\
-filter_bg 0\
-filter_reset 0\
]
dict for {k v} $args {
switch -- $k {
-filter_fg - -filter_bg {}
-filter_fg - -filter_bg - -filter_reset {}
default {
error "sgr_merge unknown option '$k'. Known options [dict keys $defaults]"
}
@ -3015,9 +3350,11 @@ namespace eval punk::ansi {
set codeint [string trimleft [lindex $paramsplit 0] 0]
switch -- $codeint {
"" - 0 {
if {![dict get $opts -filter_reset]} {
set codestate $codestate_initial
set did_reset 1
}
}
1 {
#bold
if {[llength $paramsplit] == 1} {
@ -3086,7 +3423,7 @@ namespace eval punk::ansi {
}
21 {
#ECMA-48 double underline - some terminals use as not-bold. For now we won't support that.
dict set doubleunderline 21
dict set codestate doubleunderline 21
}
22 {
#normal intensity
@ -4866,9 +5203,12 @@ namespace eval punk::ansi::ansistring {
if {$opt_cr} {
dict set visuals_opt CR [list \x0d \u240d]
}
if {$opt_lf} {
if {$opt_lf == 1} {
dict set visuals_opt LF [list \x0a \u240a]
}
if {$opt_lf == 2} {
dict set visuals_opt LF [list \x0a \u240a\n]
}
if {$opt_vt} {
dict set visuals_opt VT [list \x0b \u240b]
}

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

@ -528,7 +528,7 @@ namespace eval punk::basictelnet {
# -- --- --- ---
set tailinfo ""
if {[string length $nextwaiting]} {
set waitingdisplay [overtype::left -wrap 1 -width 77 -height 1 "" [ansistring VIEW -lf 1 -vt 1 $nextwaiting]]
set waitingdisplay [overtype::renderspace -wrap 1 -width 77 -height 1 "" [ansistring VIEW -lf 1 -vt 1 $nextwaiting]]
set tailinfo "[a+ red]from waiting:\n $waitingdisplay[a]"
}
::punk::basictelnet::add_debug "[a+ Yellow black]from stdin sending: [ansistring VIEW -lf 1 -vt 1 $chunk][a]\n$tailinfo\n" stdin $sock
@ -626,7 +626,7 @@ namespace eval punk::basictelnet {
#set rawview [ansistring VIEW -lf 1 -vt 1 [encoding convertfrom $encoding_guess $data]]
set rawview [ansistring VIEW -lf 1 -vt 1 $data]
#set viewblock [overtype::left -wrap 1 -width 78 -height 4 "" $rawview]
set viewblock [overtype::left -experimental test_mode -wrap 1 -width 78 -height 4 "" $rawview]
set viewblock [overtype::renderspace -experimental test_mode -wrap 1 -width 78 -height 4 "" $rawview]
set lines [split $viewblock \n]
if {[llength $lines] > 4} {
append debug_info [join [list {*}[lrange $lines 0 1] "...<[expr {[llength $lines] -4}] lines undisplayed>..." {*}[lrange $lines end-1 end]] \n]

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

@ -658,6 +658,7 @@ proc repl::start {inchan args} {
variable editbuf
variable editbuf_list ;#command history
variable editbuf_linenum_submitted
variable editbuf_active_index
# ---
variable running
@ -681,6 +682,7 @@ proc repl::start {inchan args} {
set editbuf [punk::repl::class::class_editbuf new {}]
lappend editbuf_list $editbuf ;#current editbuf is always in the history
set editbuf_linenum_submitted 0
set editbuf_active_index 0
# ---
if {$::punk::console::ansi_wanted == 2} {
@ -1050,6 +1052,11 @@ namespace eval repl {
}
namespace eval punk::repl::class {
oo::class create class_bufman {
}
#multiline editing buffer
oo::class create class_editbuf {
variable o_context
@ -1157,7 +1164,7 @@ namespace eval punk::repl::class {
append debug \n $mergedinfo
append debug \n "input:[ansistring VIEW -lf 1 -vt 1 $new0] before row:$o_cursor_row after row: $result_row before col:$o_cursor_col after col:$result_col"
package require textblock
set debug [textblock::frame $debug]
set debug [textblock::frame -buildcache 0 $debug]
catch {punk::console::move_emitblock_return $debug_first_row 1 $debug}
# -- --- --- --- --- ---
@ -1222,7 +1229,7 @@ namespace eval punk::repl::class {
append debug \n $mergedinfo
append debug \n "input:[ansistring VIEW -lf 1 -vt 1 $p]"
package require textblock
set debug [textblock::frame $debug]
set debug [textblock::frame -buildcache 0 $debug]
#catch {punk::console::move_emitblock_return [expr {$debug_first_row + ($i * 6)}] 1 $debug}
set result [dict get $mergedinfo result]
@ -1682,9 +1689,14 @@ proc repl::repl_handler {inputchan prompt_config} {
}
set in_repl_handler [list]
}
proc repl::editbuf {args} {
variable editbuf
proc repl::editbuf {index args} {
variable editbuf_list
set editbuf [lindex $editbuf_list $index]
if {$editbuf ne ""} {
$editbuf {*}$args
} else {
return "No such index in editbuf list"
}
}
interp alias {} editbuf {} ::repl::editbuf
proc repl::repl_process_data {inputchan type chunk stdinlines prompt_config} {
@ -1873,11 +1885,11 @@ proc repl::repl_process_data {inputchan type chunk stdinlines prompt_config} {
set info [list_as_lines $lines]
}
} errM]} {
set info [textblock::frame -title "[a red]error[a]" $errM]
set info [textblock::frame -buildcache 0 -title "[a red]error[a]" $errM]
} else {
set info [textblock::frame -ansiborder [a+ green bold] -title "[a cyan]debugview_raw[a]" $info]
set info [textblock::frame -buildcache 0 -ansiborder [a+ green bold] -title "[a cyan]debugview_raw[a]" $info]
}
set debug_width [textblock::width $info]
set debug_width [textblock::widthtopline $info]
set spacepatch [textblock::block $debug_width 2 " "]
puts -nonewline [punk::ansi::cursor_off]
#use non cursorsave versions - cursor save/restore will interfere with any concurrent ansi rendering that uses save/restore - because save/restore is a single item, not a stack.
@ -1895,16 +1907,16 @@ proc repl::repl_process_data {inputchan type chunk stdinlines prompt_config} {
set info [list_as_lines $lines]
}
} editbuf_error]} {
set info [textblock::frame -title "[a red]error[a]" "$editbuf_error\n$::errorInfo"]
set info [textblock::frame -buildcache 0 -title "[a red]error[a]" "$editbuf_error\n$::errorInfo"]
} else {
set title "[a cyan]editbuf lines [$editbuf linecount][a]"
set title "[a cyan]editbuf [expr {[llength $editbuf_list]-1}] lines [$editbuf linecount][a]"
append title "[a+ yellow bold] col:[format %3s [$editbuf cursor_column]] row:[$editbuf cursor_row][a]"
set row1 " lastchar:[ansistring VIEW -lf 1 [$editbuf last_char]] lastgrapheme:[ansistring VIEW -lf 1 [$editbuf last_grapheme]]"
set row2 " lastansi:[ansistring VIEW -lf 1 [$editbuf last_ansi]]"
set info [a+ green bold]$row1\n$row2[a]\n$info
set info [textblock::frame -ansiborder [a+ green bold] -title $title $info]
set info [textblock::frame -buildcache 0 -ansiborder [a+ green bold] -title $title $info]
}
set editbuf_width [textblock::width $info]
set editbuf_width [textblock::widthtopline $info]
set spacepatch [textblock::block $editbuf_width 2 " "]
set editbuf_offset [expr {$consolewidth - $debug_width - $editbuf_width - 2}]
@ -2475,7 +2487,19 @@ proc repl::repl_process_data {inputchan type chunk stdinlines prompt_config} {
set commandstr ""
#catch {puts stderr "zz2---->[rep $::arglej]"}
set lines [$editbuf lines]
set buf_has_data 0
foreach ln $lines {
if {[string trim $ln] ne ""} {
set buf_has_data 1
}
}
if {$buf_has_data} {
set editbufnext [punk::repl::class::class_editbuf new {}]
lappend editbuf_list $editbufnext
set editbuf_linenum_submitted 0
set editbuf $editbufnext
}
#editbuf
} else {

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

@ -231,6 +231,7 @@ namespace eval textblock {
variable o_opts_table_defaults
variable o_opts_column_defaults
variable o_opts_row_defaults
variable TSUB
constructor {args} {
#*** !doctools
#[call class::table [method constructor] [arg args]]
@ -258,6 +259,7 @@ namespace eval textblock {
set o_rowdefs [dict create] ;#user requested row data e.g -minheight -maxheight
set o_rowstates [dict create] ;#actual row data such as -minheight and -maxheight detected from supplied row data
set TSUB \uF111 ;#should be BMP PUA code to show as either replacement char or nerdfont glyph. See FSUB for comments regarding choices.
}
method Get_seps {} {
set requested_seps [dict get $o_opts_table -show_seps]
@ -594,6 +596,8 @@ namespace eval textblock {
-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
@ -769,6 +773,16 @@ namespace eval textblock {
error "textblock::table::configure_column -ansireset is read-only. It is present only to prevent unwanted colourised output in configure commands"
}
}
-blockalign - -textalign {
switch -- $v {
left - right {
lappend checked_opts $k $v
}
centre - centre {
lappend checked_opts $k centre
}
}
}
default {
lappend checked_opts $k $v
}
@ -1269,11 +1283,16 @@ namespace eval textblock {
set botseps_v [dict get $sep_elements_vertical bottom$opt_posn]
set onlyseps_v [dict get $sep_elements_vertical only$opt_posn]
#top should work for all header rows regarding vseps - as we only use it to reduce the box elements, and lower headers have same except for tlc which isn't present anyway
set headerseps_v [dict get $sep_elements_vertical top$opt_posn]
lassign [my Get_seps] _h show_seps_h _v show_seps_v
set return_headerheight 0
set return_headerwidth 0
set cidx [lindex [dict keys $o_columndefs] $index_expression]
set colwidth [my column_width $cidx]
set col_blockalign [dict get $o_columndefs $cidx -blockalign]
if {$do_show_header} {
#puts "boxlimitsinfo header $opt_posn: -- boxlimits $header_boxlimits -- boxmap $hdrmap"
set ansibase_header [dict get $o_opts_table -ansibase_header] ;#merged to single during configure
@ -1284,9 +1303,7 @@ namespace eval textblock {
} else {
set ansiborder_final $ansibase_header$ansiborder_header
}
set cidx [lindex [dict keys $o_columndefs] $index_expression]
set RST [punk::ansi::a]
set colwidth [my column_width $cidx]
set hcell_line_blank [string repeat " " $colwidth]
set h 0
@ -1304,6 +1321,8 @@ namespace eval textblock {
set column_width_cache [dict create]
#used for colspan-zero header frames
set framesub_map [list hl $TSUB vll $TSUB vlr $TSUB tlc $TSUB blc $TSUB trc $TSUB brc $TSUB] ;# a debug test
foreach header $header_list {
set headerspans [dict get $all_colspans $h]
@ -1361,21 +1380,33 @@ namespace eval textblock {
}
}
#supporting wrapping in headers might be a step too difficult for little payoff.
#we would need a flag to enable/disable - plus language-based wrapping alg (see tcllib)
#The interaction with colspans and width calculations makes it likely to have a heavy performance impact and make the code even more complex.
#May be better to require user to pre-wrap as needed
##set hval [textblock::renderspace -width $colwidth -wrap 1 "" $hval]
#review - contentwidth of hval can be greater than $colwidth+2 - if so frame function will detect and frame_cache will not be used
set header_cell_startspan [textblock::frame -usecache 1 -width [expr {$colwidth+2}] -type [dict get $ftypes header]\
#This ellipsis 0 makes a difference (unwanted ellipsis at rhs of header column that starts span)
# -width is always +2 - as the boxlimits take into account show_vseps and show_edge
set header_cell_startspan [textblock::frame -ellipsis 0 -usecache 1 -width [expr {$colwidth+2}] -type [dict get $ftypes header]\
-ansibase $ansibase_header -ansiborder $ansiborder_final\
-boxlimits $hlims -boxmap $startmap -joins $header_joins $hval\
]
#JMN
#puts "===>\n$header_cell_startspan\n<==="
set spanned_parts [list $header_cell_startspan]
if {$this_span ne "1"} {
#more parts to append
#assert this_span == "all" or >1 ie a header that spans other columns
#therefore more parts to append
#set remaining_cols [lrange [dict keys $o_columndefs] $cidx end]
set remaining_spans [lrange $headerspans $cidx+1 end]
#puts ">> remaining_spans: $remaining_spans"
set spancol [expr {$cidx + 1}]
set h_lines [lrepeat $rowh ""]
set hcell_blank [::join $h_lines \n]
set hcell_blank [::join $h_lines \n] ;#todo - just use -height option of frame?
@ -1441,22 +1472,26 @@ namespace eval textblock {
dict set column_width_cache $spancol headerwidth $hwidth
} else {
set bwidth [dict get $column_width_cache $spancol bodywidth]
set hwidth [dict get $column_width_cache $spancol headerwidth]
}
#subsequent headers may also span columns - so we will get too wide if we use the headers directly
#but if we don't take into account header widths - they may get truncated.
if {$next_posn eq "right"} {
#This is an unintuitive edge case - review
#spans at tail end are too long when edges are shown if we use bwidth+1 (vlr extends right beyond table)
#spans at tail end are too short if edges are hidden and we use bwidth (short lower horizontal bar)
if {![dict get $o_opts_table -show_edge]} {
set spanwidth [expr {$bwidth+1}]
#spans at tail end are too long when edges are shown if we use bwidth (vlr extends right beyond table)
#spans at tail end are too short if edges are hidden and we use bwidth-1 (short lower horizontal bar)
#test JMN
if {$next_posn eq "right" && [dict get $o_opts_table -show_edge]} {
set spanwidth [expr {$bwidth -1}]
} else {
set spanwidth $bwidth
}
} else {
set spanwidth [expr {$bwidth+1}]
set spanwidth [expr {$bwidth }]
}
set header_cell [textblock::frame -width $spanwidth -type [dict get $ftypes header]\
#JMN - review
set framewidth $spanwidth
incr framewidth 1
set header_cell [textblock::frame -ellipsis 0 -width $framewidth -type [dict get $ftypes header]\
-ansibase $ansibase_header -ansiborder $ansiborder_final\
-boxlimits $hlims -boxmap $this_span_map -joins $header_joins $hcell_blank\
]
@ -1485,8 +1520,9 @@ namespace eval textblock {
set spacemap [list hl " " vl " " tlc " " blc " " trc " " brc " "]
#set spacemap [list hl "\uFFFF" vl "\uFFFF" tlc "\uFFFF" blc "\uFFFF" trc "\uFFFF " brc "\uFFFF"] ;# a debug test
#-usecache 1 ok
set hblock [textblock::frame -type $spacemap -boxlimits $hlims -ansibase $ansibase_header $hval]
set spanned_frame [overtype::left -experimental test_mode -transparent 1 $spanned_frame $hblock]
set hblock [textblock::frame -ellipsis 0 -type $spacemap -boxlimits $hlims -ansibase $ansibase_header $hval]
#set spanned_frame [overtype::renderspace -experimental test_mode -transparent 1 $spanned_frame $hblock]
set spanned_frame [overtype::block -blockalign left -transparent 1 $spanned_frame $hblock]
}
@ -1495,49 +1531,50 @@ namespace eval textblock {
} else {
#zero span header
#JMN
if 0 {
#old version - sort of works
set h_lines [lrepeat $rowh ""]
set hcell_blank [join $h_lines \n]
set spacemap [list hl " " vl " " tlc " " blc " " trc " " brc " "]
set spacemap [list hl "\uFFFF" vl "\uFFFF" tlc "\uFFFF" blc "\uFFFF" trc "\uFFFF " brc "\uFFFF"] ;# a debug test
set header_frame [textblock::frame -width 0 -type [dict get $ftypes header]\
-ansibase $ansibase_header \
-boxlimits $hlims -boxmap $spacemap $hcell_blank\
]
append part_header $header_frame\n
} else {
#test version
set hw1 [dict get $o_columnstates $cidx maxwidthheaderseen] ;#headers may be masked by spans, or empty - width may depend more on spans than headers in current column
set hw2 [textblock::width $part_header] ;#widest so far
set hw3 [expr {max($hw1,$hw2)}]
set bw [dict get $o_columnstates $cidx maxwidthbodyseen]
set padwidth [expr {max($hw3,$bw)}]
if {[dict exists $column_width_cache $cidx]} {
set hwidth [dict get $column_width_cache $cidx headerwidth]
set padwidth [expr {max($padwidth,$hwidth)}]
}
#test hack - wider helps stop the breaks - but leaves junk spaces and ansiresets beyond the rhs border of table
#print function overflow 0 fixes?
set padwidth 20
#set padwidth 20
#This sort of works - but doesn't cater for colspans that don't strictly decrease in size as we go down the header list
#we end up with breaks in some situations
#we don't know the width here, because we would need to look-ahead to see the widest section of frame
#We will adjust the padding below.
#we need the column data width as a minimum or we'll cut lines above from earlier columns
set padwidth [my column_datawidth $cidx -headers 0 -data 1 -cached 1]
#set bline [string repeat \uFFFF $colwidth]
set bline [string repeat \uFFFF $padwidth]
#under assumption we are building table using L frame method and that horizontal borders are only ever 1 high
# - we can avoid using a frame - but we potentially need to manually adjust for show_hpos show_edge etc
#avoiding frame here is faster.. but not by much (<10%? on textblock::spantest2 )
if 0 {
#breaks -show_edge 0
if {$rowpos eq "top" && [dict get $o_opts_table -show_edge]} {
set padheight [expr {$rowh + 2}]
} else {
set padheight [expr {$rowh + 1}]
}
set bline [string repeat $TSUB [expr {$padwidth +1}]]
set h_lines [lrepeat $padheight $bline]
set hcell_blank [::join $h_lines \n]
set header_frame $hcell_blank
} else {
set bline [string repeat $TSUB $padwidth]
set h_lines [lrepeat $rowh $bline]
set hcell_blank [::join $h_lines \n]
set spacemap [list hl "\uFFFF" vll "\uFFFF" vlr "\uFFFF" tlc "\uFFFF" blc "\uFFFF" trc "\uFFFF " brc "\uFFFF"] ;# a debug test
# -usecache 1 ok
set header_frame [textblock::frame -width [expr {$padwidth+2}] -type [dict get $ftypes header]\
-ansibase $ansibase_header \
-boxlimits $hlims -boxmap $spacemap $hcell_blank\
#set header_frame [textblock::frame -ellipsis 0 -width [expr {$padwidth+2}] -type [dict get $ftypes header]\
# -ansibase $ansibase_header \
# -boxlimits $hlims -boxmap $framesub_map $hcell_blank\
# ]
#frame borders will never display - so use the simplest frametype and don't apply any ansi
set header_frame [textblock::frame -ellipsis 0 -width [expr {$padwidth+2}] -type ascii\
-boxlimits $hlims -boxmap $framesub_map $hcell_blank\
]
append part_header $header_frame\n
}
}
append part_header $header_frame\n
}
incr h
}
@ -1558,9 +1595,21 @@ namespace eval textblock {
]
append part_header $header_frame\n
}
set part_header [string trimright $part_header \n]
lassign [textblock::size $part_header] _w return_headerwidth _h return_headerheight
set padline [string repeat $TSUB $return_headerwidth]
set adjusted_lines [list]
foreach ln [split $part_header \n] {
if {[string first $TSUB $ln] >=0} {
lappend adjusted_lines $padline
} else {
lappend adjusted_lines $ln
}
append output $part_header
}
set part_header [join $adjusted_lines \n]
}
append output $part_header \n
set r 0
set rmax [expr {[llength $cells]-1}]
@ -1589,10 +1638,10 @@ namespace eval textblock {
set colidx [lindex [dict keys $o_columndefs] $index_expression] ;#convert possible end-1,2+2 etc expression to >= 0 integer in dict range
set opt_col_ansibase [dict get $o_columndefs $colidx -ansibase] ;#ordinary merge of codes already done in configure_column
#set colwidth [my column_width $colidx]
set body_ansibase [dict get $o_opts_table -ansibase_body]
#set ansibase [punk::ansi::codetype::sgr_merge_singles [list $body_ansibase $opt_col_ansibase]] ;#allow col to override body
set ansibase $body_ansibase$opt_col_ansibase
set body_ansiborder [dict get $o_opts_table -ansiborder_body]
if {[dict get $o_opts_table -frametype] eq "block"} {
#block is the only style where bg colour can fill the frame content area exactly if the L-shaped border elements are styled
@ -1603,44 +1652,65 @@ namespace eval textblock {
set border_ansi $body_ansibase$body_ansiborder
}
set r 0
set ftblock [expr {[dict get $o_opts_table -frametype] eq "block"}]
foreach c $cells {
set ansibase $body_ansibase$opt_col_ansibase
set row_ansibase [dict get $o_rowdefs $r -ansibase]
#todo - joinleft,joinright,joindown based on opts in args
#append output [textblock::frame -boxlimits {vll blc hlb} $c]\n
if {[dict get $o_opts_table -frametype] eq "block"} {
set row_ansibase [dict get $o_rowdefs $r -ansibase]
set cell_ansibase ""
set row_bg ""
if {$row_ansibase ne ""} {
set row_bg [punk::ansi::codetype::sgr_merge_singles [list $row_ansibase] -filter_fg 1]
}
set ansiborder_body_col_row $border_ansi$row_bg
set ansiborder_final $ansiborder_body_col_row
if 1 {
#$c will always have ansi resets due to overtype::left behaviour
#$c will always have ansi resets due to overtype behaviour ?
#todo - review overtype
if {[punk::ansi::ta::detect $c]} {
#if {[textblock::widthtopline $c] == $colwidth} {}
#use only the last ansi sequence in the cell value
#Filter out foreground and use background for ansiborder override
set parts [punk::ansi::ta::split_codes_single $c]
#we have detected ansi - so there will always be at least 3 parts beginning and ending with pt pt,ansi,pt,ansi...,pt
set codes [list]
foreach {pt cd} $parts {
if {$cd ne ""} {
lappend codes $cd
}
}
#set takebg [lindex $parts end-1]
#set cell_bg [punk::ansi::codetype::sgr_merge_singles [list $takebg] -filter_fg 1]
set cell_bg [punk::ansi::codetype::sgr_merge_singles $codes -filter_fg 1]
set cell_bg [punk::ansi::codetype::sgr_merge_singles $codes -filter_fg 1 -filter_reset 1]
#puts --->[ansistring VIEW $codes]
#puts "-->>> [ansistring VIEW $cell_bg] <<<--"
set ansiborder_final $ansiborder_body_col_row$cell_bg
#JMN
if {[punk::ansi::codetype::is_sgr_reset [lindex $codes end]]} {
if {[punk::ansi::codetype::is_sgr_reset [lindex $codes end-1]]} {
#special case double reset at end of content
set cell_ansi_tail [punk::ansi::codetype::sgr_merge_singles $codes] ;#no filters
set ansibase ""
set row_ansibase ""
if {$ftblock} {
set ansiborder_final [punk::ansi::codetype::sgr_merge [list $ansiborder_body_col_row] -filter_bg 1]
}
set cell_ansibase $cell_ansi_tail
} else {
#single trailing reset in content
set cell_ansibase "" ;#cell doesn't contribute to frame's ansibase
}
} else {
set ansiborder_body_col_row $border_ansi
set ansiborder_final $ansiborder_body_col_row
if {$ftblock} {
#no resets use cells bg to extend to the border - only for block frames
set ansiborder_final $ansiborder_body_col_row$cell_bg
}
set cell_ansibase $cell_bg
}
set ansibase_final $ansibase$row_ansibase
}
set ansibase_final $ansibase$row_ansibase$cell_ansibase
if {$r == 0} {
if {$r == $rmax} {
@ -1665,7 +1735,7 @@ namespace eval textblock {
set blims [struct::set difference $blims [dict get $::textblock::class::table_edge_parts top$opt_posn] ]
}
}
set rowframe [textblock::frame -type [dict get $ftypes body] -ansibase $ansibase_final -ansiborder $ansiborder_final -boxlimits $blims -boxmap $bmap -joins $joins $c]
set rowframe [textblock::frame -type [dict get $ftypes body] -width [expr {$colwidth+2}] -blockalign $col_blockalign -ansibase $ansibase_final -ansiborder $ansiborder_final -boxlimits $blims -boxmap $bmap -joins $joins $c]
set return_bodywidth [textblock::width $rowframe]
append part_body $rowframe \n
} else {
@ -1683,7 +1753,7 @@ namespace eval textblock {
set blims [struct::set difference $blims [dict get $::textblock::class::table_edge_parts middle$opt_posn] ]
}
}
append part_body [textblock::frame -type [dict get $ftypes body] -ansibase $ansibase_final -ansiborder $ansiborder_final -boxlimits $blims -boxmap $bmap -joins $joins $c]\n
append part_body [textblock::frame -type [dict get $ftypes body] -width [expr {$colwidth+2}] -blockalign $col_blockalign -ansibase $ansibase_final -ansiborder $ansiborder_final -boxlimits $blims -boxmap $bmap -joins $joins $c]\n
}
incr r
}
@ -1691,7 +1761,6 @@ namespace eval textblock {
if {![llength $cells]} {
set joins [lremove $joins [lsearch $joins down*]]
#we need to know the width of the column to setup the empty cell properly
#(we didn't need it above because get_column_cells_by_index returned values of the correct width)
#even if no header displayed - we should take account of any defined column widths
set colwidth [my column_width $index_expression]
@ -1751,6 +1820,14 @@ namespace eval textblock {
set RST [punk::ansi::a]
set ansibase_body [dict get $o_opts_table -ansibase_body]
set ansibase_col [dict get $cdef -ansibase]
set textalign [dict get $cdef -textalign]
switch -- $textalign {
left {set pad right}
right {set pad left}
default {
set pad "centre" ;#todo?
}
}
set ansibase_header [dict get $o_opts_table -ansibase_header]
@ -1799,15 +1876,18 @@ namespace eval textblock {
set header_underlay [lrepeat $header_maxdataheight $hdr_line_blank]
set header_underlay $ansibase_header[join $header_underlay \n]
if {$hdr ne ""} {
dict lappend output headers [overtype::left -experimental test_mode $header_underlay $ansibase_header$hdr]
dict lappend output headers [overtype::renderspace -experimental test_mode $header_underlay $ansibase_header$hdr]
} else {
dict lappend output headers $header_underlay
}
}
set colwidth [my column_width $cidx]
set cell_line_blank [string repeat " " $colwidth]
#set colwidth [my column_width $cidx]
#set cell_line_blank [string repeat " " $colwidth]
set datawidth [my column_datawidth $cidx -headers 0 -footers 0 -data 1 -cached 1]
set cell_line_blank [string repeat " " $datawidth]
set items [dict get $o_columndata $cidx]
@ -1858,10 +1938,12 @@ namespace eval textblock {
set cval_block [join $cval_lines \n]
#TODO! fix overtype library
#set cell [overtype::left -experimental test_mode $cell_ansibase$cell_blank$RST $cval_block]
#set cell [overtype::left -experimental test_mode $cell_blank $cval_block]
#set cell [overtype::renderspace -experimental test_mode $cell_ansibase$cell_blank$RST $cval_block]
#set cell [overtype::renderspace -experimental test_mode $cell_blank $cval_block]
set cell [textblock::pad $cval_block -width $colwidth -padchar " " -within_ansi 0 -which right]
#set cell [textblock::pad $cval_block -width $colwidth -padchar " " -within_ansi 0 -which right]
set cell [textblock::pad $cval_block -width $datawidth -padchar " " -within_ansi 1 -which $pad]
#set cell [textblock::pad $cval_block -width $colwidth -padchar " " -within_ansi 0 -which left]
dict lappend output cells $cell
@ -2077,10 +2159,11 @@ namespace eval textblock {
-headers 0\
-footers 0\
-data 1\
-cached 1\
]
dict for {k v} $args {
switch -- $k {
-headers - -footers - -data {}
-headers - -footers - -data - -cached {}
default {
error "column_datawidth unrecognised flag '$k'. Known flags: [dict keys $defaults]"
}
@ -2092,6 +2175,24 @@ namespace eval textblock {
if {$cidx eq ""} {
return
}
if {[dict get $opts -cached]} {
set hwidest 0
set bwidest 0
set fwidest 0
if {[dict get $opts -headers]} {
set hwidest [dict get $o_columnstates $cidx maxwidthheaderseen]
}
if {[dict get $opts -data]} {
set bwidest [dict get $o_columnstates $cidx maxwidthbodyseen]
}
if {[dict get $opts -footers]} {
#TODO!
#set bwidest [dict get $o_columnstates $cidx maxwidthfooterseen]
}
return [expr {max($hwidest,$bwidest,$fwidest)}]
}
#assert cidx is >=0 integer in valid range of keys for o_columndefs
set values [list]
if {[dict get $opts -headers]} {
@ -2213,12 +2314,12 @@ namespace eval textblock {
set table $nextcol
set height [textblock::height $table] ;#only need to get height once at start
} else {
set nextcol [textblock::join [textblock::block $padwidth $height "\uFFFF"] $nextcol]
set table [overtype::left -overflow 1 -experimental test_mode -transparent \uFFFF $table $nextcol]
set nextcol [textblock::join [textblock::block $padwidth $height $TSUB] $nextcol]
set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent $TSUB $table $nextcol]
#JMN
#set nextcol [textblock::join [textblock::block $padwidth $height "\uFFFF"] $nextcol]
#set table [overtype::left -overflow 1 -experimental test_mode -transparent \uFFFF $table $nextcol]
#set table [overtype::renderspace -overflow 1 -experimental test_mode -transparent \uFFFF $table $nextcol]
}
incr padwidth $bodywidth
incr colposn
@ -2266,6 +2367,21 @@ namespace eval textblock {
$t configure -show_header 1 -ansiborder_header [a+ cyan]
return $t
}
#more complex colspans
proc spantest2 {} {
set t [list_as_table 5 {a b c d e aa bb cc dd ee X Y} -return object]
$t configure_column 0 -headers {span3 span4 span5/5 "span-all etc blah 123 hmmmmm" span2}
$t configure_column 0 -header_colspans {3 4 1 all 1}
$t configure_column 2 -headers {"" "" "" "" c2span2}
$t configure_column 1 -header_colspans {0 0 2 0 1}
$t configure_column 2 -header_colspans {0 0 0 0 2}
$t configure -show_header 1 -ansiborder_header [a+ cyan]
return $t
}
proc periodic {args} {
#For an impressive interactive terminal app (javascript)
# see: https://github.com/spirometaxas/periodic-table-cli
@ -2607,6 +2723,19 @@ namespace eval textblock {
}
return [punk::char::ansifreestring_width $textblock]
}
#when we know the block is uniform in width - just examine topline
proc widthtopline {textblock} {
set firstnl [string first \n $textblock]
if {$firstnl >= 0} {
set tl [string range $textblock 0 $firstnl]
} else {
set tl $textblock
}
if {[punk::ansi::ta::detect $tl]} {
set tl [punk::ansi::stripansi $tl]
}
return [punk::char::ansifreestring_width $tl]
}
#uses tcl's string length on each line. Length will include chars in ansi codes etc - this is not a 'width' determining function.
proc string_length_line_max textblock {
tcl::mathfunc::max {*}[lmap v [split $textblock \n] {string length $v}]
@ -2945,7 +3074,7 @@ namespace eval textblock {
return $t
}
proc pad_test2 {blocklist} {
proc pad_test_blocklist {blocklist} {
set b 0
set blockinfo [dict create]
foreach block $blocklist {
@ -2989,7 +3118,7 @@ namespace eval textblock {
set b2 "[a+ green bold][textblock::block 4 4 x]\n[a+ Green]"
set b3 "[textblock::testblock 4 rainbow]\n[a]"
set b4 "[textblock::testblock 4 rainbow]\n[a+ Green]"
set t [textblock::pad_test2 [list $b1 $b2 $b3 $b4]]
set t [textblock::pad_test_blocklist [list $b1 $b2 $b3 $b4]]
}
@ -3039,6 +3168,7 @@ 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
#they may however still be 'ragged' ie differing line lengths
proc ::textblock::join {args} {
#lassign [punk::lib::opts_values {
# blocks -type string -multiple 1
@ -4396,9 +4526,27 @@ namespace eval textblock {
}
variable frame_cache
set out ""
if {[catch {
set termwidth [dict get [punk::console::get_size] columns]
}]} {
set termwidth 80
}
dict for {k v} $frame_cache {
lassign $v _f frame _used used
append out [textblock::join $k " " $frame " " $used]\n
#set fwidth [textblock::widthtopline $frame]
#review - are cached frames uniform width lines?
set fwidth [textblock::width $frame]
set frameinfo "$k used:$used "
set allinone_width [expr {[string length $frameinfo] + $fwidth}]
if {$allinone_width >= $termwidth} {
#split across 2 lines
append out "$frameinfo\n"
append out $frame \n
} else {
append out [textblock::join $frameinfo $frame]\n
}
append out \n ;# frames used to build tables often have joins - keep a line in between for clarity
}
if {$action eq "clear"} {
set frame_cache [dict create]
@ -4455,16 +4603,18 @@ namespace eval textblock {
-height ""\
-ansiborder ""\
-ansibase ""\
-align "left"\
-blockalign "centre"\
-textalign "left"\
-ellipsis 1\
-usecache 1\
-buildcache 1\
]
#todo -blockalignbias -textalignbias?
#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} $opts {
switch -- $k {
-etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -align - -ellipsis - -usecache - -buildcache {}
-etabs - -type - -boxlimits - -boxmap - -joins - -title - -subtitle - -width - -height - -ansiborder - -ansibase - -blockalign - -textalign - -ellipsis - -usecache - -buildcache {}
default {
error "frame option '$k' not understood. Valid options are [dict keys $defaults]"
}
@ -4584,16 +4734,24 @@ namespace eval textblock {
set opt_width [dict get $opts -width]
set opt_height [dict get $opts -height]
# -- --- --- --- --- ---
set opt_align [dict get $opts -align]
set opt_align [string tolower $opt_align]
switch -- $opt_align {
set opt_blockalign [dict get $opts -blockalign]
switch -- $opt_blockalign {
left - right - centre - center {}
default {
error "frame option -align must be left|right|centre|center - received: $opt_align"
error "frame option -blockalign must be left|right|centre|center - received: $opt_blockalign"
}
}
#these are all valid commands for overtype::<cmd>
# -- --- --- --- --- ---
set opt_textalign [dict get $opts -textalign]
switch -- $opt_textalign {
left - right - centre - center {}
default {
error "frame option -textalign must be left|right|centre|center - received: $opt_textalign"
}
}
# -- --- --- --- --- ---
set opt_ansiborder [dict get $opts -ansiborder]
set opt_ansibase [dict get $opts -ansibase] ;#experimental
set opt_ellipsis [dict get $opts -ellipsis]
@ -4611,7 +4769,7 @@ namespace eval textblock {
}
}
set contents [string map [list \r\n \n] $contents]
set actual_contentwidth [textblock::width $contents]
set actual_contentwidth [textblock::width $contents] ;#length of longest line in contents (contents can be ragged)
set actual_contentheight [textblock::height $contents]
} else {
set actual_contentwidth 0
@ -4627,92 +4785,99 @@ namespace eval textblock {
}
if {$opt_width eq ""} {
set contentwidth $content_or_title_width
set frame_inner_width $content_or_title_width
} else {
set contentwidth [expr {max(0,$opt_width - 2)}] ;#default
set frame_inner_width [expr {max(0,$opt_width - 2)}] ;#default
}
if {$opt_height eq ""} {
set contentheight $actual_contentheight
set frame_inner_height $actual_contentheight
} else {
set contentheight [expr {max(0,$opt_height -2)}] ;#default
set frame_inner_height [expr {max(0,$opt_height -2)}] ;#default
}
if {$contentheight == 0 && $contentwidth == 0} {
if {$frame_inner_height == 0 && $frame_inner_width == 0} {
set has_contents 0
}
#todo - render it with vertical overflow so we can process ansi moves?
#set linecount [textblock::height $contents]
set linecount $contentheight
set linecount $frame_inner_height
# -- --- --- --- --- --- --- --- ---
variable frame_cache
#review - custom frame affects contentwidth - exclude from caching?
#set cache_key [concat $arglist $contentwidth $contentheight]
set hashables [concat $arglist $contentwidth $contentheight]
#review - custom frame affects frame_inner_width - exclude from caching?
#set cache_key [concat $arglist $frame_inner_width $frame_inner_height]
set hashables [concat $arglist $frame_inner_width $frame_inner_height]
package require md5
set hash [md5::md5 -hex $hashables]
set cache_key "$hash-$contentwidth-$contentheight-actualcontentwidth:$actual_contentwidth"
set TSUB \u1FFF; #needs to be different to that used in table construction
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
#e.g BMP PUA U+E000 -> U+F8FF - although this is commonly used for example by nerdfonts
#also supplementary private use blocks
#however these display double wide on for example cmd terminal despite having wcswidth 1 (makes layout debugging difficult)
#U+F0000 -> U+FFFD
#U+100000 -> U+10FFFD
#FSUB options: \uf0ff \uF1FF \uf2ff (no nerdfont glyphs - should look like standard replacement char) \uF2DD (circular thingy)
#should be something someone is unlikely to use as part of a custom frame character.
#ideally a glyph that doesn't auto-expand into whitespace and is countable when in a string (narrower is better)
#As nerdfont glyphs tend to be mostly equal height & width - circular glyphs tend to be more distinguishable in a string
#terminal settings may need to be adjusted to stop auto glyph resizing - a rather annoying misfeature that some people seem to think they like.
#e.g in wezterm config: allow_square_glyphs_to_overflow_width = "Never"
#review - we could consider wasting a few cycles to check for a conflict and use a different FSUB
set FSUB \uF2DD
#this occurs commonly in table building with colspans - review
if {$actual_contentwidth > $contentwidth || $actual_contentheight != $contentheight} {
if {$actual_contentwidth > $frame_inner_width || $actual_contentheight != $frame_inner_height} {
set usecache 0
#set buildcache 0 ;#comment out for debug/analysis so we can see
set cache_key [a+ Web-red]$cache_key[a]
#puts "--->> frame_inner_width:$frame_inner_width actual_contentwidth:$actual_contentwidth contents: '$contents'"
set cache_key [a+ Web-red web-white]$cache_key[a]
}
if {$buildcache && $actual_contentwidth < $contentwidth} {
if {$buildcache && $actual_contentwidth < $frame_inner_width} {
#colourise cache_key to warn
if {$actual_contentwidth == 0} {
#we can still substitue with right length
#we can still substitute with right length
set cache_key [a+ Web-steelblue web-black]$cache_key[a]
} else {
#actual_contentwidth is shorter - rather than choose an alignment and pad - we will opt out of caching
#actual_contentwidth is narrower than frame - check template's patternwidth
if {[dict exists $frame_cache $cache_key]} {
set cache_patternwidth [dict get $frame_cache $cache_key patternwidth]
} else {
set cache_patternwidth [$actual_contentwidth]
}
if {$actual_contentwidth < $cache_patternwidth} {
set usecache 0
set cache_key [a+ Web-orange web-black]$cache_key[a]
} elseif {$actual_contentwidth == $cache_patternwidth} {
#set usecache 1
} else {
#actual_contentwidth > pattern
set usecache 0
set cache_key [a+ Web-red web-black]$cache_key[a]
}
}
}
#JMN debug
#set usecache 0
set is_cached 0
if {$usecache && [dict exists $frame_cache $cache_key]} {
set cache_patternwidth [dict get $frame_cache $cache_key patternwidth]
set template [dict get $frame_cache $cache_key frame]
set used [dict get $frame_cache $cache_key used]
dict set frame_cache $cache_key used [expr {$used+1}]
dict set frame_cache $cache_key used [expr {$used+1}] ;#update existing record
set is_cached 1
set resultlines [list]
set overwritable [string repeat $TSUB $contentwidth]
set blankset [string repeat " " $contentwidth]
set contentindex 0
set clines [split $contents \n]
if {$actual_contentwidth == 0} {
foreach tline [split $template \n] {
if {[string first $TSUB $tline] >= 0} {
lappend resultlines [string map [list $overwritable $blankset] $tline]
incr contentindex
} else {
lappend resultlines $tline
}
}
} else {
foreach tline [split $template \n] {
if {[string first $TSUB $tline] >= 0} {
#set sublen [string length [lindex [regexp -inline "\[^$TSUB]*($TSUB*).*" $tline] 1]]
#set overwritable [string repeat $TSUB $sublen]
lappend resultlines [string map [list $overwritable [lindex $clines $contentindex]] $tline]
incr contentindex
} else {
lappend resultlines $tline
}
}
}
return [::join $resultlines \n]
}
# -- --- --- --- --- --- --- --- ---
if {!$is_cached} {
set rst [a]
#set column [string repeat " " $contentwidth] ;#default - may need to override for custom frame
set underlayline [string repeat " " $contentwidth]
#set column [string repeat " " $frame_inner_width] ;#default - may need to override for custom frame
set underlayline [string repeat " " $frame_inner_width]
set underlay [::join [lrepeat $linecount $underlayline] \n]
set cache_underlayline [string repeat $TSUB $contentwidth]
set cache_underlay [::join [lrepeat $linecount $cache_underlayline] \n]
set vll_width 1 ;#default for all except custom (printing width)
set vlr_width 1
@ -4751,20 +4916,21 @@ namespace eval textblock {
set brc_width [punk::ansi::printing_length $brc]
set framewidth [expr {$contentwidth + 2}] ;#reverse default assumption
set framewidth [expr {$frame_inner_width + 2}] ;#reverse default assumption
if {$opt_width eq ""} {
#width wasn't specified - so user is expecting frame to adapt to title/contents
#content shouldn't truncate because of extra wide frame
set contentwidth $content_or_title_width
#review - punk::console::get_size ? wrapping? quite hard to support with colspans
set frame_inner_width $content_or_title_width
set tbarwidth [expr {$content_or_title_width + 2 - $tlc_width - $trc_width - 2 + $vll_width + $vlr_width}] ;#+/2's for difference between border element widths and standard element single-width
set bbarwidth [expr {$content_or_title_width + 2 - $blc_width - $brc_width - 2 + $vll_width + $vlr_width}]
} else {
set contentwidth [expr $opt_width - $vll_width - $vlr_width] ;#content may be truncated
set frame_inner_width [expr $opt_width - $vll_width - $vlr_width] ;#content may be truncated
set tbarwidth [expr {$opt_width - $tlc_width - $trc_width}]
set bbarwidth [expr {$opt_width - $blc_width - $brc_width}]
}
#set column [string repeat " " $contentwidth]
set underlayline [string repeat " " $contentwidth]
#set column [string repeat " " $frame_inner_width]
set underlayline [string repeat " " $frame_inner_width]
set underlay [::join [lrepeat $linecount $underlayline] \n]
#cache?
@ -4797,14 +4963,14 @@ namespace eval textblock {
}
}
altg {
set tbar [string repeat $hlt $contentwidth]
set tbar [string repeat $hlt $frame_inner_width]
set tbar [cd::groptim $tbar]
set bbar [string repeat $hlb $contentwidth]
set bbar [string repeat $hlb $frame_inner_width]
set bbar [cd::groptim $bbar]
}
default {
set tbar [string repeat $hlt $contentwidth]
set bbar [string repeat $hlb $contentwidth]
set tbar [string repeat $hlt $frame_inner_width]
set bbar [string repeat $hlb $frame_inner_width]
}
}
@ -4932,6 +5098,7 @@ namespace eval textblock {
}
set fs ""
set fscached ""
set cache_patternwidth 0
#todo - output nothing except maybe newlines depending on if opt_height 0 and/or opt_width 0?
if {$topborder} {
if {$leftborder && $rightborder} {
@ -4955,34 +5122,40 @@ namespace eval textblock {
append fs \n
append fscached \n
}
#set inner [overtype::$opt_align -ellipsis $opt_ellipsis $opt_ansibase$underlay$rstbase $opt_ansibase$contents$rstbase]
set inner [overtype::$opt_align -ellipsis $opt_ellipsis $opt_ansibase$underlay$rstbase $contents]
switch -- $opt_textalign {
right {set pad "left"}
left {set pad "right"}
default {set pad $opt_textalign}
}
#set textaligned_contents [textblock::pad $contents -width $actual_contentwidth -which $pad -within_ansi 1]
#set inner [overtype::block -blockalign $opt_blockalign -ellipsis $opt_ellipsis $opt_ansibase$underlay$rstbase $opt_ansibase$textaligned_contents]
#set cache_inner [overtype::$opt_align -ellipsis $opt_ellipsis $opt_ansibase$cache_underlay$rstbase $contents]
#review
set cache_inner $opt_ansibase$cache_underlay$rstbase
set cache_contentline [string repeat $FSUB $actual_contentwidth]
set cache_patternwidth $actual_contentwidth
set cache_contentpattern [::join [lrepeat $linecount $cache_contentline] \n]
set cache_inner [overtype::block -blockalign $opt_blockalign -ellipsis $opt_ellipsis $opt_ansibase$underlay$rstbase $opt_ansibase$cache_contentpattern]
#after overtype::block - our actual patternwidth may be less
set cache_patternwidth [string length [lindex [regexp -inline "\[^$FSUB]*(\[$FSUB]*).*" $cache_inner] 1]]
if {$leftborder && $rightborder} {
set bodyparts [list $lhs $opt_ansibase$inner$rstbase $rhs]
set cache_bodyparts [list $lhs $opt_ansibase$cache_inner$rstbase $rhs]
#set bodyparts [list $lhs $inner $rhs]
set cache_bodyparts [list $lhs $cache_inner $rhs]
} else {
if {$leftborder} {
set bodyparts [list $lhs $opt_ansibase$inner$rstbase]
set cache_bodyparts [list $lhs $opt_ansibase$cache_inner$rstbase]
#set bodyparts [list $lhs $inner]
set cache_bodyparts [list $lhs $cache_inner]
} elseif {$rightborder} {
set bodyparts [list $opt_ansibase$inner$rstbase $rhs]
set cache_bodyparts [list $opt_ansibase$cache_inner$rstbase $rhs]
#set bodyparts [list $inner $rhs]
set cache_bodyparts [list $cache_inner $rhs]
} else {
set bodyparts [list $opt_ansibase$inner$rstbase]
set cache_bodyparts [list $opt_ansibase$cache_inner$rstbase]
#set bodyparts [list $inner]
set cache_bodyparts [list $cache_inner]
}
}
set body [textblock::join -- {*}$bodyparts]
if {$buildcache} {
#set body [textblock::join -- {*}$bodyparts]
set cache_body [textblock::join -- {*}$cache_bodyparts]
append fscached $cache_body
}
append fs $body
#append fs $body
}
if {$opt_height eq "" || $opt_height > 1} {
@ -4992,31 +5165,91 @@ namespace eval textblock {
}
if {$bottomborder} {
if {($topborder & $fs ne "xx" ) || ($has_contents || $opt_height > 2)} {
append fs \n
#append fs \n
append fscached \n
}
if {$leftborder && $rightborder} {
append fs $blc$bottombar$brc
#append fs $blc$bottombar$brc
append fscached $blc$bottombar$brc
} else {
if {$leftborder} {
append fs $blc$bottombar
#append fs $blc$bottombar
append fscached $blc$bottombar
} elseif {$rightborder} {
append fs $bottombar$brc
#append fs $bottombar$brc
append fscached $bottombar$brc
} else {
append fs $bottombar
#append fs $bottombar
append fscached $bottombar
}
}
}
}
set template $fscached
;#end !$is_cached
}
#use the same mechanism to build the final frame - whether from cache or template
if {$actual_contentwidth == 0} {
set fs [string map [list $FSUB " "] $template]
} else {
set resultlines [list]
set overwritable [string repeat $FSUB $cache_patternwidth]
set contentindex 0
switch -- $opt_textalign {
left {set pad right}
right {set pad left}
default {set pad $opt_textalign}
}
#review
if {[string is integer -strict $opt_height] && $actual_contentheight < ($opt_height -2)} {
set diff [expr {($opt_height -2) - $actual_contentheight}]
append contents [::join [lrepeat $diff \n] ""]
}
set paddedcontents [textblock::pad $contents -which $pad -within_ansi 1] ;#autowidth to width of content (should match cache_patternwidth)
set paddedwidth [textblock::widthtopline $paddedcontents]
#review - horizontal truncation
if {$paddedwidth > $cache_patternwidth} {
set paddedcontents [overtype::renderspace -width $cache_patternwidth "" $paddedcontents]
}
set contentblock [textblock::join $paddedcontents] ;#make sure each line has ansi replays
set tlines [split $template \n]
#we will need to strip off the leading reset on each line when stitching together with template lines so that ansibase can come into play too.
#after textblock::join the reset will be a separate code ie should be exactly ESC[0m
set R [a]
set rlen [string length $R]
set clines [split $contentblock \n]
foreach tline $tlines {
if {[string first $FSUB $tline] >= 0} {
set content_line [lindex $clines $contentindex]
if {[string first $R $content_line] == 0} {
set content_line [string range $content_line $rlen end]
}
#make sure to replay opt_ansibase to the right of the replacement
lappend resultlines [string map [list $overwritable $content_line$opt_ansibase] $tline]
incr contentindex
} else {
lappend resultlines $tline
}
}
set fs [::join $resultlines \n]
}
if {$is_cached} {
return $fs
} else {
if {$buildcache} {
dict set frame_cache $cache_key [list frame $fscached used 0]
dict set frame_cache $cache_key [list frame $template used 0 patternwidth $cache_patternwidth]
}
return $fs
}
}
proc gcross {{size 1} args} {
if {$size == 0} {

Loading…
Cancel
Save