From cc016efdb022b6e85af906d9a8acc2b0c6848f92 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Fri, 15 Mar 2024 04:52:51 +1100 Subject: [PATCH] punk::ansi::example + ansi code_merge fixes --- src/modules/punk/ansi-999999.0a1.0.tm | 73 ++++++++++++++++++++++++--- src/testansi/bot.ans | 47 +++++++++++++++++ src/vendormodules/overtype-1.6.0.tm | 60 +++++++++++++++++----- 3 files changed, 160 insertions(+), 20 deletions(-) create mode 100644 src/testansi/bot.ans diff --git a/src/modules/punk/ansi-999999.0a1.0.tm b/src/modules/punk/ansi-999999.0a1.0.tm index 41fc34ee..8ac1fa61 100644 --- a/src/modules/punk/ansi-999999.0a1.0.tm +++ b/src/modules/punk/ansi-999999.0a1.0.tm @@ -101,13 +101,11 @@ namespace eval punk::ansi::class { } set cksum "not-done" if {$dimensions ne $o_render_dimensions || $o_rendered_what ne [set cksum [$o_ansistringobj checksum]]} { - set b [textblock::block $w $h " "] #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_ansistringobj GET]] set o_rendered [overtype::left -overflow 0 -wrap 1 -width $w -appendlines 1 "" [$o_ansistringobj get]] if {$cksum eq "not-done"} { #if dimensions changed - the checksum won't have been done @@ -135,6 +133,7 @@ namespace eval punk::ansi::class { return $rendered } method render_to_input_line {x {minuschar 0}} { + package require textblock set lfvis [ansistring VIEW -lf 1 \n] set maplf [list \n "[a+ green bold reverse]${lfvis}[a]\n"] ;#a mapping to highlight newlines @@ -383,6 +382,64 @@ namespace eval punk::ansi { } $text completeChars return $completeChars } + proc example {} { + #todo - review dependency on punk::repo ? + package require textblock + package require punk::repo + package require punk::console + + set fnames [list belinda.ans bot.ans flower.ans fish.ans] + set base [punk::repo::find_project] + set ansibase [file join $base src/testansi] + if {![file exists $ansibase]} { + puts stderr "Missing testansi folder at $base/src/testansi" + puts stderr "Ensure ansi test files exist: $fnames" + #error "punk::ansi::example Cannot find example files" + } + set missingbase [a+ yellow][textblock::block 80 23 ?][a] + set pics [list] + foreach f $fnames { + if {![file exists $ansibase/$f]} { + set p [overtype::left $missingbase "[a+ red bold]\nMissing file\n$ansibase/$f[a]"] + lappend pics [dict create filename $f pic $p status missing] + } else { + set img [join [lines_as_list -line trimline -block trimtail [ansicat $ansibase/$f]] \n] + lappend pics [dict create filename $f pic $img status ok] + } + } + + set termsize [punk::console:::get_size] + set margin 4 + set freewidth [expr {[dict get $termsize columns]-$margin}] + set per_row [expr {$freewidth / 80}] + + set rowlist [list] + set row [list] + set i 1 + foreach picinfo $pics { + set subtitle "" + if {[dict get $picinfo status] ne "ok"} { + set subtitle [dict get $picinfo status] + } + set title [dict get $picinfo filename] + lappend row [textblock::frame -subtitle $subtitle -title $title [dict get $picinfo pic]] + if {$i % $per_row == 0} { + lappend rowlist $row + set row [list] + } elseif {$i == [llength $pics]} { + lappend rowlist $row + } + incr i + } + + set result "" + foreach r $rowlist { + append result [textblock::join {*}$r] \n + } + + + return $result + } #control strings #https://www.ecma-international.org/wp-content/uploads/ECMA-48_5th_edition_june_1991.pdf # @@ -1755,12 +1812,12 @@ namespace eval punk::ansi { switch -- [lindex $plist $i+1] { 5 { #256 - 1 more param - dict set codestate fg "5\;[lindex $plist $i+2]" + dict set codestate fg "38\;5\;[lindex $plist $i+2]" incr i 2 } 2 { #rgb - dict set codestate fg "2\;[lindex $plist $i+2]\;[lindex $plist $i+3]\;[lindex $plist $i+4]" + dict set codestate fg "38\;2\;[lindex $plist $i+2]\;[lindex $plist $i+3]\;[lindex $plist $i+4]" incr i 4 } } @@ -1783,12 +1840,12 @@ namespace eval punk::ansi { switch -- [lindex $plist $i+1] { 5 { #256 - 1 more param - dict set codestate bg "5\;[lindex $plist $i+2]" + dict set codestate bg "48\;5\;[lindex $plist $i+2]" incr i 2 } 2 { #rgb - dict set codestate bg "2\;[lindex $plist $i+2]\;[lindex $plist $i+3]\;[lindex $plist $i+4]" + dict set codestate bg "48\;2\;[lindex $plist $i+2]\;[lindex $plist $i+3]\;[lindex $plist $i+4]" incr i 4 } } @@ -1821,12 +1878,12 @@ namespace eval punk::ansi { switch -- [lindex $plist $i+1] { 5 { #256 - 1 more param - dict set codestate underlinecolour "5\;[lindex $plist $i+2]" + dict set codestate underlinecolour "58\;5\;[lindex $plist $i+2]" incr i 2 } 2 { #rgb - dict set codestate underlinecolour "2\;[lindex $plist $i+2]\;[lindex $plist $i+3]\;[lindex $plist $i+4]" + dict set codestate underlinecolour "58\;2\;[lindex $plist $i+2]\;[lindex $plist $i+3]\;[lindex $plist $i+4]" incr i 4 } } diff --git a/src/testansi/bot.ans b/src/testansi/bot.ans new file mode 100644 index 00000000..b522ac4b --- /dev/null +++ b/src/testansi/bot.ans @@ -0,0 +1,47 @@ +°°°°°°°°°°°°±±±±±±±²²²²²² ÜÜ +ÜÜÜ ²²²±±±±°°°° °°°°°°°°±±±±±± +±±²²²²²² ÜÜÜÜÜßßßßßÜÜ  + ²²²²±±±°° °°°°±±±±±±±±²²²²²²² + ÜÜÛÛÛßßÜÜ  + ÜÜÜÜÜÜܲ²²±±° °°±±±±±±²²²²²²²²  + ÜÜÛ²²Û°±Û  ÜÜ +ÜÜÜßÜÜÜÜÜÜÜܱܱ±° °°±±± +²²ÜÜÜÜÜÜ ÜÜÛ²±²²° °±Û   +ÜÜÜÜßÛÛÜß °°°°°°°  +°°±° °±±²ÜÜßÛÛÛÛÛÛ +ßÜÜÜÜ Û²±±²± +°° °±Û  ÜÜÛÛ²²²±°° °± +±°°°° °±²ÜÛ²²²±±±°°°°°ßßÜÜ  +Üܲ²±±²± °°°° °°ßÜÜ +ÜÛ²²²±±°° °±±° ùáSù ° +° °ÜÛ²²±±°°°°° ßÜÜ +Ü Û²±±±²Û° °°±° °±°°Û²²±±°° +° °±±° ÄÄiCEÄÄ° + Û²²°±°°° ° °±²±° ß²ÜÜ Û±°°°±²± ° ° +°±° °±°°Ûßßßßßß²ÜÜ °±°± ²±±°°°  +°°° °±²±°ÜÜÜÜÛÜ°°°°ßܱ°°° °°Üß +ßßܱ°° ±°°° °±°° °²±°Ü +²²²²²²²²²Ü ß°°°°²°ù °° °±° +° °±°ܲ²²²±±±±±°° ß°±±°±ù ° °±° +° °°° °²²²±±°°°±²±°°³ °±° +° °°° °±±±±°° °°±Û²°³ùùÄ +ÄÅÄÄùù ÛßÜ  +ÛßÜ ÛßÜ ÛÛÜ Û Ü + Ûßß  ÛßÜ Û Ü + ÛßÜ ÛßÜÛÛßÜ +ÛÛßÜÛÛßß ³ +ÛÛßÜ ÛÛßÜ ÛÛ Û ÛÛ ÛÛßÛ ÛÛßß ÛÛßÜ ÛÛßÛ ÛÛ Û ÛÛ Û ÛÛ Û ÛÛ Û Û +Ûß ³ßßßß ßß ß ßßßß + ßß ßß ß ßßßß ß +ß ß ßß ß ßßßß ßßßß ßßß  + ßßßß ßß ùßßß +ßßßßßß ÜÛßÜÜÜÛßßÜÛ +ßÜÛßßßßßß Üßß +ÜßßÜÛßßßßßß ÜÛ +ßßßßßß ùÛÛÛÛÛÛ ÛÛÛ ÛÛÛ ÛÛÛßßßßß ÛÛ +Û ÛÛÛ ÛÛÛßßßßß ßßßßßÛÛÛßßßßß ßß ßßß ßßßßßßß  +ßßßßßßß ßßßßßßß ßßßßßßßù Main BBS: 215/ +374-0421 Ä*Ä CAE System: 215/796-9249  +ù + + diff --git a/src/vendormodules/overtype-1.6.0.tm b/src/vendormodules/overtype-1.6.0.tm index 57923538..4e7844bf 100644 --- a/src/vendormodules/overtype-1.6.0.tm +++ b/src/vendormodules/overtype-1.6.0.tm @@ -1526,7 +1526,8 @@ proc overtype::renderline {args} { # 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 {[punk::ansi::codetype::is_sgr_reset $code]} { - set u_codestack [list] + #set u_codestack [list] + set u_codestack [list "\x1b\[m"] } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { set u_codestack [list $code] } elseif {[punk::ansi::codetype::is_sgr $code]} { @@ -1672,7 +1673,7 @@ proc overtype::renderline {args} { lappend overlay_grapheme_control_stacks $o_codestack #there will always be an empty code at end due to foreach on 2 vars with odd-sized list ending with pt (overmap coming from perlish split) if {[punk::ansi::codetype::is_sgr_reset $code]} { - set o_codestack [list] + set o_codestack [list "\x1b\[m"] ;#reset better than empty list - fixes some ansi art issues lappend overlay_grapheme_control_list [list sgr $code] } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { set o_codestack [list $code] @@ -1686,7 +1687,8 @@ proc overtype::renderline {args} { } elseif {[regexp {\x1b7|\x1b\[s} $code]} { #experiment #cursor_save - for the replays review. - set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] + #jmn + #set temp_cursor_saved [punk::ansi::codetype::sgr_merge_list {*}$o_codestack] lappend overlay_grapheme_control_list [list other $code] } elseif {[regexp {\x1b8|\x1b\[u} $code]} { #experiment @@ -2128,10 +2130,11 @@ proc overtype::renderline {args} { 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_vt_sequence {\x1b\[([0-9]*)(?:;){0,1}([0-9]*)~$} - set re_cursor_save {\x1b\[s$} - set re_cursor_restore {\x1b\[u$} - set re_cursor_save_dec {\x1b7$} - set re_cursor_restore_dec {\x1b8$} + set re_cursor_save {\x1b\[s$} + set re_cursor_restore {\x1b\[u$} + set re_cursor_save_dec {\x1b7$} + set re_cursor_restore_dec {\x1b8$} + set re_decstbm {\x1b\[([0-9]*)(?:;){0,1}([0-9]*)r$} ;#DECSTBM set top and bottom margins set matchinfo [list] switch -regexp -matchvar matchinfo -- $code\ @@ -2339,6 +2342,22 @@ proc overtype::renderline {args} { set instruction move break }\ + $re_decstbm { + #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 + lassign $matchinfo _match margin_top margin_bottom + + #todo - return these for the caller to process.. + puts stderr "overtype::renderline DECSTBM set top and bottom margin not implemented" + #Also moves the cursor to col 1 line 1 of the page + set cursor_column 1 + set cursor_row 1 + + incr idx_over + priv::render_unapplied $overlay_grapheme_control_list $gci + set instruction move ;#own instruction? decstbm? + 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~ @@ -2442,7 +2461,8 @@ proc overtype::renderline {args} { sgr { #code is the raw code if {[punk::ansi::codetype::is_sgr_reset $code]} { - set sgr_stack [list] + #jmn + set sgr_stack [list "\x1b\[m"] } elseif {[punk::ansi::codetype::has_sgr_leadingreset $code]} { set sgr_stack [list $code] lappend overlay_grapheme_control_list [list sgr $code] @@ -2514,6 +2534,7 @@ proc overtype::renderline {args} { break }\ $re_mode { + lassign $matchinfo _match num type switch -- $num { 5 { #DECSNM - reverse video @@ -2551,8 +2572,21 @@ proc overtype::renderline {args} { set overflow_idx -1 } } + 25 { + if {$type eq "h"} { + #visible cursor + + } else { + #invisible cursor + + } + } } + }\ + default { + #puts stderr "overtype::renderline code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code] not implemented" } + } default { #don't need to handle sgr or gx0 types @@ -2613,9 +2647,11 @@ proc overtype::renderline {args} { set cstack [lindex $understacks $i] if {$cstack ne $prevstack} { if {[llength $prevstack] && ![llength $cstack]} { + #This reset is important e.g testfile fruit.ans - we get overhang on rhs without it. But why is cstack empty? append sgrleader \033\[m + } else { + append sgrleader [punk::ansi::codetype::sgr_merge_list {*}$cstack] } - append sgrleader [punk::ansi::codetype::sgr_merge_list {*}$cstack] } set prevstack $cstack } else { @@ -2637,9 +2673,9 @@ proc overtype::renderline {args} { set cstack [lindex $understacks $i] set sgrleader "" #whether cstack is same or differs from previous char's stack - we must have an output at the start of the overflow_right - if {[llength $prevstack] && ![llength $cstack]} { - append sgrleader \033\[m - } + #if {[llength $prevstack] && ![llength $cstack]} { + # append sgrleader \033\[m + #} append sgrleader [punk::ansi::codetype::sgr_merge_list {*}$cstack] append overflow_right $sgrleader append overflow_right $ch