Browse Source

ansi work, ansistring append/appendobj

master
Julian Noble 1 year ago
parent
commit
b3c5e196a3
  1. 294
      src/modules/punk/ansi-999999.0a1.0.tm
  2. 23
      src/modules/punk/repl-0.1.tm
  3. 6
      src/modules/textblock-999999.0a1.0.tm
  4. 527
      src/vendormodules/overtype-1.6.0.tm

294
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 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 effectively auto-expands the block(terminal?) width
#overflow and wrap both being true won't make sense unless we implement a max_overflow concept #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 -appendlines 1 "" [$o_ansistringobj get]] set o_rendered [overtype::left -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
if {$cksum eq "not-done"} { if {$cksum eq "not-done"} {
#if dimensions changed - the checksum won't have been done #if dimensions changed - the checksum won't have been done
set o_rendered_what [$o_ansistringobj checksum] set o_rendered_what [$o_ansistringobj checksum]
@ -129,10 +129,41 @@ namespace eval punk::ansi::class {
set o_dimensions $dimensions set o_dimensions $dimensions
set rendered [overtype::left -experimental {test_mode} -overflow 0 -wrap 1 -width $w -appendlines 1 "" [$o_ansistringobj get]] set rendered [overtype::left -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" [$o_ansistringobj get]]
return $rendered return $rendered
} }
method render_to_input_line {x {minuschar 0}} { method render_to_input_line {args} {
if {[llength $args] < 1} {
puts stderr "render_to_input_line usage: ?-dimensions WxH? ?-minus charcount? x"
}
set x [lindex $args end]
set arglist [lrange $args 0 end-1]
if {[llength $arglist] %2 != 0} {
puts stderr "render_to_input_line usage: ?-dimensions WxH? ?-minus charcount? x"
}
set defaults [dict create\
-dimensions 80x24\
-minus 0\
]
dict for {k v} $arglist {
switch -- $k {
-dimensions - -minus { }
default {
puts stderr "render_to_input_line unexpected argument '$k' usage: ?-dimensions WxH? ?-minus charcount? x"
}
}
}
set opts [dict merge $defaults $arglist]
set opt_dimensions [dict get $opts -dimensions]
set opt_minus [dict get $opts -minus]
lassign [split $opt_dimensions x] w h
if {![string is integer -strict $w] || ![string is integer -strict $h] || $w < 1 || $h < 1} {
puts stderr "render_to_input_line WxH width & height must be positive integer values usage: ?-dimensions WxH? ?-minus charcount? x"
}
if {![string is integer -strict $opt_minus]} {
puts stderr "render_to_input_line -minus must be positive integer value representing number of chars to exclude from end. usage: ?-dimensions WxH? ?-minus charcount? x"
}
package require textblock package require textblock
set lfvis [ansistring VIEW -lf 1 \n] set lfvis [ansistring VIEW -lf 1 \n]
set maplf [list \n "[a+ green bold reverse]${lfvis}[a]\n"] ;#a mapping to highlight newlines set maplf [list \n "[a+ green bold reverse]${lfvis}[a]\n"] ;#a mapping to highlight newlines
@ -141,12 +172,12 @@ namespace eval punk::ansi::class {
set rlines [lrange $lines 0 $x] set rlines [lrange $lines 0 $x]
set chunk [::join $rlines \n] set chunk [::join $rlines \n]
append chunk \n append chunk \n
if {$minuschar ne "0"} { if {$opt_minus ne "0"} {
set chunk [string range $chunk 0 end-$minuschar] set chunk [string range $chunk 0 end-$opt_minus]
} }
set rendered [overtype::left -experimental {test_mode} -overflow 0 -wrap 1 -width 80 -appendlines 1 "" $chunk] set rendered [overtype::left -experimental {test_mode} -overflow 0 -wrap 1 -width $w -height $h -appendlines 1 "" $chunk]
set marker "" set marker ""
for {set i 1} {$i <= 80} {incr i} { for {set i 1} {$i <= $w} {incr i} {
if {$i % 10 == 0} { if {$i % 10 == 0} {
::append marker "|" ::append marker "|"
} elseif {$i % 5 == 0} { } elseif {$i % 5 == 0} {
@ -159,13 +190,19 @@ namespace eval punk::ansi::class {
set xline [lindex $rlines $x]\n set xline [lindex $rlines $x]\n
set xlinev [ansistring VIEWSTYLE $xline] set xlinev [ansistring VIEWSTYLE $xline]
set xlinev [string map $maplf $xlinev] set xlinev [string map $maplf $xlinev]
set xlinedisplay [overtype::left -wrap 1 -width 80 "" $xlinev] set xlinedisplay [overtype::left -wrap 1 -width $w -height 1 "" $xlinev]
::append rendered \n $xlinedisplay ::append rendered \n $xlinedisplay
set chunk [ansistring VIEWSTYLE $chunk] set chunk [ansistring VIEWSTYLE $chunk]
set chunk [string map $maplf $chunk] set chunk [string map $maplf $chunk]
set chunkdisplay [overtype::left -wrap 1 -width 80 "" $chunk] #keep chunkdisplay narrower - leave at 80 or it will get unwieldy for larger image widths
textblock::join $rendered $chunkdisplay set chunkdisplay [overtype::left -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]
set chunkdisplay_block [join $chunkdisplay_tail \n]
#the input chunk lines are often much longer than the output.. resulting in main content being way up the screen. It's often impractical to view more than the tail of the chunkdisplay.
textblock::join $rendered $chunkdisplay_block
} }
method checksum {} { method checksum {} {
@ -335,6 +372,43 @@ namespace eval punk::ansi {
] ]
# --------------------------------------
#comparitive test (performance) string-append vs 2-object (with existing splits) append
proc test_cat1 {ansi1 ansi2} {
#make sure objects have splits
set s1 [ansistring NEW $ansi1]
namespace eval [info object namespace $s1] {my MakeSplit}
set s2 [ansistring NEW $ansi2]
namespace eval [info object namespace $s2] {my MakeSplit}
#operation under test
# --
#standard string append
$s1 append $ansi2
# --
#$s1 append \033\[31mX ;#redX
return $s1
}
proc test_cat2 {ansi1 ansi2} {
#make sure objects have splits
set s1 [ansistring NEW $ansi1]
namespace eval [info object namespace $s1] {my MakeSplit}
set s2 [ansistring NEW $ansi2]
namespace eval [info object namespace $s2] {my MakeSplit}
#operation under test
# --
#ansistring object append
$s1 appendobj $s2
# --
#$s1 append \033\[31mX ;#redX
return $s1
}
# --------------------------------------
#review - We have file possibly encoded directly in another codepage such as 437 - or utf8,utf16 etc, but then still needing post conversion to e.g cp437? #review - We have file possibly encoded directly in another codepage such as 437 - or utf8,utf16 etc, but then still needing post conversion to e.g cp437?
#In testing old ansi graphics files available on the web, some files need encoding {utf-8 cp437} some just cp437 #In testing old ansi graphics files available on the web, some files need encoding {utf-8 cp437} some just cp437
proc readfile {fname {encoding cp437}} { proc readfile {fname {encoding cp437}} {
@ -376,7 +450,7 @@ namespace eval punk::ansi {
} }
if {$dimensions eq ""} { if {$dimensions eq ""} {
set dimensions 80x26 set dimensions 80x24
} }
set ansidata [fcat -encoding $encoding $fname] set ansidata [fcat -encoding $encoding $fname]
@ -2587,6 +2661,9 @@ namespace eval punk::ansi::class {
set codestack [list] set codestack [list]
set gx0_state 0 ;#default off set gx0_state 0 ;#default off
set current_split_index 0 ;#incremented for each pt block, incremented for each code set current_split_index 0 ;#incremented for each pt block, incremented for each code
if {$o_count eq ""} {
set o_count 0
}
foreach {pt code} $o_ansisplits { foreach {pt code} $o_ansisplits {
lappend o_ptlist $pt lappend o_ptlist $pt
foreach grapheme [punk::char::grapheme_split $pt] { foreach grapheme [punk::char::grapheme_split $pt] {
@ -2594,6 +2671,7 @@ namespace eval punk::ansi::class {
lappend o_sgrstacks $codestack lappend o_sgrstacks $codestack
lappend o_gx0states $gx0_state lappend o_gx0states $gx0_state
lappend o_splitindex $current_split_index lappend o_splitindex $current_split_index
incr o_count
} }
#after handling the pt block - incr the current_split_index #after handling the pt block - incr the current_split_index
incr current_split_index ;#increment for each pt block - whether empty string or not. Indices corresponding to empty PT blocks will therefore not be present in o_splitindex as there were no elements in that ansisplit entry incr current_split_index ;#increment for each pt block - whether empty string or not. Indices corresponding to empty PT blocks will therefore not be present in o_splitindex as there were no elements in that ansisplit entry
@ -2605,7 +2683,7 @@ namespace eval punk::ansi::class {
#maintenance warning - dup in append! #maintenance warning - dup in append!
if {[punk::ansi::codetype::is_sgr_reset $code]} { if {[punk::ansi::codetype::is_sgr_reset $code]} {
set codestack [list] set codestack [list "\x1b\[m"]
lappend o_elements [list sgr $code] lappend o_elements [list sgr $code]
} elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} {
set codestack [list $code] set codestack [list $code]
@ -2669,7 +2747,7 @@ namespace eval punk::ansi::class {
return 0 return 0
} }
my MakeSplit my MakeSplit
set o_count [my DoCount [join $o_ptlist ""]] #set o_count [my DoCount [join $o_ptlist ""]]
} }
return $o_count return $o_count
} }
@ -2823,15 +2901,16 @@ namespace eval punk::ansi::class {
lappend o_sgrstacks $last_codestack lappend o_sgrstacks $last_codestack
lappend o_gx0states $last_gx0state lappend o_gx0states $last_gx0state
lappend o_splitindex $current_split_index lappend o_splitindex $current_split_index
incr o_count
} }
incr o_count [my DoCount $catstr] #incr o_count [my DoCount $catstr] ;#from before we were doing grapheme split.. review
} else { } else {
if {![llength $o_ansisplits]} { if {![llength $o_ansisplits]} {
#if we have an initial string - but no internal split-state because this is our first append and no methods have caused its generation - we can run more efficiently by combining it with the first append #if we have an initial string - but no internal split-state because this is our first append and no methods have caused its generation - we can run more efficiently by combining it with the first append
append o_string $catstr ;#append before split and count on whole lot append o_string $catstr ;#append before split and count on whole lot
my MakeSplit my MakeSplit ;#update o_count
set combined_plaintext [join $o_ptlist ""] #set combined_plaintext [join $o_ptlist ""]
set o_count [my DoCount $combined_plaintext] #set o_count [my DoCount $combined_plaintext]
assert {[llength $o_elements] == [llength $o_sgrstacks] && [llength $o_elements] == [llength $o_gx0states] && [llength $o_elements] == [llength $o_splitindex]} assert {[llength $o_elements] == [llength $o_sgrstacks] && [llength $o_elements] == [llength $o_gx0states] && [llength $o_elements] == [llength $o_splitindex]}
return $o_string return $o_string
} else { } else {
@ -2841,15 +2920,18 @@ namespace eval punk::ansi::class {
set ptnew "" set ptnew ""
set codestack [lindex $o_sgrstacks end] set codestack [lindex $o_sgrstacks end]
set gx0_state [lindex $o_gx0states end] set gx0_state [lindex $o_gx0states end]
set current_split_index 0 set current_split_index [lindex $o_splitindex end]
#first pt must be merged with last element of o_ptlist
set new_pt_list [list]
foreach {pt code} $newsplits { foreach {pt code} $newsplits {
lappend o_ptlist $pt lappend new_pt_list $pt
append ptnew $pt append ptnew $pt
foreach grapheme [punk::char::grapheme_split $catstr] { foreach grapheme [punk::char::grapheme_split $pt] {
lappend o_elements [list g $grapheme] lappend o_elements [list g $grapheme]
lappend o_sgrstacks $codestack lappend o_sgrstacks $codestack
lappend o_gx0states $gx0_state lappend o_gx0states $gx0_state
lappend o_splitindex $current_split_index lappend o_splitindex $current_split_index
incr o_count
} }
incr current_split_index ;#increment 1 of 2 within each loop incr current_split_index ;#increment 1 of 2 within each loop
if {$code ne ""} { if {$code ne ""} {
@ -2858,7 +2940,7 @@ namespace eval punk::ansi::class {
lappend o_splitindex $current_split_index lappend o_splitindex $current_split_index
#maintenance - dup in MakeSplit! #maintenance - dup in MakeSplit!
if {[punk::ansi::codetype::is_sgr_reset $code]} { if {[punk::ansi::codetype::is_sgr_reset $code]} {
set codestack [list] set codestack [list "\x1b\[m"]
lappend o_elements [list sgr $code] lappend o_elements [list sgr $code]
} elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} {
set codestack [list $code] set codestack [list $code]
@ -2883,14 +2965,78 @@ namespace eval punk::ansi::class {
incr current_split_index ;#increment 2 of 2 incr current_split_index ;#increment 2 of 2
} }
} }
lset o_ptlist end [string cat [lindex $o_ptlist end] [lindex $new_pt_list 0]]
lappend o_ptlist {*}[lrange $new_pt_list 1 end]
lset o_ansisplits end [string cat [lindex $o_ansisplits end] [lindex $newsplits 0]] lset o_ansisplits end [string cat [lindex $o_ansisplits end] [lindex $newsplits 0]]
lappend o_ansisplits {*}[lrange $newsplits 1 end] lappend o_ansisplits {*}[lrange $newsplits 1 end]
incr o_count [my DoCount $ptnew]
#if {$o_count eq ""} {
# #we have splits - but didn't count graphemes?
# set o_count [my DoCount [join $o_ptlist ""]] ;#o_ptlist already has ptnew parts
#} else {
# incr o_count [my DoCount $ptnew]
#}
} }
} }
assert {[llength $o_elements] == [llength $o_sgrstacks] && [llength $o_elements] == [llength $o_gx0states] && [llength $o_elements] == [llength $o_splitindex]} assert {[llength $o_elements] == [llength $o_sgrstacks] && [llength $o_elements] == [llength $o_gx0states] && [llength $o_elements] == [llength $o_splitindex]}
return $o_string return $o_string
} }
#we are currently assuming that the component strings have complete graphemes ie no split clusters - and therefore we don't attempt to check for and combine at the string catenation points.
#This is 'often'? likely to be true - We don't have grapheme cluster support yet anyway. review.
method appendobj {args} {
if {![llength $o_ansisplits]} {
my MakeSplit
}
foreach a $args {
set ns [info object namespace $a]
upvar ${ns}::o_ansisplits new_ansisplits
upvar ${ns}::o_count new_count
if {![llength $new_ansisplits] || $new_count eq ""} {
namespace eval $ns {my MakeSplit}
}
upvar ${ns}::o_ptlist new_ptlist
upvar ${ns}::o_string new_string
upvar ${ns}::o_elements new_elements
upvar ${ns}::o_sgrstacks new_sgrstacks
upvar ${ns}::o_gx0states new_gx0states
upvar ${ns}::o_splitindex new_splitindex
lset o_ansisplits end [string cat [lindex $o_ansisplits end] [lindex $new_ansisplits 0]]
lappend o_ansisplits {*}[lrange $new_ansisplits 1 end]
lset o_ptlist end [string cat [lindex $o_ptlist end] [lindex $new_ptlist 0]]
lappend o_ptlist {*}[lrange $new_ptlist 1 end]
append o_string $new_string
lappend o_elements {*}$new_elements
#prepend the previous sgr stack to all stacks in the new list.
#This allows us to use only list operations to keep the sgr data valid - but we don't yet make it canonical/flat by examining each for resets etc.
#ie just call sgr_merge_list once now.
set laststack [lindex $o_sgrstacks end]
set mergedtail [punk::ansi::codetype::sgr_merge_list "" {*}$laststack]
foreach n $new_sgrstacks {
lappend o_sgrstacks [list $mergedtail {*}$n]
}
lappend o_gx0states {*}$new_gx0states
#first and last of ansisplits splits merge
set lastidx [lindex $o_splitindex end]
set firstnewidx [lindex $new_splitindex 0]
set diffidx [expr {$lastidx - $firstnewidx}] ;#may be negative
foreach v $new_splitindex {
lappend o_splitindex [expr {$v + $diffidx}]
}
incr o_count $new_count
}
return $o_count
}
#method append_and_render - append and render up to end of appended data at same time #method append_and_render - append and render up to end of appended data at same time
method view {args} { method view {args} {
@ -2941,14 +3087,50 @@ namespace eval punk::ansi::class {
foreach {pt code} $o_ansisplits { foreach {pt code} $o_ansisplits {
append output [ansistring VIEW {*}$args $pt] append output [ansistring VIEW {*}$args $pt]
#map DEC cursor_save/restore to CSI version
set code [string map [list \x1b7 \x1b\[s \x1b8 \x1b\[u ] $code]
set c1 [string index $code 0]
set c1c2 [string range $code 0 1]
#set re_ST_open {(?:\033P|\u0090|\033X|\u0098|\033\^|\u009e|\033_|\u009f)}
set leadernorm [string range [string map [list\
\x1b\[ 7CSI\
\x9b 8CSI\
\x1b\] 7OSC\
\x1b\( 7GFX\
\x9d 8OSC\
\x1b 7ESC\
] $c1c2] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars
#we leave the tail of the code unmapped for now
switch -- $leadernorm {
7CSI - 7OSC {
set codenorm [string cat $leadernorm [string range $code 2 end]]
}
7ESC {
set codenorm [string cat $leadernorm [string range $code 1 end]]
}
8CSI - 8OSC {
set codenorm [string cat $leadernorm [string range $code 1 end]]
}
default {
#we haven't made a mapping for this
set codenorm $code
}
}
switch -- $leadernorm {
{7CSI} - {8CSI} {
set param [string range $codenorm 4 end-1]
#puts stdout "--> CSI [string index $leadernorm 0] bit param:$param"
switch -- [string index $codenorm end] {
m {
if {[punk::ansi::codetype::is_sgr_reset $code]} { if {[punk::ansi::codetype::is_sgr_reset $code]} {
set displaycode [ansistring VIEW $code] set displaycode [ansistring VIEW $code]
append output ${whiteb}$displaycode$RST append output ${whiteb}$displaycode$RST
} elseif {[punk::ansi::codetype::is_gx_open $code]} { } else {
append output ${GX}GX+$RST
} elseif {[punk::ansi::codetype::is_gx_close $code]} {
append output ${GX}GX-$RST
} elseif {[punk::ansi::codetype::is_sgr $code]} {
set displaycode [ansistring VIEW $code] set displaycode [ansistring VIEW $code]
if {[punk::ansi::codetype::has_sgr_leadingreset $code]} { if {[punk::ansi::codetype::has_sgr_leadingreset $code]} {
#highlight the esc & leftbracket in white as indication there is a leading reset #highlight the esc & leftbracket in white as indication there is a leading reset
@ -2957,46 +3139,66 @@ namespace eval punk::ansi::class {
} else { } else {
append output ${greenb}$displaycode$RST append output ${greenb}$displaycode$RST
} }
} else { }
switch -regexp -matchvar matchinfo -- $code\ }
$re_row_move { A - B {
#row move
set displaycode [ansistring VIEW $code] set displaycode [ansistring VIEW $code]
set displaycode [string map [list A "A$arrow_up" B "B$arrow_down"] $displaycode] set displaycode [string map [list A "A$arrow_up" B "B$arrow_down"] $displaycode]
append output ${cyanb}$displaycode$RST append output ${cyanb}$displaycode$RST
}\
$re_col_move { }
lassign $matchinfo _match num type C - D - G {
#set num [string range $codenorm 4 end-1]
set displaycode [ansistring VIEW $code] set displaycode [ansistring VIEW $code]
set displaycode [string map [list C "C$arrow_right" D "D$arrow_left" G "G$arrow_lr"] $displaycode] set displaycode [string map [list C "C$arrow_right" D "D$arrow_left" G "G$arrow_lr"] $displaycode]
append output ${cyanb}$displaycode$RST append output ${cyanb}$displaycode$RST
}\ }
$re_both_move { H - f {
lassign $matchinfo _match row col set params [string range $codenorm 4 end-1]
lassign [split $params {;}] row col
#lassign $matchinfo _match row col
set displaycode [ansistring VIEW $code] set displaycode [ansistring VIEW $code]
if {$col eq ""} { if {$col eq ""} {
#row only move #row only move
set map [list H "H${arrow_lr}"] set map [list H "H${arrow_lr}" f "f${arrow_lr}]
} else { } else {
#row and col move #row and col move
set map [list H "H${arrow_lr}${arrow_du}"] set map [list H "H${arrow_lr}${arrow_du}" f "${arrow_lr}${arrow_du}"]
} }
set displaycode [string map $map $displaycode] set displaycode [string map $map $displaycode]
append output ${cyanb}$displaycode$RST append output ${cyanb}$displaycode$RST
}\ }
$re_cursor_save -\ s {
$re_cursor_save_dec {
append output ${blueb}[ansistring VIEW $code]$RST append output ${blueb}[ansistring VIEW $code]$RST
}\ }
$re_cursor_restore -\ u {
$re_cursor_restore_dec {
append output ${blueb_r}[ansistring VIEW $code]$RST append output ${blueb_r}[ansistring VIEW $code]$RST
}\ }
default {
append output ${unk}[ansistring VIEW -lf 1 $code]$RST
}
}
}
7GFX {
switch -- [string index $codenorm 4] {
"0" {
append output ${GX}GX+$RST
}
"B" {
append output ${GX}GX-$RST
}
}
}
7ESC {
append output ${unk}[ansistring VIEW -lf 1 $code]$RST
}
default { default {
#if the code is a PM (or other encapsulation type code e.g terminated by ST) we want to see linefeeds as visual representation character #if the code is a PM (or other encapsulation type code e.g terminated by ST) we want to see linefeeds as visual representation character
append output ${unk}[ansistring VIEW -lf 1 $code]$RST append output ${unk}[ansistring VIEW -lf 1 $code]$RST
} }
} }
} }
return $output return $output
} }

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

@ -1140,9 +1140,11 @@ namespace eval punk::repl::class {
set result [dict get $mergedinfo result] set result [dict get $mergedinfo result]
set o_insert_mode [dict get $mergedinfo insert_mode] set o_insert_mode [dict get $mergedinfo insert_mode]
set result_col [dict get $mergedinfo cursor_column] set result_col [dict get $mergedinfo cursor_column]
set cmove [dict get $mergedinfo cursor_row] set result_row [dict get $mergedinfo cursor_row]
set overflow_right [dict get $mergedinfo overflow_right] ;#should be empty if no \v set overflow_right [dict get $mergedinfo overflow_right] ;#should be empty if no \v
set unapplied [dict get $mergedinfo unapplied] set unapplied [dict get $mergedinfo unapplied]
set instruction [dict get $mergedinfo instruction]
set insert_lines_below [dict get $mergedinfo insert_lines_below] set insert_lines_below [dict get $mergedinfo insert_lines_below]
set insert_lines_above [dict get $mergedinfo insert_lines_above] set insert_lines_above [dict get $mergedinfo insert_lines_above]
@ -1151,7 +1153,7 @@ namespace eval punk::repl::class {
#puts "merged: $mergedinfo" #puts "merged: $mergedinfo"
set debug "add_chunk0" set debug "add_chunk0"
append debug \n $mergedinfo append debug \n $mergedinfo
append debug \n "input:[ansistring VIEW -lf 1 -vt 1 $new0] before row:$o_cursor_row after row: $cmove before col:$o_cursor_col after col:$result_col" 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 package require textblock
set debug [textblock::frame $debug] set debug [textblock::frame $debug]
catch {punk::console::move_emitblock_return $debug_first_row 1 $debug} catch {punk::console::move_emitblock_return $debug_first_row 1 $debug}
@ -1161,13 +1163,16 @@ namespace eval punk::repl::class {
set cursor_row_idx [expr {$o_cursor_row-1}] set cursor_row_idx [expr {$o_cursor_row-1}]
lset o_rendered_lines $cursor_row_idx $result lset o_rendered_lines $cursor_row_idx $result
set nextrow $cmove set nextrow $result_row
#if {$insert_lines_below > 0} { switch -- $instruction {
# for {set i 0} {$i < $insert_lines_below} {incr i} { lf_start {
# lappend o_rendered_lines "" #for normal commandline - we just add a line below
# } lappend o_rendered_lines ""
# set o_cursor_col 1 incr nextrow
#} set o_cursor_col 1
}
}
if {$insert_lines_below == 1} { if {$insert_lines_below == 1} {
if {[string length $overflow_right]} { if {[string length $overflow_right]} {
lappend o_rendered_lines $overflow_right lappend o_rendered_lines $overflow_right

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

@ -364,11 +364,12 @@ namespace eval textblock {
-width ""\ -width ""\
-ansiborder ""\ -ansiborder ""\
-align "left"\ -align "left"\
-ellipsis 1\
] ]
set opts [dict merge $defaults $arglist] set opts [dict merge $defaults $arglist]
foreach {k v} $opts { foreach {k v} $opts {
switch -- $k { switch -- $k {
-etabs - -type - -title - -subtitle - -width - -ansiborder - -align {} -etabs - -type - -title - -subtitle - -width - -ansiborder - -align - -ellipsis {}
default { default {
error "frame option '$k' not understood. Valid options are [dict keys $defaults]" error "frame option '$k' not understood. Valid options are [dict keys $defaults]"
} }
@ -418,6 +419,7 @@ namespace eval textblock {
#these are all valid commands for overtype::<cmd> #these are all valid commands for overtype::<cmd>
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_ansiborder [dict get $opts -ansiborder] set opt_ansiborder [dict get $opts -ansiborder]
set opt_ellipsis [dict get $opts -ellipsis]
# -- --- --- --- --- --- # -- --- --- --- --- ---
if {[string last \t $contents] >= 0} { if {[string last \t $contents] >= 0} {
@ -638,7 +640,7 @@ namespace eval textblock {
set bottombar $bbar set bottombar $bbar
} }
append fs $tlc$topbar$trc\n append fs $tlc$topbar$trc\n
set inner [overtype::$opt_align -ellipsis 1 $column $contents] set inner [overtype::$opt_align -ellipsis $opt_ellipsis $column $contents]
set body [textblock::join -- $lhs $inner $rhs] set body [textblock::join -- $lhs $inner $rhs]
append fs $body append fs $body
append fs \n $blc$bottombar$brc append fs \n $blc$bottombar$brc

527
src/vendormodules/overtype-1.6.0.tm

@ -252,6 +252,7 @@ proc overtype::left {args} {
set defaults [dict create\ set defaults [dict create\
-bias ignored\ -bias ignored\
-width \uFFEF\ -width \uFFEF\
-height \uFFeF\
-wrap 0\ -wrap 0\
-ellipsis 0\ -ellipsis 0\
-ellipsistext $default_ellipsis_horizontal\ -ellipsistext $default_ellipsis_horizontal\
@ -262,13 +263,13 @@ proc overtype::left {args} {
-exposed1 \uFFFD\ -exposed1 \uFFFD\
-exposed2 \uFFFD\ -exposed2 \uFFFD\
-experimental 0\ -experimental 0\
-looplimit 15000\ -looplimit 100000\
] ]
#-ellipsis args not used if -wrap is true #-ellipsis args not used if -wrap is true
set argsflags [lrange $args 0 end-2] set argsflags [lrange $args 0 end-2]
dict for {k v} $argsflags { dict for {k v} $argsflags {
switch -- $k { switch -- $k {
-looplimit - -width - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 - -experimental {} -looplimit - -width - -height - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 - -experimental {}
default { default {
set known_opts [dict keys $defaults] set known_opts [dict keys $defaults]
error "overtype::left unknown option '$k'. Known options: $known_opts" error "overtype::left unknown option '$k'. Known options: $known_opts"
@ -284,6 +285,7 @@ proc overtype::left {args} {
##### #####
#for repl - standard output line indicator is a dash - todo, add a different indicator for a continued line. #for repl - standard output line indicator is a dash - todo, add a different indicator for a continued line.
set opt_width [dict get $opts -width] set opt_width [dict get $opts -width]
set opt_height [dict get $opts -height]
set opt_appendlines [dict get $opts -appendlines] set opt_appendlines [dict get $opts -appendlines]
set opt_transparent [dict get $opts -transparent] set opt_transparent [dict get $opts -transparent]
set opt_ellipsistext [dict get $opts -ellipsistext] set opt_ellipsistext [dict get $opts -ellipsistext]
@ -337,9 +339,12 @@ proc overtype::left {args} {
lassign [blocksize $underblock] _w colwidth _h colheight lassign [blocksize $underblock] _w colwidth _h colheight
} else { } else {
set colwidth $opt_width set colwidth $opt_width
set colheight $opt_height
} }
if {$underblock eq ""} { if {$underblock eq ""} {
set underlines [list "\x1b\[0m\x1b\[0m"] set blank "\x1b\[0m\x1b\[0m"
#set underlines [list "\x1b\[0m\x1b\[0m"]
set underlines [lrepeat $colheight $blank]
} else { } else {
set underlines [lines_as_list -ansiresets 1 $underblock] set underlines [lines_as_list -ansiresets 1 $underblock]
} }
@ -347,7 +352,10 @@ proc overtype::left {args} {
#todo - reconsider the 'line' as the natural chunking mechanism for the overlay. #todo - reconsider the 'line' as the natural chunking mechanism for the overlay.
#In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output colwidth #In practice an overlay ANSI stream can be a single line with ansi moves/restores etc - or even have no moves or newlines, just relying on wrapping at the output colwidth
#In such cases - we process the whole shebazzle for the first output line - only reducing by the applied amount at the head each time, reprocessing the long tail each time. #In such cases - we process the whole shebazzle for the first output line - only reducing by the applied amount at the head each time, reprocessing the long tail each time.
#(in cases where there are interline moves or cursor jumps anyway)
#This works - but doesn't seem efficient. #This works - but doesn't seem efficient.
#On the other hand.. maybe it depends on the data. For simpler files it's more efficient than splitting first
if 0 {
set inputchunks [split $overblock \n] set inputchunks [split $overblock \n]
if {$test_mode} { if {$test_mode} {
set lflines [list] set lflines [list]
@ -360,6 +368,53 @@ proc overtype::left {args} {
} }
set inputchunks $lflines[unset lflines] set inputchunks $lflines[unset lflines]
} }
}
if {!$test_mode} {
set inputchunks [split $overblock \n]
} else {
set scheme 3
switch -- $scheme {
0 {
set inputchunks [list $overblock]
}
1 {
set inputchunks [punk::ansi::ta::split_codes $overblock]
}
2 {
#split into lines if possible first - then into plaintext/ansi-sequence chunks ?
set inputchunks [list ""] ;#put an empty plaintext split in for starters
set i 1
set lines [split $overblock \n]
foreach ln $lines {
if {$i < [llength $lines]} {
append ln \n
}
set sequence_split [punk::ansi::ta::split_codes_single $ln] ;#use split_codes Not split_codes_single?
set lastpt [lindex $inputchunks end]
lset inputchunks end [string cat $lastpt [lindex $sequence_split 0]]
lappend inputchunks {*}[lrange $sequence_split 1 end]
incr i
}
}
3 {
set lflines [list]
set inputchunks [split $overblock \n]
foreach ln $inputchunks {
append ln \n
lappend lflines $ln
}
if {[llength $lflines]} {
lset lflines end [string range [lindex $lflines end] 0 end-1]
}
set inputchunks $lflines[unset lflines]
}
}
}
#overblock height/width isn't useful in the presence of an ansi input overlay with movements. The number of lines may bear little relationship to the output height #overblock height/width isn't useful in the presence of an ansi input overlay with movements. The number of lines may bear little relationship to the output height
#lassign [blocksize $overblock] _w overblock_width _h overblock_height #lassign [blocksize $overblock] _w overblock_width _h overblock_height
@ -391,6 +446,10 @@ proc overtype::left {args} {
while {[llength $inputchunks]} { while {[llength $inputchunks]} {
#set overtext [lindex $inputchunks $overidx]; lset inputchunks $overidx "" #set overtext [lindex $inputchunks $overidx]; lset inputchunks $overidx ""
set overtext [lpop inputchunks 0] set overtext [lpop inputchunks 0]
if {![string length $overtext]} {
continue
}
#puts "----->[ansistring VIEW -lf 1 -vt 1 -nul 1 $overtext]<----"
set undertext [lindex $outputlines [expr {$row -1}]] set undertext [lindex $outputlines [expr {$row -1}]]
set renderedrow $row set renderedrow $row
@ -428,8 +487,9 @@ proc overtype::left {args} {
#-- todo - detect looping properly #-- todo - detect looping properly
if {$row > 1 && $overtext ne "" && $unapplied eq $overtext && $post_render_row == $row} { if {$row > 1 && $overtext ne "" && $unapplied eq $overtext && $post_render_row == $row && $instruction eq ""} {
puts stderr "overtype::left loop?" puts stderr "overtype::left loop?"
puts [ansistring VIEW $rinfo]
break break
} }
#-- #--
@ -496,7 +556,9 @@ proc overtype::left {args} {
} else { } else {
#lf included in data #lf included in data
set row $post_render_row set row $post_render_row
set col 1 set col $post_render_col
#set col 1
#if {$post_render_row != $renderedrow} { #if {$post_render_row != $renderedrow} {
# set col 1 # set col 1
#} else { #} else {
@ -617,17 +679,17 @@ proc overtype::left {args} {
} }
move { move {
######## ########
#Ansi moves need to create new lines
if {$post_render_row > [llength $outputlines]} { if {$post_render_row > [llength $outputlines]} {
if {$opt_appendlines} { #Ansi moves need to create new lines ?
set diff [expr {$post_render_row - [llength $outputlines]}] #if {$opt_appendlines} {
if {$diff > 0} { # set diff [expr {$post_render_row - [llength $outputlines]}]
lappend outputlines {*}[lrepeat $diff ""] # if {$diff > 0} {
} # lappend outputlines {*}[lrepeat $diff ""]
set row $post_render_row # }
} else { # set row $post_render_row
#} else {
set row [llength $outputlines] set row [llength $outputlines]
} #}
} else { } else {
set row $post_render_row set row $post_render_row
} }
@ -666,7 +728,7 @@ proc overtype::left {args} {
puts [textblock::join $lhs " $post_render_col " $rhs] puts [textblock::join $lhs " $post_render_col " $rhs]
} }
if 1 { if {!$test_mode} {
#rendered #rendered
append rendered $overflow_right append rendered $overflow_right
#set replay_codes_overlay "" #set replay_codes_overlay ""
@ -675,22 +737,33 @@ proc overtype::left {args} {
set row $renderedrow set row $renderedrow
set col 1
incr row incr row
#only add newline if we're at the bottom #only add newline if we're at the bottom
if {$row > [llength $outputlines]} { if {$row > [llength $outputlines]} {
lappend outputlines {*}[lrepeat 1 ""] lappend outputlines {*}[lrepeat 1 ""]
} }
set col 1
} else { } else {
set edit_mode 0
if {$edit_mode} {
set inputchunks [linsert $inputchunks 0 $overflow_right$unapplied] set inputchunks [linsert $inputchunks 0 $overflow_right$unapplied]
set overflow_right "" set overflow_right ""
set unapplied "" set unapplied ""
set row $renderedrow set row $post_render_row
set col $post_render_col #set col $post_render_col
set col 1
if {$row > [llength $outputlines]} { if {$row > [llength $outputlines]} {
lappend outputlines {*}[lrepeat 1 ""] lappend outputlines {*}[lrepeat 1 ""]
} }
} else {
append rendered $overflow_right
set overflow_right ""
set row $post_render_row
set col 1
if {$row > [llength $outputlines]} {
lappend outputlines {*}[lrepeat 1 ""]
}
}
} }
} }
lf_overflow { lf_overflow {
@ -1523,29 +1596,56 @@ proc overtype::renderline {args} {
#underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here #underlay should already have been rendered and not have non-sgr codes - but let's retain the check for them and not stack them if other codes are here
#only stack SGR (graphics rendition) codes - not title sets, cursor moves etc #only stack SGR (graphics rendition) codes - not title sets, cursor moves etc
#order of if-else based on assumptions:
# that pure resets are fairly common - more so than leading resets with other info
# that non-sgr codes are not that common, so ok to check for resets before verifying it is actually SGR at all.
if {$code ne ""} { if {$code ne ""} {
set c1c2 [string range $code 0 1]
set leadernorm [string range [string map [list\
\x1b\[ 7CSI\
\x9b 8CSI\
\x1b\( 7GFX\
] $c1c2] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars
switch -- $leadernorm {
7CSI - 8CSI {
if {[string index $code end] eq "m"} {
if {[punk::ansi::codetype::is_sgr_reset $code]} { if {[punk::ansi::codetype::is_sgr_reset $code]} {
#set u_codestack [list]
set u_codestack [list "\x1b\[m"] set u_codestack [list "\x1b\[m"]
} elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} {
set u_codestack [list $code] set u_codestack [list $code]
} elseif {[punk::ansi::codetype::is_sgr $code]} { } else {
#basic simplification first.. straight dups #basic simplification first.. straight dups
set dup_posns [lsearch -all -exact $u_codestack $code] ;#-exact because of square-bracket glob chars set dup_posns [lsearch -all -exact $u_codestack $code] ;#-exact because of square-bracket glob chars
set u_codestack [lremove $u_codestack {*}$dup_posns] set u_codestack [lremove $u_codestack {*}$dup_posns]
lappend u_codestack $code lappend u_codestack $code
} else { }
#leave SGR stack as is }
if {[punk::ansi::codetype::is_gx_open $code]} { }
7GFX {
switch -- [string index $code 2] {
"0" {
set u_gx_stack [list gx0_on] ;#we'd better use a placeholder - or debugging will probably get into a big mess set u_gx_stack [list gx0_on] ;#we'd better use a placeholder - or debugging will probably get into a big mess
} elseif {[punk::ansi::codetype::is_gx_close $code]} { }
B {
set u_gx_stack [list] set u_gx_stack [list]
} }
} }
} }
default {
}
}
#if {[punk::ansi::codetype::is_sgr_reset $code]} {
# #set u_codestack [list]
#} elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} {
#} elseif {[punk::ansi::codetype::is_sgr $code]} {
#} else {
# #leave SGR stack as is
# if {[punk::ansi::codetype::is_gx_open $code]} {
# } elseif {[punk::ansi::codetype::is_gx_close $code]} {
# }
#}
}
#consider also if there are other codes that should be stacked..? #consider also if there are other codes that should be stacked..?
} }
@ -1813,34 +1913,26 @@ proc overtype::renderline {args} {
"<lf>" { "<lf>" {
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
if {$idx == 0} { if {$idx == 0} {
#leave the overflow_idx #puts "---a <lf> at col 1"
#idx_over already incremented #linefeed at column 1
#leave the overflow_idx ;#? review
set instruction lf_start ;#specific instruction for newline at column 1 set instruction lf_start ;#specific instruction for newline at column 1
priv::render_unapplied $overlay_grapheme_control_list $gci priv::render_unapplied $overlay_grapheme_control_list $gci
break break
} elseif {$overflow_idx != -1 && $idx == $overflow_idx} { } elseif {$overflow_idx != -1 && $idx == $overflow_idx} {
puts "---c <lf> at overflow_idx=$overflow_idx" #linefeed after final column
#puts "---c <lf> at overflow_idx=$overflow_idx"
# - review special treatment?
incr cursor_row incr cursor_row
#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2 set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2
set overflow_idx $idx set instruction lf_overflow ;#only special treatment is to give it it's own instruction in case caller needs to handle differently
#set insert_lines_below 1
#set instruction newlines_below
set instruction lf_overflow
#idx_over already incremented
priv::render_unapplied $overlay_grapheme_control_list $gci priv::render_unapplied $overlay_grapheme_control_list $gci
break break
} else { } else {
#puts "---mid-or-end-text-linefeed idx:$idx overflow_idx:$overflow_idx"
#linefeed occurred in middle or at end of text #linefeed occurred in middle or at end of text
#puts "---mid-or-end-text-linefeed idx:$idx overflow_idx:$overflow_idx"
incr cursor_row incr cursor_row
#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2 set overflow_idx $idx ;#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2
set overflow_idx $idx
#set insert_lines_below 1
#set instruction newlines_below
set instruction lf_mid set instruction lf_mid
#idx_over already incremented
priv::render_unapplied $overlay_grapheme_control_list $gci priv::render_unapplied $overlay_grapheme_control_list $gci
break break
} }
@ -2075,7 +2167,7 @@ proc overtype::renderline {args} {
} }
incr idx incr idx
} }
if {($cursor_column < [llength $outcols]) || $overflow_idx == -1} { if {($cursor_column < [llength $outcols]) || $overflow_idx == -1 || $test_mode} {
incr cursor_column incr cursor_column
} }
} elseif {$uwidth > 1} { } elseif {$uwidth > 1} {
@ -2109,7 +2201,7 @@ proc overtype::renderline {args} {
priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode
incr idx incr idx
incr cursor_column incr cursor_column
if {$overflow_idx !=-1} { if {$overflow_idx !=-1 && !$test_mode} {
#overflow #overflow
if {$cursor_column > [llength $outcols]} { if {$cursor_column > [llength $outcols]} {
set cursor_column [llength $outcols] set cursor_column [llength $outcols]
@ -2139,13 +2231,52 @@ proc overtype::renderline {args} {
set re_decstbm {\x1b\[([0-9]*)(?:;){0,1}([0-9]*)r$} ;#DECSTBM set top and bottom margins set re_decstbm {\x1b\[([0-9]*)(?:;){0,1}([0-9]*)r$} ;#DECSTBM set top and bottom margins
set matchinfo [list] set matchinfo [list]
switch -regexp -matchvar matchinfo -- $code\ #remap of DEC cursor_save/cursor_restore from ESC sequence to equivalent CSI
$re_col_move { #probably not ideal - consider putting cursor_save/cursor_restore in functions so they can be called from the appropriate switch branch instead of using this mapping
lassign $matchinfo _match num type #review - cost/benefit of function calls within these switch-arms instead of inline code?
switch -- $type { set code [string map [list \x1b7 \x1b\[s \x1b8 \x1b\[u ] $code]
set c1 [string index $code 0]
set c1c2 [string range $code 0 1]
#set re_ST_open {(?:\033P|\u0090|\033X|\u0098|\033\^|\u009e|\033_|\u009f)}
set leadernorm [string range [string map [list\
\x1b\[ 7CSI\
\x9b 8CSI\
\x1b\] 7OSC\
\x9d 8OSC\
\x1b 7ESC\
] $c1c2] 0 3] ;#leadernorm is 1st 2 chars mapped to 4char normalised indicator - or is original 2 chars
#we leave the tail of the code unmapped for now
switch -- $leadernorm {
7CSI - 7OSC {
set codenorm [string cat $leadernorm [string range $code 2 end]]
}
7ESC {
set codenorm [string cat $leadernorm [string range $code 1 end]]
}
8CSI - 8OSC {
set codenorm [string cat $leadernorm [string range $code 1 end]]
}
default {
#we haven't made a mapping for this
set codenorm $code
}
}
#we've mapped 7 and 8bit escapes to values we can handle as literals in switch statements to take advantange of jump tables.
switch -- $leadernorm {
{7CSI} - {8CSI} {
set param [string range $codenorm 4 end-1]
#puts stdout "--> CSI [string index $leadernorm 0] bit param:$param"
switch -- [string index $codenorm end] {
D { D {
#Col move
#puts stdout "<-back"
#cursor back #cursor back
#left-arrow/move-back when ltr mode #left-arrow/move-back when ltr mode
set num $param
if {$num eq ""} {set num 1} if {$num eq ""} {set num 1}
set version 2 set version 2
@ -2177,9 +2308,12 @@ proc overtype::renderline {args} {
} }
} }
C { C {
#Col move
#puts stdout "->forward"
#todo - consider right-to-left cursor mode (e.g Hebrew).. some day. #todo - consider right-to-left cursor mode (e.g Hebrew).. some day.
#cursor forward #cursor forward
#right-arrow/move forward #right-arrow/move forward
set num $param
if {$num eq ""} {set num 1} if {$num eq ""} {set num 1}
#todo - retrict to moving 1 position past datalen? restrict to column width? #todo - retrict to moving 1 position past datalen? restrict to column width?
@ -2195,6 +2329,10 @@ proc overtype::renderline {args} {
if {$overflow_idx == -1} { if {$overflow_idx == -1} {
incr max incr max
} }
if {$test_mode && $cursor_column == $max+1} {
#move_forward while in overflow
incr cursor_column -1
}
if {($cursor_column + $num) <= $max} { if {($cursor_column + $num) <= $max} {
incr idx $num incr idx $num
@ -2202,9 +2340,11 @@ proc overtype::renderline {args} {
} else { } else {
if {$autowrap_mode} { if {$autowrap_mode} {
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#jmn
if {$idx == $overflow_idx} { if {$idx == $overflow_idx} {
incr num incr num
} }
#horizontal movement beyond line extent needs to wrap - throw back to caller #horizontal movement beyond line extent needs to wrap - throw back to caller
#we may have both overflow_rightand unapplied data #we may have both overflow_rightand unapplied data
#(can have overflow_right if we were in insert_mode and processed chars prior to this movement) #(can have overflow_right if we were in insert_mode and processed chars prior to this movement)
@ -2272,21 +2412,18 @@ proc overtype::renderline {args} {
} }
} }
G { G {
#Col move
#move absolute column #move absolute column
#adjust to colstart - as column 1 is within overlay #adjust to colstart - as column 1 is within overlay
#??? #???
set idx [expr {$num + $opt_colstart -1}] set idx [expr {$param + $opt_colstart -1}]
set cursor_column $num set cursor_column $param
error "renderline absolute col move ESC G unimplemented" error "renderline absolute col move ESC G unimplemented"
} }
}
}\
$re_row_move {
lassign $matchinfo _match num type
switch -- $type {
A { A {
#Row move - up
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move up set num $param
if {$num eq ""} {set num 1} if {$num eq ""} {set num 1}
incr cursor_row -$num incr cursor_row -$num
@ -2302,6 +2439,8 @@ proc overtype::renderline {args} {
break break
} }
B { B {
#Row move - down
set num $param
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move down #move down
if {$num eq ""} {set num 1} if {$num eq ""} {set num 1}
@ -2314,11 +2453,11 @@ proc overtype::renderline {args} {
#retain cursor_column #retain cursor_column
break break
} }
} H - f {
}\ #$re_both_move
$re_both_move { lassign [split $param {;}] row col
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
lassign $matchinfo _match row col #lassign $matchinfo _match row col
if {$col eq ""} {set col 1} if {$col eq ""} {set col 1}
set max [llength $outcols] set max [llength $outcols]
@ -2342,11 +2481,13 @@ proc overtype::renderline {args} {
priv::render_unapplied $overlay_grapheme_control_list $gci priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction move set instruction move
break break
}\
$re_decstbm { }
r {
#$re_decstbm
#https://www.vt100.net/docs/vt510-rm/DECSTBM.html #https://www.vt100.net/docs/vt510-rm/DECSTBM.html
#This control function sets the top and bottom margins for the current page. You cannot perform scrolling outside the margins #This control function sets the top and bottom margins for the current page. You cannot perform scrolling outside the margins
lassign $matchinfo _match margin_top margin_bottom lassign [split $param {;} margin_top margin_bottom]
#todo - return these for the caller to process.. #todo - return these for the caller to process..
puts stderr "overtype::renderline DECSTBM set top and bottom margin not implemented" puts stderr "overtype::renderline DECSTBM set top and bottom margin not implemented"
@ -2358,75 +2499,9 @@ proc overtype::renderline {args} {
priv::render_unapplied $overlay_grapheme_control_list $gci priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction move ;#own instruction? decstbm? set instruction move ;#own instruction? decstbm?
break break
}\
$re_vt_sequence {
lassign $matchinfo _match key mod
#Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~
#
#e.g esc \[2~ insert esc \[2;2~ shift-insert
#mod - subtract 1, and then use bitmask
#shift = 1, (left)Alt = 2, control=4, meta=8 (meta seems to do nothing on many terminals on windows? Intercepted by windows?)
#puts stderr "vt key:$key mod:$mod code:[ansistring VIEW $code]"
if {$key eq "1"} {
#home
} elseif {$key eq "2"} {
#Insert
if {$mod eq ""} {
#no modifier key
set insert_mode [expr {!$insert_mode}]
#rather than set the cursor - we return the insert mode state so the caller can decide
}
} elseif {$key eq "3"} {
#Delete - presumably this shifts other chars in the line, with empty cells coming in from the end
switch -- $mod {
"" {
priv::render_delchar $idx
}
"5" {
#ctrl-del - delete to end of word (pwsh) - possibly word on next line if current line empty(?)
}
}
} elseif {$key eq "4"} {
#End
} elseif {$key eq "5"} {
#pgup
} elseif {$key eq "6"} {
#pgDn
} elseif {$key eq "7"} {
#Home
#??
set idx [expr {$opt_colstart -1}]
set cursor_column 1
} elseif {$key eq "8"} {
#End
} elseif {$key eq "11"} {
#F1 - or ESCOP or e.g shift F1 ESC\[1;2P
} elseif {$key eq "12"} {
#F2 - or ESCOQ
} elseif {$key eq "13"} {
#F3 - or ESCOR
} elseif {$key eq "14"} {
#F4 - or ESCOS
} elseif {$key eq "15"} {
#F5 or shift F5 ESC\[15;2~
} elseif {$key eq "17"} {
#F6
} elseif {$key eq "18"} {
#F7
} elseif {$key eq "19"} {
#F8
} elseif {$key eq "20"} {
#F9
} elseif {$key eq "21"} {
#F10
} elseif {$key eq "23"} {
#F11
} elseif {$key eq "24"} {
#F12
} }
s {
}\ #$re_cursor_save
$re_cursor_save - $re_cursor_save_dec {
#cursor save could come after last column #cursor save could come after last column
if {$overflow_idx != -1 && $idx == $overflow_idx} { if {$overflow_idx != -1 && $idx == $overflow_idx} {
#bartman2.ans test file - fixes misalignment at bottom of dialog bubble #bartman2.ans test file - fixes misalignment at bottom of dialog bubble
@ -2493,8 +2568,10 @@ proc overtype::renderline {args} {
#don't incr index - or the save will cause cursor to move to the right #don't incr index - or the save will cause cursor to move to the right
#carry on #carry on
}\
$re_cursor_restore - $re_cursor_restore_dec { }
u {
#$re_cursor_restore
#we are going to jump somewhere.. for now we will assume another line, and process accordingly. #we are going to jump somewhere.. for now we will assume another line, and process accordingly.
#The caller has the cursor_saved_position/cursor_saved_attributes if any (?review - if we always pass it back it, we could save some calls for moves in same line) #The caller has the cursor_saved_position/cursor_saved_attributes if any (?review - if we always pass it back it, we could save some calls for moves in same line)
#don't set overflow at this point. The existing underlay to the right must be preserved. #don't set overflow at this point. The existing underlay to the right must be preserved.
@ -2528,52 +2605,89 @@ proc overtype::renderline {args} {
} }
#incr idx_over #incr idx_over
} }
#if the save occured within this line - that's ok - it's in the return value list and caller can prepend for the next loop. #if the save occured within this line - that's ok - it's in the return value list and caller can prepend for the next loop.
set instruction restore_cursor set instruction restore_cursor
break break
}\
$re_other_single {
lassign $matchinfo _match type
switch -- $type {
D {
#index (IND)
#vt102-docs: "Moves cursor down one line in same column. If cursor is at bottom margin, screen performs a scroll-up"
puts stderr "ESC D not fully implemented"
incr cursor_row
priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction down
#retain cursor_column
break
} }
M { ~ {
#Reverse Index (RI) #$re_vt_sequence
#vt102-docs: "Moves cursor up one line in same column. If cursor is at top margin, screen performs a scroll-down" #lassign $matchinfo _match key mod
puts stderr "ESC M not fully implemented" lassign [split $param {;}] key mod
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]] #Note that f1 to f4 show as ESCOP|Q|R|S (VT220?) but f5+ show as ESC\[15~
#move up #
incr cursor_row -1 #e.g esc \[2~ insert esc \[2;2~ shift-insert
if {$cursor_row < 1} { #mod - subtract 1, and then use bitmask
set cursor_row 1 #shift = 1, (left)Alt = 2, control=4, meta=8 (meta seems to do nothing on many terminals on windows? Intercepted by windows?)
#puts stderr "vt key:$key mod:$mod code:[ansistring VIEW $code]"
if {$key eq "1"} {
#home
} elseif {$key eq "2"} {
#Insert
if {$mod eq ""} {
#no modifier key
set insert_mode [expr {!$insert_mode}]
#rather than set the cursor - we return the insert mode state so the caller can decide
} }
#ensure rest of *overlay* is emitted to remainder } elseif {$key eq "3"} {
priv::render_unapplied $overlay_grapheme_control_list $gci #Delete - presumably this shifts other chars in the line, with empty cells coming in from the end
set instruction up ;#need instruction for scroll-down? switch -- $mod {
#retain cursor_column "" {
break priv::render_delchar $idx
} }
E { "5" {
#review - is behaviour different to 8bit c1 NEL \x85? lf? #ctrl-del - delete to end of word (pwsh) - possibly word on next line if current line empty(?)
#Next Line (NEL) }
puts stderr "ESC E" }
} elseif {$key eq "4"} {
#End
} elseif {$key eq "5"} {
#pgup
} elseif {$key eq "6"} {
#pgDn
} elseif {$key eq "7"} {
#Home
#??
set idx [expr {$opt_colstart -1}]
set cursor_column 1
} elseif {$key eq "8"} {
#End
} elseif {$key eq "11"} {
#F1 - or ESCOP or e.g shift F1 ESC\[1;2P
} elseif {$key eq "12"} {
#F2 - or ESCOQ
} elseif {$key eq "13"} {
#F3 - or ESCOR
} elseif {$key eq "14"} {
#F4 - or ESCOS
} elseif {$key eq "15"} {
#F5 or shift F5 ESC\[15;2~
} elseif {$key eq "17"} {
#F6
} elseif {$key eq "18"} {
#F7
} elseif {$key eq "19"} {
#F8
} elseif {$key eq "20"} {
#F9
} elseif {$key eq "21"} {
#F10
} elseif {$key eq "23"} {
#F11
} elseif {$key eq "24"} {
#F12
} }
} }
}\ h - l {
$re_mode { #we are matching only last char to get to this arm - but are there other sequences ending in h|l we need to handle?
lassign $matchinfo _match num type
#$re_mode if first after CSI is "?"
#some docs mention ESC=<mode>h|l - not seen on windows terminals.. review
#e.g https://www2.math.upenn.edu/~kazdan/210/computer/ansi.html
if {[string index $codenorm 4] eq "?"} {
set num [string range $codenorm 5 end-1] ;#param between ? and h|l
#lassign $matchinfo _match num type
switch -- $num { switch -- $num {
5 { 5 {
#DECSNM - reverse video #DECSNM - reverse video
@ -2621,10 +2735,73 @@ proc overtype::renderline {args} {
} }
} }
} }
}\
} else {
puts stderr "overtype::renderline CSI...h|l code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented"
}
}
default { default {
puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" puts stderr "overtype::renderline CSI code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented"
}
}
} }
7ESC {
#$re_other_single
switch -- [string index $codenorm end] {
D {
#\x84
#index (IND)
#vt102-docs: "Moves cursor down one line in same column. If cursor is at bottom margin, screen performs a scroll-up"
puts stderr "ESC D not fully implemented"
incr cursor_row
priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction down
#retain cursor_column
break
}
M {
#\x8D
#Reverse Index (RI)
#vt102-docs: "Moves cursor up one line in same column. If cursor is at top margin, screen performs a scroll-down"
puts stderr "ESC M not fully implemented"
set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}[lindex $overlay_grapheme_control_stacks $gci]]
#move up
incr cursor_row -1
if {$cursor_row < 1} {
set cursor_row 1
}
#ensure rest of *overlay* is emitted to remainder
priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction up ;#need instruction for scroll-down?
#retain cursor_column
break
}
E {
#\x85
#review - is behaviour different to lf?
#todo - possibly(?) same logic as <lf> handling above. i.e return instruction depends on where column_cursor is at the time we get NEL
#leave implementation until logic for <lf> is set in stone... still under review
#It's arguable NEL is a pure cursor movement as opposed to the semantic meaning of crlf or lf in a file.
#
#Next Line (NEL) "Move the cursor to the left margin on the next line. If the cursor is at the bottom margin, scroll the page up"
puts stderr "ESC E unimplemented"
}
default {
puts stderr "overtype::renderline ESC<x> code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented"
}
}
}
}
#switch -regexp -matchvar matchinfo -- $code\
#$re_mode {
#}\
#default {
# puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented"
#}
} }
default { default {

Loading…
Cancel
Save