Browse Source

ansi fixes - cursor movement

master
Julian Noble 7 months ago
parent
commit
c29cf8b146
  1. 151
      src/modules/punk/ansi-999999.0a1.0.tm
  2. 2
      src/modules/punk/lib-999999.0a1.0.tm
  3. 5
      src/modules/punk/repl-0.1.tm
  4. 405
      src/vendormodules/overtype-1.5.9.tm

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

@ -95,7 +95,11 @@ namespace eval punk::ansi::class {
} }
if {$o_rendered_what ne $o_raw || $dimensions ne $o_render_dimensions} { if {$o_rendered_what ne $o_raw || $dimensions ne $o_render_dimensions} {
set b [textblock::block $w $h " "] set b [textblock::block $w $h " "]
#some ansi art/layout relies on wrapping at the width-dimension to display properly #some ansi layout/art relies on wrapping at the width-dimension to display properly
#this includes cursor movements ie right arrow can move cursor to columns in lines below
#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 -appendlines 1 $b $o_raw] set o_rendered [overtype::left -overflow 0 -wrap 1 -appendlines 1 $b $o_raw]
#set o_rendered_what $o_raw #set o_rendered_what $o_raw
set o_render_dimensions $dimensions set o_render_dimensions $dimensions
@ -113,6 +117,9 @@ namespace eval punk::ansi::class {
method viewchars {} { method viewchars {} {
return [punk::ansi::stripansiraw $o_raw] return [punk::ansi::stripansiraw $o_raw]
} }
method viewstyle {} {
return [ansistring VIEWSTYLE $o_raw]
}
} }
} }
@ -175,20 +182,46 @@ namespace eval punk::ansi {
#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?
proc readfile {fname} { proc readfile {fname {encoding cp437}} {
#todo #todo
#1- look for BOM - read according to format given by BOM #1- look for BOM - read according to format given by BOM
#2- assume utf-8 #2- assume utf-8
#3- if errors - assume cp437? #3- if errors - assume cp437?
set data [fcat $fname] set ansidata [fcat -encoding $encoding $fname]
if {[file extension $fname] eq ".ans"} { set obj [punk::ansi::class::class_ansi new $ansidata]
set ansidata [encoding convertfrom cp437 $data] return $obj
}
proc ansicat {fname args} {
set encnames [encoding names]
set encoding ""
set dimensions ""
foreach a $args {
if {$a in $encnames} {
set encoding $a
} else { } else {
set ansidata $data if {[regexp {[0-9]+(?:x|X)[0-9]+} $a]} {
set dimensions $a
}
} }
}
if {$encoding eq ""} {
set encoding cp437
}
if {$dimensions eq ""} {
set dimensions 80x26
}
set ansidata [fcat -encoding $encoding $fname]
set obj [punk::ansi::class::class_ansi new $ansidata] set obj [punk::ansi::class::class_ansi new $ansidata]
return $obj $obj render $dimensions
}
#utf-8/ascii encoded cp437
proc ansicat2 {fname {encoding utf-8}} {
set data [fcat -encoding $encoding $fname]
set ansidata [encoding convertfrom cp437 $data]
set obj [punk::ansi::class::class_ansi new $ansidata]
$obj render
} }
proc is_utf8_char {char} { proc is_utf8_char {char} {
regexp {(?x) # Expanded regexp syntax, so I can put in comments :-) regexp {(?x) # Expanded regexp syntax, so I can put in comments :-)
@ -931,8 +964,47 @@ namespace eval punk::ansi {
#[para] DECRC #[para] DECRC
return \x1b8 return \x1b8
} }
# -- --- --- --- --- # -- --- --- --- ---
#DECAWM - automatic line wrapping
proc enable_line_wrap {} {
#*** !doctools
#[call [fun enable_line_wrap]]
#[para] enable automatic line wrapping when characters entered beyond rightmost column
#[para] This will also allow forward movements to move to subsequent lines
#[para] This is DECAWM - and is the same sequence output by 'tput smam'
return \x1b\[?7h
}
proc disable_line_wrap {} {
#*** !doctools
#[call [fun disable_line_wrap]]
#[para] disable automatic line wrapping
#[para] reset DECAWM - same sequence output by 'tput rmam'
#tput rmam
return \x1b\[?7l
}
#DECRQM to query line-wrap state
# \x1b\[?7\$p
#DECRPM responses e.g:
# \x1b\[?7\;1\$y
# \x1b\[?7\;2\$y
#where 1 = set, 2 = unset. (0 = mode not recognised, 3 = permanently set, 4 = permanently unset)
#Alt screen buffer
proc enable_alt_screen {} {
#tput smcup outputs "\x1b\[?1049h\x1b\[22\;0\;0t" second esc sequence - DECSLPP? setting page height one less than main screen?
#\x1b\[?1049h ;#xterm
return \x1b\[?47h
}
proc disable_alt_screen {} {
#tput rmcup outputs \x1b\[?1049l\x1b\[23\;0\;0t]
#\x1b\[?1049l
return \x1b\[?47l
}
# -- --- ---
proc erase_line {} { proc erase_line {} {
#*** !doctools #*** !doctools
#[call [fun erase_line]] #[call [fun erase_line]]
@ -1334,14 +1406,17 @@ namespace eval punk::ansi {
dict set codestate_empty nosupersub "" ;#75 dict set codestate_empty nosupersub "" ;#75
# -- # --
dict set codestate_empty fgbright "" ;#90-97 - keeping separate to fg ie unmerged with it. unsure how it interacts or is used. REVIEW. dict set codestate_empty fg "" ;#30-37 + 90-97
dict set codestate_empty bgbright "" ;#100-107 as above dict set codestate_empty bg "" ;#40-47 + 100-107
dict set codestate_empty fg ""
dict set codestate_empty bg ""
proc sgr_merge {args} { #as a common case optimisation - it will not merge a single element list, even if that code contains redundant elements
proc sgr_merge_list {args} {
if {[llength $args] == 0} {
return ""
} elseif {[llength $args] == 1} {
return [lindex $args 0]
}
variable codestate_empty variable codestate_empty
set othercodes [list] set othercodes [list]
@ -1619,11 +1694,10 @@ namespace eval punk::ansi {
dict set codestate subcript "" dict set codestate subcript ""
} }
90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 { 90 - 91 - 92 - 93 - 94 - 95 - 96 - 97 {
#does this belong with fg? REVIEW dict set codestate fg $p
dict set codestate fgbright $p
} }
100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 { 100 - 101 - 102 - 103 - 104 - 105 - 106 - 107 {
dict set codestate bgbright $p dict set codestate bg $p
} }
} }
@ -1933,7 +2007,7 @@ namespace eval punk::ansi::ansistring {
namespace path [list ::punk::ansi ::punk::ansi::ta] namespace path [list ::punk::ansi ::punk::ansi::ta]
namespace ensemble create namespace ensemble create
namespace export length length1 trim trimleft trimright index VIEW VIEWCODES INDEXABSOLUTE INDEXCOLUMNS COLUMNINDEX namespace export length length1 trim trimleft trimright index VIEW VIEWCODES VIEWSTYLE INDEXABSOLUTE INDEXCOLUMNS COLUMNINDEX
#todo - expose _splits_ methods so caller can work efficiently with the splits themselves #todo - expose _splits_ methods so caller can work efficiently with the splits themselves
#we need to consider whether these can be agnostic towards splits from split_codes vs split_codes_single #we need to consider whether these can be agnostic towards splits from split_codes vs split_codes_single
@ -2353,7 +2427,7 @@ namespace eval punk::ansi::ansistring {
switch -regexp -matchvar matchinfo -- $code\ switch -regexp -matchvar matchinfo -- $code\
$re_row_move { $re_row_move {
set displaycode [ansistring VIEW $code] set displaycode [ansistring VIEW $code]
set displaycode [string map [list A "C$arrow_up" B "D$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 { $re_col_move {
@ -2391,6 +2465,45 @@ namespace eval punk::ansi::ansistring {
} }
return $output return $output
} }
#an attempt to show the codes and colour/style of the *input*
#ie we aren't looking at the row/column positioning - but we do want to keep track of cursor attribute saves and restores
proc VIEWSTYLE {string} {
set splits [punk::ansi::ta::split_codes_single $string]
set output ""
set codestack [list]
set gx_stack [list] ;#not actually a stack
set cursor_saved ""
foreach {pt code} $splits {
append output [punk::ansi::codetype::sgr_merge_list {*}$codestack]$pt
if {$code ne ""} {
append output [a][VIEW $code]
if {[punk::ansi::codetype::is_sgr_reset $code]} {
set codestack [list]
} elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} {
set codestack [list $code]
} elseif {[punk::ansi::codetype::is_sgr $code]} {
#basic simplification first.. straight dups
set dup_posns [lsearch -all -exact $codestack $code] ;#-exact because of square-bracket glob chars
set codestack [lremove $codestack {*}$dup_posns]
lappend codestack $code
} elseif {[regexp {\x1b7|\x1b\[s} $code]} {
#cursor_save
set cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$codestack]
} elseif {[regexp {\x1b8|\x1b\[u} $code]} {
#cursor_restore
set codestack [list $cursor_saved]
} else {
#leave SGR stack as is
if {[punk::ansi::codetype::is_gx_open $code]} {
set 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]} {
set gx_stack [list]
}
}
}
}
return $output
}
proc length {string} { proc length {string} {
#*** !doctools #*** !doctools

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

@ -937,7 +937,7 @@ namespace eval punk::lib {
} }
#set newreplay [join $codestack ""] #set newreplay [join $codestack ""]
set newreplay [punk::ansi::codetype::sgr_merge {*}$codestack] set newreplay [punk::ansi::codetype::sgr_merge_list {*}$codestack]
if {$line_has_sgr && $newreplay ne $replaycodes} { if {$line_has_sgr && $newreplay ne $replaycodes} {
#adjust if it doesn't already does a reset at start #adjust if it doesn't already does a reset at start

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

@ -213,6 +213,7 @@ if {$::tcl_platform(platform) eq "windows"} {
#expermental terminal alt screens #expermental terminal alt screens
#alternatives are \x1b\[?47h ans \x1b[?\47l
proc ::repl::term::screen_push_alt {} { proc ::repl::term::screen_push_alt {} {
#tput smcup #tput smcup
puts -nonewline stderr "\033\[?1049h" puts -nonewline stderr "\033\[?1049h"
@ -1139,7 +1140,7 @@ 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_change] set cmove [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 insert_lines_below [dict get $mergedinfo insert_lines_below] set insert_lines_below [dict get $mergedinfo insert_lines_below]
@ -1220,7 +1221,7 @@ 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 o_cursor_col [dict get $mergedinfo cursor_column] set o_cursor_col [dict get $mergedinfo cursor_column]
set cmove [dict get $mergedinfo cursor_row_change] set cmove [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 insert_lines_below [dict get $mergedinfo insert_lines_below] set insert_lines_below [dict get $mergedinfo insert_lines_below]

405
src/vendormodules/overtype-1.5.9.tm

@ -219,6 +219,7 @@ proc overtype::left {args} {
lassign [lrange $args end-1 end] underblock overblock lassign [lrange $args end-1 end] underblock overblock
set defaults [dict create\ set defaults [dict create\
-bias ignored\ -bias ignored\
-width \uFFEF\
-wrap 0\ -wrap 0\
-ellipsis 0\ -ellipsis 0\
-ellipsistext $default_ellipsis_horizontal\ -ellipsistext $default_ellipsis_horizontal\
@ -233,7 +234,7 @@ proc overtype::left {args} {
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 {
-bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 {} -width - -bias - -wrap - -ellipsis - -ellipsistext - -ellipsiswhitespace - -overflow - -appendlines - -transparent - -exposed1 - -exposed2 {}
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"
@ -243,8 +244,12 @@ proc overtype::left {args} {
set opts [dict merge $defaults $argsflags] set opts [dict merge $defaults $argsflags]
# -- --- --- --- --- --- # -- --- --- --- --- ---
set opt_overflow [dict get $opts -overflow] set opt_overflow [dict get $opts -overflow]
#####
# review -wrap should map onto DECAWM terminal mode - the wrap 2 idea may not fit in with this?.
set opt_wrap [dict get $opts -wrap] ;#wrap 1 is hard wrap cutting word at exact column, or 1 column early for 2w-glyph, wrap 2 is for language-based word-wrap algorithm (todo) set opt_wrap [dict get $opts -wrap] ;#wrap 1 is hard wrap cutting word at exact column, or 1 column early for 2w-glyph, wrap 2 is for language-based word-wrap algorithm (todo)
#####
#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_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]
@ -253,25 +258,31 @@ proc overtype::left {args} {
set opt_exposed2 [dict get $opts -exposed2] ;#widechar_exposed_right - todo set opt_exposed2 [dict get $opts -exposed2] ;#widechar_exposed_right - todo
# -- --- --- --- --- --- # -- --- --- --- --- ---
#modes
set insert_mode 0 ;#can be toggled by insert key or ansi IRM sequence ESC [ 4 h|l
set autowrap_mode $opt_wrap
set reverse_mode 0
set norm [list \r\n \n] set norm [list \r\n \n]
set underblock [string map $norm $underblock] set underblock [string map $norm $underblock]
set overblock [string map $norm $overblock] set overblock [string map $norm $overblock]
#set underlines [split $underblock \n] #set underlines [split $underblock \n]
set underlines [lines_as_list -ansiresets 1 $underblock]
#set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {punk::ansi::printing_length $v}]] #underblock is a 'rendered' block - so width height make sense
if {$opt_width eq "\uFFEF"} {
lassign [blocksize $underblock] _w colwidth _h colheight lassign [blocksize $underblock] _w colwidth _h colheight
} else {
set colwidth $opt_width
}
set underlines [lines_as_list -ansiresets 1 $underblock]
set overlines [split $overblock \n] set overlines [split $overblock \n]
#set overblock_width [tcl::mathfunc::max {*}[lmap v $overlines {punk::ansi::printing_length $v}]] #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
set under_exposed_max [expr {$colwidth - $overblock_width}]
set right_exposed $under_exposed_max
#if {[punk::ansi::ta::detect_sgr [lindex $underlines 0]]} {
# set replay_codes "[punk::ansi::a]"
#} else {
# set replay_codes ""
#}
set replay_codes_underlay [dict create 1 ""] set replay_codes_underlay [dict create 1 ""]
lappend replay_codes_overlay "" lappend replay_codes_overlay ""
set unapplied "" set unapplied ""
@ -290,28 +301,7 @@ proc overtype::left {args} {
set undertext [lindex $outputlines [expr {$row -1}]] set undertext [lindex $outputlines [expr {$row -1}]]
set renderedrow $row set renderedrow $row
set pad 0 #renderline pads each underaly line to width with spaces and should track where end of data is
if {$pad} {
set undertext_printlen [punk::ansi::printing_length $undertext]
if {$undertext_printlen < $colwidth} {
set udiff [expr {$colwidth - $undertext_printlen}]
append undertext [string repeat { } $udiff]
}
}
#padding of new empties needed for auto line adding to work - testing with ansi-art
if {$undertext eq ""} {
set undertext [string repeat " " $colwidth]
} else {
set undertext_printlen [punk::ansi::printing_length $undertext]
if {$undertext_printlen < $colwidth} {
set udiff [expr {$colwidth - $undertext_printlen}]
append undertext [string repeat { } $udiff]
}
}
#examining printing length of a potentially ansi-movement-laden line in isolation makes no sense
#set overtext_printlen [punk::ansi::printing_length $overtext]
#set overflowlength [expr {$overtext_printlen - $colwidth}]
set overtext [string cat [lindex $replay_codes_overlay $overidx] $overtext] set overtext [string cat [lindex $replay_codes_overlay $overidx] $overtext]
@ -320,14 +310,18 @@ proc overtype::left {args} {
lappend underlay_resets [list $row [dict get $replay_codes_underlay $row]] lappend underlay_resets [list $row [dict get $replay_codes_underlay $row]]
} }
#review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary - #review insert_mode. As an 'overtype' function whose main function is not interactive keystrokes - insert is secondary -
#but even if we didn't want it as an option to the function call - to process ansi fully it may need to be supported (how widely supported are ansi insert-mode toggles?) #but even if we didn't want it as an option to the function call - to process ansi adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l
set rinfo [renderline -info 1 -insert_mode 0 -transparent $opt_transparent -width $colwidth -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext] set rinfo [renderline -info 1 -insert_mode $insert_mode -autowrap_mode $autowrap_mode -transparent $opt_transparent -width $colwidth -exposed1 $opt_exposed1 -exposed2 $opt_exposed2 -overflow $opt_overflow -cursor_column $col -cursor_row $row $undertext $overtext]
set instruction [dict get $rinfo instruction] set instruction [dict get $rinfo instruction]
set insert_mode [dict get $rinfo insert_mode]
set autowrap_mode [dict get $rinfo autowrap_mode] ;#
#set reverse_mode [dict get $rinfo reverse_mode];#how to support in rendered linelist? we need to examine all pt/code blocks and flip each SGR stack?
set rendered [dict get $rinfo result] set rendered [dict get $rinfo result]
set overflow_right [dict get $rinfo overflow_right] set overflow_right [dict get $rinfo overflow_right]
set overflow_right_column [dict get $rinfo overflow_right_column]
set unapplied [dict get $rinfo unapplied] set unapplied [dict get $rinfo unapplied]
set render_col [dict get $rinfo cursor_column] set post_render_col [dict get $rinfo cursor_column]
set render_row [dict get $rinfo cursor_row_change] set post_render_row [dict get $rinfo cursor_row]
set c_saved_pos [dict get $rinfo cursor_saved_position] set c_saved_pos [dict get $rinfo cursor_saved_position]
set c_saved_attributes [dict get $rinfo cursor_saved_attributes] set c_saved_attributes [dict get $rinfo cursor_saved_attributes]
set visualwidth [dict get $rinfo visualwidth] set visualwidth [dict get $rinfo visualwidth]
@ -336,6 +330,13 @@ proc overtype::left {args} {
dict set replay_codes_underlay [expr {$renderedrow+1}] [dict get $rinfo replay_codes_underlay] dict set replay_codes_underlay [expr {$renderedrow+1}] [dict get $rinfo replay_codes_underlay]
lset replay_codes_overlay [expr $overidx+1] [dict get $rinfo replay_codes_overlay] lset replay_codes_overlay [expr $overidx+1] [dict get $rinfo replay_codes_overlay]
#-- todo - detect looping properly
if {$row > 1 && $overtext ne "" && $unapplied eq $overtext && $post_render_row == $row} {
puts stderr "overtype::left loop?"
break
}
#--
if {[dict size $c_saved_pos] >= 1} { if {[dict size $c_saved_pos] >= 1} {
set cursor_saved_position $c_saved_pos set cursor_saved_position $c_saved_pos
set cursor_saved_attributes $c_saved_attributes set cursor_saved_attributes $c_saved_attributes
@ -345,15 +346,9 @@ proc overtype::left {args} {
#background line is narrower than data in line #background line is narrower than data in line
set overflow_handled 0 set overflow_handled 0
if {!$opt_overflow} { if {!$opt_overflow && !$autowrap_mode} {
#not allowed to overflow column therefore we get overflow data to either truncate or wrap #not allowed to overflow column or wrap therefore we get overflow data to truncate
if {$opt_wrap} { if {[dict get $opts -ellipsis]} {
#wrap by returning unapplied and overflow_right
if {$instruction eq ""} {
set instruction wrap
}
} elseif {[dict get $opts -ellipsis]} {
set show_ellipsis 1 set show_ellipsis 1
if {!$opt_ellipsiswhitespace} { if {!$opt_ellipsiswhitespace} {
#we don't want ellipsis if only whitespace was lost #we don't want ellipsis if only whitespace was lost
@ -388,7 +383,8 @@ proc overtype::left {args} {
if {$opt_appendlines} { if {$opt_appendlines} {
lappend outputlines $rendered lappend outputlines $rendered
} else { } else {
#lset outputlines [expr {$renderedrow-1}] $rendered #?
lset outputlines [expr {$renderedrow-1}] $rendered
} }
} }
@ -410,7 +406,7 @@ proc overtype::left {args} {
#should move to home position and reset ansi SGR? #should move to home position and reset ansi SGR?
#puts stderr "overtype::left cursor_restore without save data available" #puts stderr "overtype::left cursor_restore without save data available"
} }
#If we were inserting prior to hitting the cursor_restore - there could be overflow_right data - generally the overtype functions aren't for inserting - but ansi could enable it #If we were inserting prior to hitting the cursor_restore - there could be overflow_right data - generally the overtype functions aren't for inserting - but ansi can enable it
#if we were already in overflow when cursor_restore was hit - it shouldn't have been processed as an action - just stored. #if we were already in overflow when cursor_restore was hit - it shouldn't have been processed as an action - just stored.
if {!$overflow_handled && $overflow_right ne ""} { if {!$overflow_handled && $overflow_right ne ""} {
#wrap before restore? - possible effect on saved cursor position #wrap before restore? - possible effect on saved cursor position
@ -441,26 +437,41 @@ proc overtype::left {args} {
} }
up { up {
#renderline already knows not to go above l #renderline already knows not to go above l
set row $render_row #Note that an ansi up sequence after last column going up to a previous line and also beyond the last column, will result in the next grapheme going onto the following line.
set col $render_col #this seems correct - as the column remains beyond the right margin so subsequent chars wrap (?) review
#puts stderr "up $post_render_row"
#puts stderr "$rinfo"
set row $post_render_row
set rowdata [lindex $outputlines [expr {$row -1}]]
set len [punk::ansi::printing_length $rowdata]
if {$len+1 < $post_render_col} {
set col [expr {$len+1}]
} else {
set col $post_render_col
}
} }
down { down {
#renderline doesn't know how far down we can go.. #renderline doesn't know how far down we can go..
if {$render_row > [llength $outputlines]} { if {$post_render_row > [llength $outputlines]} {
#if {$opt_appendlines} {
# set diff [expr {$post_render_row - [llength $outputlines]}]
# if {$diff > 0} {
# lappend outputlines {*}[lrepeat $diff ""]
# }
#}
set row [llength $outputlines] set row [llength $outputlines]
} else { } else {
set row $render_row set row $post_render_row
} }
set col $post_render_col
set col $render_col
} }
move { move {
if {$render_row > [llength $outputlines]} { if {$post_render_row > [llength $outputlines]} {
set row [llength $outputlines] set row [llength $outputlines]
} else { } else {
set row $render_row set row $post_render_row
} }
set col $render_col set col $post_render_col
#overflow + unapplied? #overflow + unapplied?
} }
newline_above - newline_below { newline_above - newline_below {
@ -468,13 +479,62 @@ proc overtype::left {args} {
} }
wrap { wrap {
#hard wraps in this context. #hard wraps in this context.
#note that cursor_forward may move deep into the next line - or even span multiple lines !TODO
if {$overflow_right_column eq ""} {
#so why are we getting a wrap instruction?
puts stderr "overtype::left wrap instruction when no overflow_right_column\n$rinfo"
incr row incr row
set col 1 set col 1
} else {
if {$post_render_col >= $overflow_right_column} {
#review - check printing_length of each following underlay line and move appropriately?
#puts "post_render_col: $post_render_col"
#puts "overflow_right_column: $overflow_right_column"
set c $overflow_right_column
set i $c
while {$i <= $post_render_col} {
if {($i-1) % $colwidth == 0} {
incr row
set c 1
} else {
incr c
}
incr i
}
set col $c
#incr row
#set col [expr {1+ ($post_render_col - $overflow_right_column)}]
} else {
incr row
set col 1
}
}
}
overflow {
#normal single-width grapheme overflow
incr row
set col 1 ;#whether wrap or not - next data is at column 1
if {!$autowrap_mode} {
set overflow_handled 1
set unapplied ""
#handled by dropping it..
}
}
overflow_splitchar {
#2nd half of grapheme would overflow - grapheme returned in unapplied. There may also be overflow_right from earlier inserts
#todo - consider various options .. re-render a single trailing space or placeholder on same output line, etc
incr row
if {$autowrap_mode} {
set col 1
} else {
set overflow_handled 1
#handled by dropping it..
}
} }
vt { vt {
#can vt add a line like a linefeed can? #can vt add a line like a linefeed can?
set row $render_row set row $post_render_row
set col $render_col set col $post_render_col
} }
default { default {
puts stderr "overtype::left unhandled renderline instruction '$instruction'" puts stderr "overtype::left unhandled renderline instruction '$instruction'"
@ -505,7 +565,7 @@ proc overtype::left {args} {
#dict set replay_codes_underlay [expr {$renderedrow+1}] [dict get $rinfo replay_codes_underlay] #dict set replay_codes_underlay [expr {$renderedrow+1}] [dict get $rinfo replay_codes_underlay]
#lset replay_codes_overlay [expr $overidx+1] [dict get $rinfo replay_codes_overlay] #lset replay_codes_overlay [expr $overidx+1] [dict get $rinfo replay_codes_overlay]
set prevrow $row set prevrow $renderedrow
} }
#puts stdout $underlay_resets #puts stdout $underlay_resets
return [join $outputlines \n] return [join $outputlines \n]
@ -873,6 +933,8 @@ proc overtype::renderline {args} {
-cursor_column 1\ -cursor_column 1\
-cursor_row ""\ -cursor_row ""\
-insert_mode 1\ -insert_mode 1\
-autowrap_mode 1\
-reverse_mode 0\
-info 0\ -info 0\
-exposed1 \uFFFD\ -exposed1 \uFFFD\
-exposed2 \uFFFD\ -exposed2 \uFFFD\
@ -886,7 +948,7 @@ proc overtype::renderline {args} {
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 {
-width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row - -insert_mode - -info - -exposed1 - -exposed2 {} -width - -overflow - -transparent - -startcolumn - -cursor_column - -cursor_row - -insert_mode - -autowrap_mode - -reverse_mode - -info - -exposed1 - -exposed2 {}
default { default {
set known_opts [dict keys $defaults] set known_opts [dict keys $defaults]
error "overtype::renderline unknown option '$k'. Known options: $known_opts" error "overtype::renderline unknown option '$k'. Known options: $known_opts"
@ -906,9 +968,17 @@ proc overtype::renderline {args} {
error "overtype::renderline -cursor_row must be empty for unspecified/unknown or a non-zero positive integer. received: '$opt_row_context'" error "overtype::renderline -cursor_row must be empty for unspecified/unknown or a non-zero positive integer. received: '$opt_row_context'"
} }
} }
# -- --- --- --- --- --- --- --- --- --- --- ---
#The _mode flags correspond to terminal modes that can be set/reset via escape sequences (e.g DECAWM wraparound mode)
set opt_insert_mode [dict get $opts -insert_mode];#should usually be 1 for each new line in editor mode but must be initialised to 1 externally (review) set opt_insert_mode [dict get $opts -insert_mode];#should usually be 1 for each new line in editor mode but must be initialised to 1 externally (review)
#default is for overtype #default is for overtype
# -- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- ---
set opt_autowrap_mode [dict get $opts -autowrap_mode] ;#DECAWM - char or movement can go beyond leftmost/rightmost col to prev/next line
set opt_reverse_mode [dict get $opts -reverse_mode] ;#DECSNM
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_transparent [dict get $opts -transparent] set opt_transparent [dict get $opts -transparent]
if {$opt_transparent eq "0"} { if {$opt_transparent eq "0"} {
set do_transparency 0 set do_transparency 0
@ -925,11 +995,6 @@ proc overtype::renderline {args} {
set opt_exposed2 [dict get $opts -exposed2] set opt_exposed2 [dict get $opts -exposed2]
# -- --- --- --- --- --- --- --- --- --- --- --- # -- --- --- --- --- --- --- --- --- --- --- ---
#if {$opt_row_context eq ""} {
# set cursor_row 0 ;#we aren't allowed to make assumptions about our context. zero represents cursor_row_change - not an absolute row (for which zero is invalid anyway)
#} else {
# set cursor_row "=$opt_row_context" ;#we are at this row number in the greater context - allow moves that explicitly refer to this row without returning prematurely
#}
if {$opt_row_context eq ""} { if {$opt_row_context eq ""} {
set cursor_row 1 set cursor_row 1
} else { } else {
@ -1040,15 +1105,33 @@ proc overtype::renderline {args} {
#consider also if there are other codes that should be stacked..? #consider also if there are other codes that should be stacked..?
} }
#fill columns to width with spaces, and carry over stacks - we will have to keep track of where the underlying data ends manually - TODO
if {$opt_width ne "\uFFef"} {
if {[llength $understacks]} {
set cs $u_codestack
set gs $u_gx_stack
} else {
set cs [list]
set gs [list]
}
if {[llength $undercols]< $opt_width} {
set diff [expr {$opt_width- [llength $undercols]}]
if {$diff > 0} {
lappend undercols {*}[lrepeat $diff " "]
lappend understacks {*}[lrepeat $diff $cs]
lappend understacks_gx {*}[lrepeat $diff $gs]
}
}
}
#trailing codes in effect for underlay #trailing codes in effect for underlay
#replay code for last overlay position in input line #replay code for last overlay position in input line
# whether or not we get that far - we need to return it for possible replay on next line # whether or not we get that far - we need to return it for possible replay on next line
if {[llength $undermap]} { if {[llength $understacks]} {
#dict set understacks [expr {$i_u + 1}] $u_codestack ;#This is one column higher than our input #dict set understacks [expr {$i_u + 1}] $u_codestack ;#This is one column higher than our input
lappend understacks $u_codestack lappend understacks $u_codestack
#set replay_codes_underlay [join $u_codestack ""] #set replay_codes_underlay [join $u_codestack ""]
set replay_codes_underlay [punk::ansi::codetype::sgr_merge {*}$u_codestack] set replay_codes_underlay [punk::ansi::codetype::sgr_merge_list {*}$u_codestack]
# For gx we need the column after the data too ? # For gx we need the column after the data too ?
#dict set understacks_gx [expr {$i_u +1}] $u_gx_stack #dict set understacks_gx [expr {$i_u +1}] $u_gx_stack
@ -1136,7 +1219,7 @@ proc overtype::renderline {args} {
lappend overstacks_gx $o_gxstack lappend overstacks_gx $o_gxstack
#set replay_codes_overlay [join $o_codestack ""] #set replay_codes_overlay [join $o_codestack ""]
set replay_codes_overlay [punk::ansi::codetype::sgr_merge {*}$o_codestack] set replay_codes_overlay [punk::ansi::codetype::sgr_merge_list {*}$o_codestack]
#if {[dict exists $overstacks $max_overlay_grapheme_index]} { #if {[dict exists $overstacks $max_overlay_grapheme_index]} {
# set replay_codes_overlay [join [dict get $overstacks $max_overlay_grapheme_index] ""] # set replay_codes_overlay [join [dict get $overstacks $max_overlay_grapheme_index] ""]
@ -1156,7 +1239,7 @@ proc overtype::renderline {args} {
} else { } else {
#overflow zero - we can't grow beyond our column width - so we get ellipsis or truncation #overflow zero - we can't grow beyond our column width - so we get ellipsis or truncation
if {$opt_width ne "\uFFEF"} { if {$opt_width ne "\uFFEF"} {
set overflow_idx $opt_width set overflow_idx [expr {$opt_width}]
} else { } else {
#review - this is also the cursor position when adding a char at end of line? #review - this is also the cursor position when adding a char at end of line?
set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it
@ -1183,7 +1266,10 @@ proc overtype::renderline {args} {
#idx is the per column output index #idx is the per column output index
set idx [expr {$opt_colcursor -1}] ;#don't use opt_colstart here - we have padded and won't start emitting until idx reaches opt_colstart-1 set idx [expr {$opt_colcursor -1}] ;#don't use opt_colstart here - we have padded and won't start emitting until idx reaches opt_colstart-1
#cursor_column is usually one above idx - but we have opt_colstart which is like a margin - todo: remove cursor_column from the following loop and calculate it's offset when breaking or at end.
#(for now we are incrementing/decrementing both in sync - which is a bit silly)
set cursor_column $opt_colcursor set cursor_column $opt_colcursor
#idx_over is the per grapheme overlay index #idx_over is the per grapheme overlay index
set idx_over -1 set idx_over -1
@ -1193,7 +1279,9 @@ proc overtype::renderline {args} {
#renderline -overflow 1 "" data #renderline -overflow 1 "" data
#foreach {pt code} $overmap {} #foreach {pt code} $overmap {}
set insert_mode $opt_insert_mode ;#default 1 set insert_mode $opt_insert_mode ;#default 1
set in_overflow 0 set autowrap_mode $opt_autowrap_mode ;#default 1
#puts "-->$overlay_grapheme_control_list<--" #puts "-->$overlay_grapheme_control_list<--"
#puts "-->overflow_idx: $overflow_idx" #puts "-->overflow_idx: $overflow_idx"
for {set gci 0} {$gci < [llength $overlay_grapheme_control_list]} {incr gci} { for {set gci 0} {$gci < [llength $overlay_grapheme_control_list]} {incr gci} {
@ -1210,12 +1298,6 @@ proc overtype::renderline {args} {
set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our original data width set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our original data width
if {$in_overflow} {
#render any char - even \b\v\r into outcols - will become part of overflow
#no stacks added from here on - raw codes go into overflow/remainder
priv::render_addchar $idx $ch [list] [list] $insert_mode
incr idx ;#width doesn't matter from here on - idx once in overflow no longer represents columns
} else {
if {$overflow_idx != -1} { if {$overflow_idx != -1} {
#review - how to check arbitrary length item such as tab is going to overflow .. before we get to overflow_idx? #review - how to check arbitrary length item such as tab is going to overflow .. before we get to overflow_idx?
@ -1225,32 +1307,20 @@ proc overtype::renderline {args} {
set owidth [grapheme_width_cached $ch] set owidth [grapheme_width_cached $ch]
if {$owidth == 2} { if {$owidth == 2} {
#review split 2w overflow? #review split 2w overflow?
#we don't want to split a 2w into replacement characters at end of line and beginning of next line #we don't want to make the decision here to split a 2w into replacement characters at end of line and beginning of next line
#better to consider the overlay char as unable to be applied to the line #better to consider the overlay char as unable to be applied to the line
#render empty string to column - and reduce overlay grapheme index by one so that the current ch goes into unapplied #render empty string to column(?) - and reduce overlay grapheme index by one so that the current ch goes into unapplied
#we have the option here to put the 2w in the normal overflow and continue, instead of adding to unapplied and throwing back to caller #throwing back to caller with instruction complicates its job - but is necessary to avoid making decsions for it here.
#throwing back to caller with instruction complicates its job - but might be necessary to avoid making decsions for it here.
#REVIEW - decide one way or another, update callers as necessary and chop unused branch.
set continue 1
if $continue {
priv::render_addchar $idx "" [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode
set overflow_idx $idx
#incr idx
set in_overflow 1
incr gci -1
#priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode
continue
} else {
priv::render_addchar $idx "" [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode priv::render_addchar $idx "" [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode
#change the overflow_idx #change the overflow_idx
set overflow_idx $idx set overflow_idx $idx
incr idx incr idx
incr idx_over -1 ;#set overlay grapheme index back one so that current ch is considered unapplied incr idx_over -1 ;#set overlay grapheme index back one so that sgr stack from previous overlay grapheme used
priv::render_unapplied $overlay_grapheme_control_list [expr {$gci-1}] ;#note $gci-1 instead of just gci priv::render_unapplied $overlay_grapheme_control_list [expr {$gci-1}] ;#note $gci-1 instead of just gci
#throw back to caller's loop - add instruction to caller as this is not the usual case #throw back to caller's loop - add instruction to caller as this is not the usual case
#caller may for example choose to render a single replacement char to this line and omit the grapheme, or wrap it to the next line
set instruction overflow_splitchar set instruction overflow_splitchar
break break
}
} elseif {$owidth > 2} { } elseif {$owidth > 2} {
#? tab? #? tab?
#TODO! #TODO!
@ -1258,11 +1328,12 @@ proc overtype::renderline {args} {
#tab of some length dependent on tabstops/elastic tabstop settings? #tab of some length dependent on tabstops/elastic tabstop settings?
} }
} elseif {$idx == $overflow_idx} { } elseif {$idx == $overflow_idx} {
#don't incr cursor_column beyond the overflow_idx #don't incr idx beyond the overflow_idx
set in_overflow 1 #idx_over already incremented - decrement so current overlay grapheme stacks go to unapplied
priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode incr idx_over -1
incr idx priv::render_unapplied $overlay_grapheme_control_list [expr {$gci-1}] ;#back one index here too
continue set instruction overflow
break
} }
} }
@ -1354,7 +1425,7 @@ proc overtype::renderline {args} {
} }
"<cr>" { "<cr>" {
set idx [expr {$opt_colstart -1}] set idx [expr {$opt_colstart -1}]
set cursor_column 1 ;#? set cursor_column $opt_colstart ;#?
} }
"<bs>" { "<bs>" {
#literal backspace char - not necessarily from keyboard #literal backspace char - not necessarily from keyboard
@ -1486,17 +1557,11 @@ proc overtype::renderline {args} {
} ;# end switch } ;# end switch
} }
} }
}
other { other {
set code $item set code $item
if {$in_overflow} {
#render controls into overflow/remainder output
priv::render_addchar $idx $code [list] [list] $insert_mode
incr idx ;#take up a column for each control sequence too
continue
}
#since this element isn't a grapheme - advance idx_over to next grapheme overlay when about to fill 'unapplied' #since this element isn't a grapheme - advance idx_over to next grapheme overlay when about to fill 'unapplied'
set re_mode {\x1b\[\?([0-9]*)(h|l)} ;#e.g DECAWM
set re_col_move {\x1b\[([0-9]*)(C|D|G)$} set re_col_move {\x1b\[([0-9]*)(C|D|G)$}
set re_row_move {\x1b\[([0-9]*)(A|B)$} set re_row_move {\x1b\[([0-9]*)(A|B)$}
set re_both_move {\x1b\[([0-9]*)(?:;){0,1}([0-9]*)H$} ;# or "f" ? set re_both_move {\x1b\[([0-9]*)(?:;){0,1}([0-9]*)H$} ;# or "f" ?
@ -1512,7 +1577,8 @@ proc overtype::renderline {args} {
lassign $matchinfo _match num type lassign $matchinfo _match num type
switch -- $type { switch -- $type {
D { D {
#left-arrow/move-back #cursor back
#left-arrow/move-back when ltr mode
if {$num eq ""} {set num 1} if {$num eq ""} {set num 1}
incr idx -$num incr idx -$num
incr cursor_column -$num incr cursor_column -$num
@ -1523,24 +1589,42 @@ proc overtype::renderline {args} {
} }
} }
C { C {
#todo - consider right-to-left cursor mode (e.g Hebrew).. some day.
#cursor forward
#right-arrow/move forward #right-arrow/move forward
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?
#should ideally wrap to next line when interactive and not on last row #should ideally wrap to next line when interactive and not on last row
#(some ansi art seems to expect this behaviour)
#This presumably depends on the terminal's wrap mode
#e.g DECAWM autowrap mode
# CSI ? 7 h - set: autowrap (also tput smam)
# CSI ? 7 l - reset: no autowrap (also tput rmam)
set version 2 set version 2
if {$version eq "2"} { if {$version eq "2"} {
set max [llength $outcols] set max [llength $outcols]
if {!$opt_overflow} { if {$opt_overflow} {
} else {
incr max incr max
} }
if {($cursor_column + $num) > $max} { if {($cursor_column + $num) <= $max} {
set cursor_column $max
set idx [expr {$cursor_column -1}]
} else {
incr idx $num incr idx $num
incr cursor_column $num incr cursor_column $num
} else {
if {$opt_autowrap_mode} {
#horizontal movement beyond line extent needs to wrap - throw back to caller
#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)
#leave row as is - caller will need to determine how many rows the column-movement has consumed
incr cursor_column $num ;#give our caller the necessary info
incr idx_over
priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction wrap
break
} else {
set cursor_column $max
set idx [expr {$cursor_column -1}]
}
} }
} else { } else {
if {!$opt_overflow || ($cursor_column + $num) <= [llength $outcols+1]} { if {!$opt_overflow || ($cursor_column + $num) <= [llength $outcols+1]} {
@ -1773,7 +1857,7 @@ proc overtype::renderline {args} {
} }
} }
#append cursor_saved_attributes [join $sgr_stack ""] #append cursor_saved_attributes [join $sgr_stack ""]
append cursor_saved_attributes [punk::ansi::codetype::sgr_merge {*}$sgr_stack] append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack]
if 0 { if 0 {
@ -1829,41 +1913,56 @@ proc overtype::renderline {args} {
set instruction move set instruction move
set cursor_restore_required 1 set cursor_restore_required 1
break break
}\
$re_mode {
switch -- $num {
5 {
#DECSNM - reverse video
#How we simulate this to render within a block of text is an open question.
#track all SGR stacks and constantly flip based on the current SGR reverse state?
#It is the job of the calling loop to do this - so at this stage we'll just set the states
#DECAWM autowrap
if {$type eq "h"} {
#set (enable)
set reverse_mode 1
} else {
#reset (disable)
set reverse_mode 0
}
}
7 {
#DECAWM autowrap
if {$type eq "h"} {
#set (enable)
set autowrap_mode 1
if {$opt_width ne "\uFFEF"} {
set overflow_idx $opt_width
} else {
#review - this is also the cursor position when adding a char at end of line?
set overflow_idx [expr {[llength $undercols]}] ;#index at which we would be *in* overflow a row move may still override it
} }
#review - can idx ever be beyond overflow_idx limit when we change e.g with a width setting and cursor movements? presume not - but sanity check for now.
if {$idx >= $overflow_idx} {
puts stderr "renderline error - idx '$idx' >= overflow_idx '$overflow_idx' - unexpected"
} }
sgr { } else {
#prior to overflow - we have our sgr codes already in stacks #reset (disable)
#post-overflow we need to keep them in order along with non sgr codes and graphemes set autowrap_mode 0
if {$in_overflow} { set overflow_idx -1
set code $item
#render controls into output - will become overflow/remainder
priv::render_addchar $idx $code [list] [list] $insert_mode
incr idx ;#take up an overflow column for each control sequence too
} }
} }
gx0 {
if {$in_overflow} {
set code $item
if {$code eq "gx0_on"} {
set actual "\x1b(0"
} else {
set actual "\x1b(B"
} }
priv::render_addchar $idx $actual [list] [list] $insert_mode
incr idx
} }
}
default {
#don't need to handle sgr or gx0 types
#we have our sgr gx0 codes already in stacks for each overlay grapheme
} }
} }
} }
#-------------- #--------------
#if {$in_overflow} {
# #set cursor_column [expr {$overflow_idx -1}]
# set cursor_column [expr {$overflow_idx +1}]
#} else {
# set cursor_column [expr {$idx + 1}]
#}
if {$opt_overflow == 0} { if {$opt_overflow == 0} {
@ -1887,6 +1986,10 @@ proc overtype::renderline {args} {
set prev_g0 [list] set prev_g0 [list]
#note overflow_idx may already have been set lower if we had a row move above due to \v or ANSI moves #note overflow_idx may already have been set lower if we had a row move above due to \v or ANSI moves
set in_overflow 0 ;#used to stop char-width scanning once in overflow set in_overflow 0 ;#used to stop char-width scanning once in overflow
if {$overflow_idx == 0} {
#how does caller avoid an infinite loop if they have autowrap on and keep throwing graphemes to the next line? REVIEW
set in_overflow 1
}
foreach ch $outcols { foreach ch $outcols {
#puts "---- [ansistring VIEW $ch]" #puts "---- [ansistring VIEW $ch]"
@ -1905,7 +2008,7 @@ proc overtype::renderline {args} {
if {$i < [llength $understacks]} { if {$i < [llength $understacks]} {
set cstack [lindex $understacks $i] set cstack [lindex $understacks $i]
#append overflow_right [join $cstack ""] #append overflow_right [join $cstack ""]
append overflow_right [punk::ansi::codetype::sgr_merge {*}$cstack] append overflow_right [punk::ansi::codetype::sgr_merge_list {*}$cstack]
} }
} }
append overflow_right $ch append overflow_right $ch
@ -1944,7 +2047,7 @@ proc overtype::renderline {args} {
append outstring \033\[m append outstring \033\[m
} }
#append outstring [join $cstack ""] #append outstring [join $cstack ""]
append outstring [punk::ansi::codetype::sgr_merge {*}$cstack] append outstring [punk::ansi::codetype::sgr_merge_list {*}$cstack]
} }
set prevstack $cstack set prevstack $cstack
} else { } else {
@ -1965,7 +2068,7 @@ proc overtype::renderline {args} {
} }
if {$tail_idx-1 < [llength $understacks]} { if {$tail_idx-1 < [llength $understacks]} {
#set replay_codes [join [lindex $understacks $tail_idx-1] ""] ;#tail replay codes #set replay_codes [join [lindex $understacks $tail_idx-1] ""] ;#tail replay codes
set replay_codes [punk::ansi::codetype::sgr_merge [lindex $understacks $tail_idx-1]] ;#tail replay codes set replay_codes [punk::ansi::codetype::sgr_merge_list {*}[lindex $understacks $tail_idx-1]] ;#tail replay codes
} }
if {$tail_idx-1 < [llength $understacks_gx]} { if {$tail_idx-1 < [llength $understacks_gx]} {
set gx0 [lindex $understacks_gx $tail_idx-1] set gx0 [lindex $understacks_gx $tail_idx-1]
@ -1987,22 +2090,30 @@ proc overtype::renderline {args} {
#replay_codes_underlay is the set of codes in effect at the very end of the original underlay #replay_codes_underlay is the set of codes in effect at the very end of the original underlay
#replay_codes_overlay is the set of codes in effect at the very end of the original overlay (even if not all overlay was applied) #replay_codes_overlay is the set of codes in effect at the very end of the original overlay (even if not all overlay was applied)
#todo - replay_codes for gx0 mode #todo - replay_codes for gx0 mode
#overflow_idx may change during ansi & character processing
if {$overflow_idx == -1} {
set overflow_right_column ""
} else {
set overflow_right_column [expr {$overflow_idx+1}]
}
return [list\ return [list\
result $outstring\ result $outstring\
visualwidth [punk::ansi::printing_length $outstring]\ visualwidth [punk::ansi::printing_length $outstring]\
instruction $instruction\ instruction $instruction\
stringlen [string length $outstring]\ stringlen [string length $outstring]\
overflow_idx $overflow_idx\ overflow_right_column $overflow_right_column\
overflow_right $overflow_right\ overflow_right $overflow_right\
unapplied $unapplied\ unapplied $unapplied\
insert_mode $insert_mode\ insert_mode $insert_mode\
autowrap_mode $autowrap_mode\
insert_lines_above $insert_lines_above\ insert_lines_above $insert_lines_above\
insert_lines_below $insert_lines_below\ insert_lines_below $insert_lines_below\
cursor_saved_position $cursor_saved_position\ cursor_saved_position $cursor_saved_position\
cursor_saved_attributes $cursor_saved_attributes\ cursor_saved_attributes $cursor_saved_attributes\
cursor_restore_required $cursor_restore_required\ cursor_restore_required $cursor_restore_required\
cursor_column $cursor_column\ cursor_column $cursor_column\
cursor_row_change $cursor_row\ cursor_row $cursor_row\
opt_overflow $opt_overflow\ opt_overflow $opt_overflow\
replay_codes $replay_codes\ replay_codes $replay_codes\
replay_codes_underlay $replay_codes_underlay\ replay_codes_underlay $replay_codes_underlay\
@ -2075,7 +2186,8 @@ namespace eval overtype::priv {
#set unapplied [join [lrange $overlay_grapheme_control_list $gci+1 end]] #set unapplied [join [lrange $overlay_grapheme_control_list $gci+1 end]]
set unapplied "" set unapplied ""
append unapplied [join [lindex $overstacks $idx_over] ""] #append unapplied [join [lindex $overstacks $idx_over] ""]
append unapplied [punk::ansi::codetype::sgr_merge_list {*}[lindex $overstacks $idx_over]]
switch -- [lindex $overstacks_gx $idx_over] { switch -- [lindex $overstacks_gx $idx_over] {
"gx0_on" { "gx0_on" {
append unapplied "\x1b(0" append unapplied "\x1b(0"
@ -2097,7 +2209,6 @@ namespace eval overtype::priv {
} else { } else {
append unapplied $item append unapplied $item
} }
#incr idx_over
} }
} }
proc render_delchar {i} { proc render_delchar {i} {

Loading…
Cancel
Save