Browse Source

more ansi and repl fixes

master
Julian Noble 9 months ago
parent
commit
be20491421
  1. 3
      src/modules/punk/ansi-999999.0a1.0.tm
  2. 2
      src/modules/punk/repl-0.1.tm
  3. 94
      src/testansi/fox_goat.ans
  4. 409
      src/vendormodules/overtype-1.5.9.tm
  5. 2401
      src/vendormodules/overtype-1.6.0.tm

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

@ -100,7 +100,8 @@ namespace eval punk::ansi::class {
#overflow is a different concept - perhaps not particularly congruent with the idea of the textblock as a mini terminal emulator.
#overflow effectively auto-expands the block(terminal?) width
#overflow and wrap both being true won't make sense unless we implement a max_overflow concept
set o_rendered [overtype::left -overflow 0 -wrap 1 -appendlines 1 $b $o_raw]
#set o_rendered [overtype::left -overflow 0 -wrap 1 -appendlines 1 $b $o_raw]
set o_rendered [overtype::left -overflow 0 -wrap 1 -width 80 -appendlines 1 "" $o_raw]
#set o_rendered_what $o_raw
set o_render_dimensions $dimensions
}

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

@ -1945,7 +1945,7 @@ proc repl::repl_process_data {inputchan type chunk stdinlines prompt_config} {
}
}
}
set last_cursor_colun [$editbuf cursor_column]
set last_cursor_column [$editbuf cursor_column]
} else {
#rputs stderr "->0byte read stdin"
if {[chan eof $inputchan]} {

94
src/testansi/fox_goat.ans

@ -0,0 +1,94 @@

ワワ ワ ワ ワロワ ワワ゚ロ゚ ワワワワワワロワワワワワワワワ
ワ ワ ワ ワワ
ワ ロワロ゚゚゚ロロワロロ ロロワ゚゚ ゚ ワ゚ロ ロ ロロロロロロロロロロロロロロロワワワワ
゚゚ワワロワ ゚ロロ ワロワ ワ
゚ワワ゚゚ロ゚゚ワ ゚ ワロロロロ゚ロロワ ゚゚ロ゚ ワ ロワロワ ロ
ロロロワワ゚゚゚゚゚ロロロロロロロロロロワワワワワワワワ ワ
ワ
゚゚ワワ ロワロワロ ワワ゚゚゚ ゚ ワワ゚ ゚゚
ワワロ ワ゚ ロ ロロロロ ゚゚ロ゚゚ワワワワワ゚゚゚゚゚ロロロロロ゚゚゚゚゚ロワ
ロ゚゚゚ワワロロ゚ワワ゚゚ワワ ゚ロワ゚ワワ
ワロ゚ロワワ ロ ロロロロ ワワワ゚゚
゚゚゚ワワワワワ゚゚゚゚゚ロロ
ロ ロ゚ワワロロ゚ワワワワワワ゚゚゚ ゚゚ ゚゚ワロワワワ゚゚
ロ゚ロワ ロ ロロロロ ゚ワロ゚ワロロロ゚゚ロ゚゚ワ
ワ
゚ロロロワワ゚゚゚゚ ゚ ロロロロワ ゚゚゚゚ロロロロロロ゚゚ ゚゚ロワ゚
ロ ロロロロ ワロワワワロワワ゚ワ゚ワ
ロ゚ロロワ゚゚゚ ロロ゚ ロ゚ ロ゚ロロロ゚ロロワロ ロロロロ ゚ ロ゚
ワロロロ ロロロワ゚ワ ワ ゚ワ゚
゚ロ゚ ロ゚゚ロ゚ワロ ロロワロ ロロロロ ロ゚ワ ロロロ ワ ロロロ
 ロ ゚゚ロ
ロワワワワワロロワ ロ゚ワロ ゚ ワワワワワ
ロ ロロロロワロロロロ ロロ
ワ ロワロ゚ ゚゚ロ゚ ゚ワワワ ワロロ゚゚ロ゚
゚ ワ゚ロロロロロ゚ ロロ
ロワロロ゚ ゚゚ワワワ゚ロロロロ ロロ゚ ワロ゚゚ ワワワワ
ロロ ゚ロロ゚
ロワ゚ロワ゚゚ ワ ワ゚ワワワワロロロロロロロ ロロ ワワロロロロロ゚ ロロ
゚゚ロワ ゚
ロ゚ ワ ロワロ゚゚゚゚゚ワワ゚ワロロロロロロロロロロロワロワロロロロロロロ
゚゚ワロワロ
ロ ワ ロロ゚ ゚゚ワワロロロロロロロロロロ゚ロロロロロロロロロ゚ロロ
ロロ
ロロ゚ ワ ワワロロロロロ゚ロロロロロロロワ゚ロロロロワワロロロ
ワロ゚ロロ
゚ ロワロワロ゚゚ワワワロロロロロロ ロロロロロロ゚ ゚ロロロロロロ
゚ ゚゚
ロワ゚ロ゚ロ ゚゚ワロロロロロロロロワ゚ロロ゚ワ ロ ゚ロ゚ロ
ロ ワワワワワ ロ
ロ ゚ワワロロロロロロロロロロワロロロロ ロ ワ ゚゚
ワロロロ゚゚゚゚゚ワ
ワワロロロロロロロロロロロロロロロロ ロ ロロワ゚ロワワ゚゚ワ
゚ワロロロロロロロワ
ワワワワワワワ゚ロロロロロロロロロロロロロロロ ロロロ ロロロワ゚ロロ
ワ゚ロロロ゚ ワ゚ ゚ロ ゚ワ
ワロロロロロロロロワワワロロロロロロロロロロロロロロロ゚ワロ゚ロ ロロロワワ
ロ゚ロワ゚ロロロロロロロワワ ワ゚ ゚
ロロロロロロロロロロワワワワロロロロロロロロロロワ゚ロロロロロ ワロロ ロロロ ワロ
゚゚ロロロワ ロロロロロロロロロロロ゚ワ
゚ロロ゚ワロロロロロロ ゚ワロロロロロロロロロロロロロ ロロロロロロ ロロ ロ ロロロ 
゚゚゚゚ロロロロロロロロロロロロロロロ゚ロロ
゚ ゚ワロロロロロ ロロロロロロ゚ロロロロロロロ゚゚ ゚ロロロワ゚ロワ ロ ロロロ 
゚゚゚ロロロロロロロ ロロロロロロロワワワ
ロ゚ロロロロ ロロロロロロロワ゚ロロロロワ゚ ロロワ゚ロロ ゚ ロ゚゚
ワワワ ロ゚ロロ゚ロロ゚ワロロロロロロロロ ワワワワワ゚
ロロロロロロロワワロロロロロロロロロロワロ゚ワ゚ロ゚ロワ ロロロロワ゚ ワワワワワ ゚ワロロ ワ
ロロロロロロロロロ ロ ワワワワ ワ
ワロ ゚ロ゚ロロロロロロロロロロロロロロロロロロロロ ロロ゚ロロワワワ゚゚ワ゚ロロ ワワロロロ
ロロロロロ ゚ワ ロロ
ロワ ロ゚ロロロロロロ ロロロロロロロロロロロロ ロロロロ゚ロロロロ ゚ワ゚ ワロロロロロ
ロロロワロワ゚ワ
ロロ ロワ ゚ ゚ ゚ロロロロロロロロロロ゚ワロロロ ワ ロワ ワ゚゚゚゚ワワワ
ワ ロロロロロロロロロロロロロワ ゚ロワ ゚ ゚
゚ワワロ゚ワ゚ロロロロロロ゚゚ワロロ゚゚ロ ロロロロワワワワ゚ ワ゚゚゚゚゚゚
゚゚゚゚゚゚゚゚゚゚゚゚゚ワロロロワロロ
゚゚ロワ゚゚゚゚ワロロロロロロ ロロ゚゚ワワロ ロ ロロロロロロロロロロロロワワワワワワ
ワワワワワワワワワワワワワ ワワワロ ゚
゚ ロワ ワ ロワロ ロロ゚ロロロロ゚ワロロロロワ ワ゚ロ ロ ロ゚ロロロロロロロロロロロ
ロロロロロロロロロロロロロロロロ ワワロロ ゚
ワワロ゚ロロ゚ロ゚゚ロロロ゚ ゚゚ロロロ ゚ワロ ロ ロ ロ ワ ロワワワ゚゚゚゚゚ロロロ
ロロロロロロロロロロロロロロロロ ワ ゚゚ロ゚゚ワワ
゚ロ ゚゚ ワワワロ゚゚ ゚ロロ ワ゚ワ゚ワ ゚ロロワ゚゚゚゚ロ゚ 
ロロロロ ロロロロワワ ワワワワ ワワワワ ワ ワ ワ ゚ロワロ゚ ワ
ワロロロロロロ゚゚゚゚ ゚ロロロ゚ロロロワロワワワ ゚゚゚゚゚゚ ロロロロ ゚゚゚ 
゚゚ロワロロワロロロ゚ワワ ロ
ロロロロワ ワワワワ ワロロワ ゚゚゚゚゚ ゚゚゚ 
ワ゚゚゚ワ ロロロロ ロロロロ ゚゚゚゚゚゚゚゚ロ゚゚ ワロロ゚゚ ロロ゚ ロロ゚ワ
ロワワ ワワロロロワワ ゚ ゚ロロロ ワ ワ゚゚ロ ロ ゚ロ
ロロ ロロロロ ロロロロロロロ ロ ロロ ワワロワ ゚ ロロロ ロ ロ
゚゚゚゚゚゚゚゚ ゚゚ ゚ ロワワ ワ゚゚ ロ ワ ゚
ロワロロロロワロロロロロロロワロワロロワ ゚゚゚ワワロロ゚゚ロワ ロ゚
George Ramos (C)Copyright 1992
ワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワワ
ワワワワワワワワワワワワワワワ
ロロワ ワロ ロ ロ ワワロロロ ワワロ゚ワ゚ロワ゚ロ゚ワロロロロ ロロ ゚ロ ロ ワ゚ロロロワ ワロ ロ ロ ワワロロロ゚ワワロロ゚ワ゚
ロロ ロロワ ワロロ
ロロロ ロロ ワ ロ ワロロロロ ワロロ ロ ロロ゚ワ゚ロロロロ ゚ ロ ロワ ロ ロ ロロロロ ロロ ワ ロ ワロロロロ ロロ゚ロ ロ 
ロ ゚ ロロ ロロロ
ロロロワロロワロワロワワワロロロワロロロロワロロワロロロワロロロワロワロワロロワロワワロロロロロワロロワロワロワワワロロロロワワロロロワロ
ロワロワロロワロロロ



409
src/vendormodules/overtype-1.5.9.tm

@ -209,6 +209,10 @@ proc overtype::string_columns {text} {
# a cursor start position other than top-left is a possible addition to consider.
#see editbuf in punk::repl for a more stateful ansi-processor. Both systems use loops over overtype::renderline
proc overtype::left {args} {
#*** !doctools
#[call [fun overtype::left] [arg args] ]
#[para] usage: ?-transparent [0|1]? ?-overflow [1|0]? ?-ellipsis [1|0]? ?-ellipsistext ...? undertext overtext
# @c overtype starting at left (overstrike)
# @c can/should we use something like this?: 'format "%-*s" $len $overtext
variable default_ellipsis_horizontal
@ -268,6 +272,7 @@ proc overtype::left {args} {
set underblock [string map $norm $underblock]
set overblock [string map $norm $overblock]
#set underlines [split $underblock \n]
#underblock is a 'rendered' block - so width height make sense
@ -276,7 +281,11 @@ proc overtype::left {args} {
} else {
set colwidth $opt_width
}
set underlines [lines_as_list -ansiresets 1 $underblock]
if {$underblock eq ""} {
set underlines [list "\x1b\[0m\x1b\[0m"]
} else {
set underlines [lines_as_list -ansiresets 1 $underblock]
}
set overlines [split $overblock \n]
#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
@ -296,7 +305,11 @@ proc overtype::left {args} {
set outputlines $underlines
set underlay_resets [list]
for {set overidx 0} {$overidx < [llength $overlines]} {incr overidx} {
set overidx 0
while {$overidx < [llength $overlines]} {
flush stdout
set overtext [lindex $overlines $overidx]; lset overlines $overidx ""
set undertext [lindex $outputlines [expr {$row -1}]]
set renderedrow $row
@ -311,6 +324,7 @@ proc overtype::left {args} {
}
#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 adequately we need to support IRM (insertion-replacement mode) ESC [ 4 h|l
set LASTCALL [list -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 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 insert_mode [dict get $rinfo insert_mode]
@ -330,6 +344,8 @@ proc overtype::left {args} {
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]
#-- todo - detect looping properly
if {$row > 1 && $overtext ne "" && $unapplied eq $overtext && $post_render_row == $row} {
puts stderr "overtype::left loop?"
@ -341,7 +357,6 @@ proc overtype::left {args} {
set cursor_saved_position $c_saved_pos
set cursor_saved_attributes $c_saved_attributes
}
set cursor_restore_required [dict get $rinfo cursor_restore_required]
#background line is narrower than data in line
@ -383,7 +398,7 @@ proc overtype::left {args} {
if {$opt_appendlines} {
lappend outputlines $rendered
} else {
#?
#?
lset outputlines [expr {$renderedrow-1}] $rendered
}
}
@ -391,42 +406,12 @@ proc overtype::left {args} {
set nextprefix ""
if {$cursor_restore_required} {
if {[dict exists $cursor_saved_position row]} {
set row [dict get $cursor_saved_position row]
set col [dict get $cursor_saved_position column]
#puts stdout "restoring: row $row col $col [ansistring VIEW $cursor_saved_attributes] [a] unapplied [ansistring VIEWCODES $unapplied]"
#set nextprefix $cursor_saved_attributes
lset replay_codes_overlay [expr $overidx+1] $cursor_saved_attributes
set cursor_saved_position [dict create]
set cursor_saved_attributes ""
} else {
#TODO
#?restore without save?
#should move to home position and reset ansi SGR?
#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 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 {!$overflow_handled && $overflow_right ne ""} {
#wrap before restore? - possible effect on saved cursor position
#this overflow data has previously been rendered so has no cursor movements or further save/restore operations etc
#we can just insert another call to renderline to solve this.. ?
#It would perhaps be more properly handled as a queue of instructions from our initial renderline call
#we don't need to worry about overflow next call- but we should carry forward our gx and ansi stacks
set blank [string repeat " " [punk::ansi::printing_length $overflow_right]] ;#use size of rendered overflow rather than colwidth which would add trailing space
set foldline [overtype::renderline $blank $overflow_right]
linsert outputlines $renderedrow $foldline
#review - row & col set by restore - but not if there was no save..
}
set overflow_handled 1
} else {
#todo - handle potential insertion mode as above for cursor restore?
#keeping separate branches for debugging - review and merge as appropriate when stable
switch -- $instruction {
"" {
if {$unapplied eq ""} {
{} {
flush stdout
if {$unapplied eq "" && [ansistring length $rendered]} {
#consumed all overlay - no instruction
set col 1
incr row
@ -436,79 +421,138 @@ proc overtype::left {args} {
}
}
up {
#renderline already knows not to go above l
#renderline knows it's own line number, and knows not to go above row l
#it knows that a move whilst 1-beyond the width conflicts with the linefeed and reduces the move by one accordingly.
#row returned should be correct.
#column may be the overflow column - as it likes to report that to the caller.
#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.
#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"
#puts stdout "1 row:$row col $col"
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
}
set col $post_render_col
#puts stdout "2 row:$row col $col"
#puts stdout "-----------------------"
#puts stdout $rinfo
#flush stdout
}
down {
#renderline doesn't know how far down we can go..
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]
} else {
set row $post_render_row
if {$opt_appendlines} {
set diff [expr {$post_render_row - [llength $outputlines]}]
if {$diff > 0} {
lappend outputlines {*}[lrepeat $diff ""]
}
lappend outputlines ""
}
}
set row $post_render_row
set col $post_render_col
}
restore_cursor {
#testfile belinda.ans uses this
#puts stdout "[a+ blue bold]CURSOR_RESTORE[a]"
if {[dict exists $cursor_saved_position row]} {
set row [dict get $cursor_saved_position row]
set col [dict get $cursor_saved_position column]
#puts stdout "restoring: row $row col $col [ansistring VIEW $cursor_saved_attributes] [a] unapplied [ansistring VIEWCODES $unapplied]"
#set nextprefix $cursor_saved_attributes
lset replay_codes_overlay [expr $overidx+1] $cursor_saved_attributes
set cursor_saved_position [dict create]
set cursor_saved_attributes ""
} else {
#TODO
#?restore without save?
#should move to home position and reset ansi SGR?
#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 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 {!$overflow_handled && $overflow_right ne ""} {
#wrap before restore? - possible effect on saved cursor position
#this overflow data has previously been rendered so has no cursor movements or further save/restore operations etc
#we can just insert another call to renderline to solve this.. ?
#It would perhaps be more properly handled as a queue of instructions from our initial renderline call
#we don't need to worry about overflow next call (?)- but we should carry forward our gx and ansi stacks
set sub_info [overtype::renderline -info 1 -width $colwidth -insert_mode $insert_mode -autowrap_mode $autowrap_mode -overflow [dict get $opts -overflow] "" $overflow_right]
set foldline [dict get $sub_info result]
set insert_mode [dict get $sub_info insert_mode] ;#probably not needed..
set autowrap_mode [dict get $sub_info autowrap_mode] ;#nor this..
linsert outputlines $renderedrow $foldline
#review - row & col set by restore - but not if there was no save..
}
set overflow_handled 1
}
move {
########
#Ansi moves need to create new lines
if {$post_render_row > [llength $outputlines]} {
set row [llength $outputlines]
if {$opt_appendlines} {
set diff [expr {$post_render_row - [llength $outputlines]}]
if {$diff > 0} {
lappend outputlines {*}[lrepeat $diff ""]
}
set row $post_render_row
} else {
set row [llength $outputlines]
}
} else {
set row $post_render_row
}
#######
set col $post_render_col
#overflow + unapplied?
}
newline_above - newline_below {
#todo
newlines_above {
#renderline doesn't advance the row for us - the caller has the choice to implement or not
set row $post_render_row
set col $post_render_col
if {$new_lines_above > 0} {
set outputlines [linsert $outputlines $row [lrepeat $new_lines_above ""]]
incr row $new_lines_above ;#we should end up on the same line of text (at a different index), with new empties inserted above
}
}
newlines_below {
puts newlines_below
}
wrap {
#hard wraps in this context.
wrapmoveforward {
#doesn't seem to be used by fruit.ans testfile
#used by dzds.ans
#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
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
set c $colwidth
set r $post_render_row
if {$post_render_col > $colwidth} {
set i $c
while {$i <= $post_render_col} {
if {$c == $colwidth+1} {
incr r
if {$opt_appendlines} {
if {$r < [llength $outputlines]} {
lappend outputlines ""
}
}
set c 1
} else {
incr c
}
incr i
}
set col $c
} else {
set r [expr {$post_render_row +1}]
set c $post_render_col
}
set row $r
set col $c
}
overflow {
#normal single-width grapheme overflow
@ -517,7 +561,7 @@ proc overtype::left {args} {
if {!$autowrap_mode} {
set overflow_handled 1
set unapplied ""
#handled by dropping it..
#handled by dropping it
}
}
overflow_splitchar {
@ -528,10 +572,11 @@ proc overtype::left {args} {
set col 1
} else {
set overflow_handled 1
#handled by dropping it..
#handled by dropping it
}
}
vt {
#can vt add a line like a linefeed can?
set row $post_render_row
set col $post_render_col
@ -541,15 +586,12 @@ proc overtype::left {args} {
}
}
}
if {!$overflow_handled} {
append nextprefix $overflow_right
}
append nextprefix $unapplied
#if {$instruction ne ""} {
# puts "---->>instruction:'$instruction' nextprefix:[ansistring VIEW $nextprefix]<<---"
#}
if {$nextprefix ne ""} {
set nextoveridx [expr {$overidx+1}]
if {$nextoveridx >= [llength $overlines]} {
@ -566,6 +608,7 @@ proc overtype::left {args} {
#lset replay_codes_overlay [expr $overidx+1] [dict get $rinfo replay_codes_overlay]
set prevrow $renderedrow
incr overidx
}
#puts stdout $underlay_resets
return [join $outputlines \n]
@ -906,13 +949,37 @@ proc overtype::grapheme_width_cached {ch} {
return $width
}
#v2
#-returnextra to enable returning of overflow and length
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
#
#
#-returnextra enables returning of overflow and length
#review - use punk::ansi::ta::detect to short-circuit processing and do simpler string calcs as an optimisation?
#review - DECSWL/DECDWL double width line codes - very difficult/impossible to align and compose with other elements
#(could render it by faking it with sixels and a lot of work - find/make a sixel font and ensure it's exactly 2 cols per char)
#todo - review transparency issues with single/double width characters
#bidi - need a base direction and concept of directional runs for RTL vs LTR - may be best handled at another layer?
proc overtype::renderline {args} {
#*** !doctools
#[call [fun overtype::renderline] [arg args] ]
#[para] renderline is the core engine for overtype string processing (frames & textblocks), and the raw mode commandline repl for the Tcl Punk Shell
#[para] It is also a central part of an ansi (micro) virtual terminal-emulator of sorts
#[para] This system does a half decent job at rendering 90's ANSI art to manipulable colour text blocks that can be joined & framed for layout display within a unix or windows terminal
#[para] Renderline helps maintain ANSI text styling reset/replay codes so that the styling of one block doesn't affect another.
#[para] Calling on the punk::ansi library - it can coalesce codes to keep the size down.
#[para] It is a giant mess of doing exactly what common wisdom says not to do... lots at once.
#[para] renderline is part of the Unicode and ANSI aware Overtype system which 'renders' a block of text onto a static underlay
#[para] The underlay is generally expected to be an ordered set of lines or a rectangular text block analogous to a terminal screen - but it can also be ragged in line length, or just blank.
#[para] The overlay couuld be similar - in which case it may often be used to overwrite a column or section of the underlay.
#[para] The overlay could however be a sequence of ANSI-laden text that jumps all over the place.
#
#[para] renderline itself only deals with a single line - or sometimes a single character. It is generally called from a loop that does further terminal-like or textblock processing.
#[para] By suppyling the -info 1 option - it can return various fields indicating the state of the render.
#[para] The main 3 are the result, overflow_right, and unapplied.
#[para] Renderline handles cursor movements from either keystrokes or ANSI sequences but for a full system the aforementioned loop will need to be in place to manage the set of lines under manipulation.
if {[llength $args] < 2} {
error {usage: ?-info 0|1? ?-startcolumn <int>? ?-cursor_column <int>? ?-cursor_row <int>|""? ?-transparent [0|1|<regexp>]? ?-overflow [1|0]? undertext overtext}
}
@ -1053,7 +1120,9 @@ proc overtype::renderline {args} {
#an ugly hack to serve *some* common case ascii quickly with byte-compiled literal switch - feels dirty.
#.. but even 0.5uS per char (grapheme_width_cached) adds up quickly when stitching lots of lines together.
switch -- $grapheme {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? - a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y - z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
" " - - - _ - ! - @ - # - $ - % - ^ - & - * - = - + - : - . - , - / - | - ? -
a - b - c - d - e - f - g - h - i - j - k - l - m - n - o - p - q - r - s - t - u - v - w - x - y -
z - A - B - C - D - E - F - G - H - I - J - K - L - M - N - O - P - Q - R - S - T - U - V - W - X - Y - Z - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 {
set width 1
}
default {
@ -1102,11 +1171,12 @@ proc overtype::renderline {args} {
}
}
}
#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 {$opt_width ne "\uFFEf"} {
if {[llength $understacks]} {
set cs $u_codestack
set gs $u_gx_stack
@ -1287,7 +1357,7 @@ proc overtype::renderline {args} {
for {set gci 0} {$gci < [llength $overlay_grapheme_control_list]} {incr gci} {
set gc [lindex $overlay_grapheme_control_list $gci]
lassign $gc type item
#emit plaintext chars first using existing SGR codes from under/over stack as appropriate
#then check if the following code is a cursor movement within the line and adjust index if so
#foreach ch $overlay_graphemes {}
@ -1295,8 +1365,17 @@ proc overtype::renderline {args} {
g {
set ch $item
incr idx_over; #idx_over (until unapplied reached anyway) is per *grapheme* in the overlay - not per col.
set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our original data width
if {$overflow_idx == -1} {
#review.
#This corresponds to opt_overflow being ture (at least until overflow_idx is in some cases forced to a value when throwing back to calling loop)
set within_undercols false
if {$idx <= [llength $undercols]-1 && [llength $undercols]} {
set within_undercols true
}
} else {
set within_undercols [expr {$idx <= [llength $undercols]-1}] ;#within our active data width
}
if {$overflow_idx != -1} {
@ -1406,24 +1485,50 @@ proc overtype::renderline {args} {
set chtest [string map [list \n <lf> \b <bs> \r <cr> \v <vt> \x7f <del>] $ch]
switch -- $chtest {
"<lf>" {
incr cursor_row
#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2
set overflow_idx $idx
#idx_over already incremented
priv::render_unapplied $overlay_grapheme_control_list $gci
if 1 {
if {$idx == 0} {
#leave the overflow_idx
set insert_lines_above 1 ;#keep for consistency with ansi sequence that requests insertion of line(s)?
set instruction newlines_above
} else {
#linefeed occurred in middle or at end of text
incr cursor_row
#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
}
#idx_over already incremented
priv::render_unapplied $overlay_grapheme_control_list $gci
break
if {$idx == 0} {
set insert_lines_above 1 ;#keep for consistency with ansi sequence that requests insertion of line(s)?
set instruction newline_above
} else {
set insert_lines_below 1
set instruction newline_below
#v1
incr cursor_row
#override overflow_idx even if it was set to -1 due to opt_overflow = 1|2
set overflow_idx $idx
#idx_over already incremented
priv::render_unapplied $overlay_grapheme_control_list $gci
if {$idx == 0} {
set insert_lines_above 1 ;#keep for consistency with ansi sequence that requests insertion of line(s)?
set instruction newlines_above
} else {
set insert_lines_below 1
set instruction newlines_below
}
break
}
break
#set cursor_column 1
}
"<cr>" {
#consider also the old space-carriagereturn softwrap convention used in some terminals.
#In the context of rendering to a block of text - this works similarly in that the space gets eaten so programs emitting space-cr at the terminal width col will pretty much get what they expect.
set idx [expr {$opt_colstart -1}]
set cursor_column $opt_colstart ;#?
}
@ -1478,7 +1583,6 @@ proc overtype::renderline {args} {
priv::render_addchar [expr {$idx-1}] $opt_exposed1 [lindex $understacks $idx-1] [lindex $understacks_gx $idx-1] 0
}
incr idx
incr cursor_column
} else {
set prevcolinfo [lindex $outcols $idx-1]
#for insert mode - first replace the empty 2ndhalf char with exposed2 before shifting it right
@ -1494,9 +1598,10 @@ proc overtype::renderline {args} {
priv::render_addchar [expr {$idx-1}] $opt_exposed1 [lindex $understacks $idx-1] [lindex $understacks_gx $idx-1] 0 ;#replace not insert
} ;# else??
incr idx
}
if {$cursor_column < [llength $outcols] || $overflow_idx == -1} {
incr cursor_column
}
} elseif {$uwidth == 0} {
if {$within_undercols} {
#e.g combining diacritic - increment before over char REVIEW
@ -1512,12 +1617,14 @@ proc overtype::renderline {args} {
incr idx
incr cursor_column
}
if {$cursor_column > [llength $outcols]} {
set cursor_column [llength $outcols]
}
} elseif {$uwidth == 1} {
set owidth [grapheme_width_cached $ch]
if {$owidth == 1} {
priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode
incr idx
incr cursor_column
} else {
priv::render_addchar $idx $ch [lindex $overstacks $idx_over] [lindex $overstacks_gx $idx_over] $insert_mode
incr idx
@ -1528,6 +1635,8 @@ proc overtype::renderline {args} {
priv::render_addchar [expr {$idx+1}] $opt_exposed2 [lindex $understacks $idx+1] [lindex $understacks_gx $idx+1] $insert_mode
}
incr idx
}
if {($cursor_column < [llength $outcols]) || $overflow_idx == -1} {
incr cursor_column
}
} elseif {$uwidth > 1} {
@ -1552,6 +1661,9 @@ proc overtype::renderline {args} {
incr idx 2
incr cursor_column 2
}
if {$cursor_column > [llength $outcols] || $overflow_idx == -1} {
set cursor_column [llength $outcols]
}
}
}
} ;# end switch
@ -1604,22 +1716,27 @@ proc overtype::renderline {args} {
set version 2
if {$version eq "2"} {
set max [llength $outcols]
if {$opt_overflow} {
if {$overflow_idx == -1} {
incr max
}
if {($cursor_column + $num) <= $max} {
incr idx $num
incr cursor_column $num
} else {
if {$opt_autowrap_mode} {
if {$idx == $overflow_idx} {
incr num
}
#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
incr cursor_column $num ;#give our caller the necessary info as columns from start of row
#incr idx_over
#should be gci following last one applied
priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction wrap
set instruction wrapmoveforward
break
} else {
set cursor_column $max
@ -1695,9 +1812,16 @@ proc overtype::renderline {args} {
if {$num eq ""} {set num 1}
incr cursor_row -$num
#if {$overflow_idx != -1} {
# if {$idx == $overflow_idx} {
# #compensate for linefeed
# incr cursor_row
# }
#}
if {$cursor_row < 1} {
set cursor_row 1
}
#ensure rest of *overlay* is emitted to remainder
incr idx_over
priv::render_unapplied $overlay_grapheme_control_list $gci
@ -1706,9 +1830,23 @@ proc overtype::renderline {args} {
break
}
B {
set row_before_move $cursor_row
#move down
if {$num eq ""} {set num 1}
incr cursor_row $num
#if {$overflow_idx != -1} {
# if {$idx == $overflow_idx} {
# #incr cursor_row -1
# if {$cursor_row == $row_before_move} {
# if {!$opt_overflow} {
# #allow other controls to be processed or next grapheme to overflow
# continue
# }
# }
# }
#}
incr idx_over ;#idx_over hasn't encountered a grapheme and hasn't advanced yet
priv::render_unapplied $overlay_grapheme_control_list $gci
set instruction down
@ -1722,7 +1860,7 @@ proc overtype::renderline {args} {
if {$col eq ""} {set col 1}
set max [llength $outcols]
if {$opt_overflow} {
if {$overflow_idx == -1} {
incr max
}
if {$col > $max} {
@ -1818,9 +1956,13 @@ proc overtype::renderline {args} {
#a real terminal would not be able to know the state of the underlay.. so we should probably ignore it.
#set sgr_stack [lindex $understacks $idx]
#set gx_stack [lindex $understacks_gx $idx] ;#not actually a stack - just a boolean state (for now?)
set sgr_stack [list]
set gx_stack [list]
#we shouldn't need to scan for intermediate cursor save/restores - as restores would throw-back to the calling loop - so our overlay 'line' is since those.
#The overlay_grapheme_control_list had leading resets from previous lines - so we go back to the beginning not just the first grapheme.
foreach gc [lrange $overlay_grapheme_control_list 0 $gci-1] {
lassign $gc type code
#types g other sgr gx0
@ -1859,25 +2001,7 @@ proc overtype::renderline {args} {
#append cursor_saved_attributes [join $sgr_stack ""]
append cursor_saved_attributes [punk::ansi::codetype::sgr_merge_list {*}$sgr_stack]
if 0 {
set stack_cur [join [lindex $understacks $idx] ""]
set stack_prev [join [lindex $understacks $idx-1] ""]
puts ">>>'[ansistring VIEW $stack_cur]' prev:'[ansistring VIEW $stack_prev]'"
puts "idx_over: $idx_over"
set cursor_saved_attributes $stack_prev
switch -- [lindex $understacks_gx $idx] {
"gx0_on" {
append cursor_saved_attributes "\x1b(0"
}
"gx0_off" {
append cursor_saved_attributes "\x1b(B"
}
}
}
#as there is apparently only one cursor storage element we don't need to throw back to the calling loop for a save.
#don't incr index - or the save will cause cursor to move to the right
#carry on
@ -1909,9 +2033,9 @@ proc overtype::renderline {args} {
#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.
set instruction move
set cursor_restore_required 1
set instruction restore_cursor
break
}\
$re_mode {
@ -2111,7 +2235,6 @@ proc overtype::renderline {args} {
insert_lines_below $insert_lines_below\
cursor_saved_position $cursor_saved_position\
cursor_saved_attributes $cursor_saved_attributes\
cursor_restore_required $cursor_restore_required\
cursor_column $cursor_column\
cursor_row $cursor_row\
opt_overflow $opt_overflow\

2401
src/vendormodules/overtype-1.6.0.tm

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save