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
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
#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
#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
#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
#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 ""} {
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"
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]]
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
#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
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?
#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.