Browse Source

ansi fixes - cursor movement

master
Julian Noble 9 months ago
parent
commit
c29cf8b146
  1. 153
      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. 831
      src/vendormodules/overtype-1.5.9.tm

153
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,21 +182,47 @@ 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 ansidata [encoding convertfrom cp437 $data]
} else {
set ansidata $data
}
set obj [punk::ansi::class::class_ansi new $ansidata] set obj [punk::ansi::class::class_ansi new $ansidata]
return $obj 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 {
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]
$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 :-)
[\x00-\x7F] | # Single-byte chars (ASCII range) [\x00-\x7F] | # Single-byte chars (ASCII range)
@ -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]

831
src/vendormodules/overtype-1.5.9.tm

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