1
0
forked from aniani/vim

patch 8.0.0693: no terminal emulator support

Problem:    No terminal emulator support.  Cannot properly run commands in the
            GUI.  Cannot run a job interactively with an ssh connection.
Solution:   Very early implementation of the :terminal command.  Includes
            libvterm converted to ANSI C.  Many parts still missing.
This commit is contained in:
Bram Moolenaar
2017-07-07 11:54:15 +02:00
parent da5116da45
commit e4f25e4a8d
87 changed files with 11693 additions and 13 deletions

View File

@@ -0,0 +1,200 @@
INIT
UTF8 0
WANTPARSER
!Basic text
PUSH "hello"
text 0x68, 0x65, 0x6c, 0x6c, 0x6f
!C0
PUSH "\x03"
control 3
PUSH "\x1f"
control 0x1f
!C1 8bit
PUSH "\x83"
control 0x83
PUSH "\x9f"
control 0x9f
!C1 7bit
PUSH "\e\x43"
control 0x83
PUSH "\e\x5f"
control 0x9f
!High bytes
PUSH "\xa0\xcc\xfe"
text 0xa0, 0xcc, 0xfe
!Mixed
PUSH "1\n2"
text 0x31
control 10
text 0x32
!Escape
PUSH "\e="
escape "="
!Escape 2-byte
PUSH "\e(X"
escape "(X"
!Split write Escape
PUSH "\e("
PUSH "Y"
escape "(Y"
!Escape cancels Escape, starts another
PUSH "\e(\e)Z"
escape ")Z"
!CAN cancels Escape, returns to normal mode
PUSH "\e(\x{18}AB"
text 0x41, 0x42
!C0 in Escape interrupts and continues
PUSH "\e(\nX"
control 10
escape "(X"
!CSI 0 args
PUSH "\e[a"
csi 0x61 *
!CSI 1 arg
PUSH "\e[9b"
csi 0x62 9
!CSI 2 args
PUSH "\e[3;4c"
csi 0x63 3,4
!CSI 1 arg 1 sub
PUSH "\e[1:2c"
csi 0x63 1+,2
!CSI many digits
PUSH "\e[678d"
csi 0x64 678
!CSI leading zero
PUSH "\e[007e"
csi 0x65 7
!CSI qmark
PUSH "\e[?2;7f"
csi 0x66 L=3f 2,7
!CSI greater
PUSH "\e[>c"
csi 0x63 L=3e *
!CSI SP
PUSH "\e[12 q"
csi 0x71 12 I=20
!Mixed CSI
PUSH "A\e[8mB"
text 0x41
csi 0x6d 8
text 0x42
!Split write
PUSH "\e"
PUSH "[a"
csi 0x61 *
PUSH "foo\e["
text 0x66, 0x6f, 0x6f
PUSH "4b"
csi 0x62 4
PUSH "\e[12;"
PUSH "3c"
csi 0x63 12,3
!Escape cancels CSI, starts Escape
PUSH "\e[123\e9"
escape "9"
!CAN cancels CSI, returns to normal mode
PUSH "\e[12\x{18}AB"
text 0x41, 0x42
!C0 in Escape interrupts and continues
PUSH "\e[12\n;3X"
control 10
csi 0x58 12,3
!OSC BEL
PUSH "\e]1;Hello\x07"
osc "1;Hello"
!OSC ST (7bit)
PUSH "\e]1;Hello\e\\"
osc "1;Hello"
!OSC ST (8bit)
PUSH "\x{9d}1;Hello\x9c"
osc "1;Hello"
!Escape cancels OSC, starts Escape
PUSH "\e]Something\e9"
escape "9"
!CAN cancels OSC, returns to normal mode
PUSH "\e]12\x{18}AB"
text 0x41, 0x42
!C0 in OSC interrupts and continues
PUSH "\e]2;\nBye\x07"
control 10
osc "2;Bye"
!DCS BEL
PUSH "\ePHello\x07"
dcs "Hello"
!DCS ST (7bit)
PUSH "\ePHello\e\\"
dcs "Hello"
!DCS ST (8bit)
PUSH "\x{90}Hello\x9c"
dcs "Hello"
!Escape cancels DCS, starts Escape
PUSH "\ePSomething\e9"
escape "9"
!CAN cancels DCS, returns to normal mode
PUSH "\eP12\x{18}AB"
text 0x41, 0x42
!C0 in OSC interrupts and continues
PUSH "\ePBy\ne\x07"
control 10
dcs "Bye"
!NUL ignored
PUSH "\x{00}"
!NUL ignored within CSI
PUSH "\e[12\x{00}3m"
csi 0x6d 123
!DEL ignored
PUSH "\x{7f}"
!DEL ignored within CSI
PUSH "\e[12\x{7f}3m"
csi 0x6d 123
!DEL inside text"
PUSH "AB\x{7f}C"
text 0x41,0x42
text 0x43

View File

@@ -0,0 +1,122 @@
INIT
WANTENCODING
!Low
ENCIN "123"
encout 0x31,0x32,0x33
# We want to prove the UTF-8 parser correctly handles all the sequences.
# Easy way to do this is to check it does low/high boundary cases, as that
# leaves only two for each sequence length
#
# These ranges are therefore:
#
# Two bytes:
# U+0080 = 000 10000000 => 00010 000000
# => 11000010 10000000 = C2 80
# U+07FF = 111 11111111 => 11111 111111
# => 11011111 10111111 = DF BF
#
# Three bytes:
# U+0800 = 00001000 00000000 => 0000 100000 000000
# => 11100000 10100000 10000000 = E0 A0 80
# U+FFFD = 11111111 11111101 => 1111 111111 111101
# => 11101111 10111111 10111101 = EF BF BD
# (We avoid U+FFFE and U+FFFF as they're invalid codepoints)
#
# Four bytes:
# U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000
# => 11110000 10010000 10000000 10000000 = F0 90 80 80
# U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111
# => 11110111 10111111 10111111 10111111 = F7 BF BF BF
!2 byte
ENCIN "\xC2\x80\xDF\xBF"
encout 0x0080, 0x07FF
!3 byte
ENCIN "\xE0\xA0\x80\xEF\xBF\xBD"
encout 0x0800,0xFFFD
!4 byte
ENCIN "\xF0\x90\x80\x80\xF7\xBF\xBF\xBF"
encout 0x10000,0x1fffff
# Next up, we check some invalid sequences
# + Early termination (back to low bytes too soon)
# + Early restart (another sequence introduction before the previous one was finished)
!Early termination
ENCIN "\xC2!"
encout 0xfffd,0x21
ENCIN "\xE0!\xE0\xA0!"
encout 0xfffd,0x21,0xfffd,0x21
ENCIN "\xF0!\xF0\x90!\xF0\x90\x80!"
encout 0xfffd,0x21,0xfffd,0x21,0xfffd,0x21
!Early restart
ENCIN "\xC2\xC2\x90"
encout 0xfffd,0x0090
ENCIN "\xE0\xC2\x90\xE0\xA0\xC2\x90"
encout 0xfffd,0x0090,0xfffd,0x0090
ENCIN "\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90"
encout 0xfffd,0x0090,0xfffd,0x0090,0xfffd,0x0090
# Test the overlong sequences by giving an overlong encoding of U+0000 and
# an encoding of the highest codepoint still too short
#
# Two bytes:
# U+0000 = C0 80
# U+007F = 000 01111111 => 00001 111111 =>
# => 11000001 10111111 => C1 BF
#
# Three bytes:
# U+0000 = E0 80 80
# U+07FF = 00000111 11111111 => 0000 011111 111111
# => 11100000 10011111 10111111 = E0 9F BF
#
# Four bytes:
# U+0000 = F0 80 80 80
# U+FFFF = 11111111 11111111 => 000 001111 111111 111111
# => 11110000 10001111 10111111 10111111 = F0 8F BF BF
!Overlong
ENCIN "\xC0\x80\xC1\xBF"
encout 0xfffd,0xfffd
ENCIN "\xE0\x80\x80\xE0\x9F\xBF"
encout 0xfffd,0xfffd
ENCIN "\xF0\x80\x80\x80\xF0\x8F\xBF\xBF"
encout 0xfffd,0xfffd
# UTF-16 surrogates U+D800 and U+DFFF
!UTF-16 Surrogates
ENCIN "\xED\xA0\x80\xED\xBF\xBF"
encout 0xfffd,0xfffd
!Split write
ENCIN "\xC2"
ENCIN "\xA0"
encout 0x000A0
ENCIN "\xE0"
ENCIN "\xA0\x80"
encout 0x00800
ENCIN "\xE0\xA0"
ENCIN "\x80"
encout 0x00800
ENCIN "\xF0"
ENCIN "\x90\x80\x80"
encout 0x10000
ENCIN "\xF0\x90"
ENCIN "\x80\x80"
encout 0x10000
ENCIN "\xF0\x90\x80"
ENCIN "\x80"
encout 0x10000

View File

@@ -0,0 +1,55 @@
INIT
UTF8 1
WANTSTATE g
!Low
RESET
PUSH "ABC"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1
putglyph 0x43 1 0,2
!UTF-8 1 char
# U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE
# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE
RESET
PUSH "\xC3\x81\xC3\xA9"
putglyph 0xc1 1 0,0
putglyph 0xe9 1 0,1
!UTF-8 wide char
# U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO
RESET
PUSH "\xEF\xBC\x90 "
putglyph 0xff10 2 0,0
putglyph 0x20 1 0,2
!UTF-8 combining chars
# U+0301 = 0xCC 0x81 name: COMBINING ACUTE
RESET
PUSH "e\xCC\x81Z"
putglyph 0x65,0x301 1 0,0
putglyph 0x5a 1 0,1
!Combining across buffers
RESET
PUSH "e"
putglyph 0x65 1 0,0
PUSH "\xCC\x81Z"
putglyph 0x65,0x301 1 0,0
putglyph 0x5a 1 0,1
RESET
PUSH "e"
putglyph 0x65 1 0,0
PUSH "\xCC\x81"
putglyph 0x65,0x301 1 0,0
PUSH "\xCC\x82"
putglyph 0x65,0x301,0x302 1 0,0
!DECSCA protected
RESET
PUSH "A\e[1\"qB\e[2\"qC"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1 prot
putglyph 0x43 1 0,2

View File

@@ -0,0 +1,224 @@
INIT
UTF8 1
WANTSTATE
!Implicit
PUSH "ABC"
?cursor = 0,3
!Backspace
PUSH "\b"
?cursor = 0,2
!Horizontal Tab
PUSH "\t"
?cursor = 0,8
!Carriage Return
PUSH "\r"
?cursor = 0,0
!Linefeed
PUSH "\n"
?cursor = 1,0
!Backspace bounded by lefthand edge
PUSH "\e[4;2H"
?cursor = 3,1
PUSH "\b"
?cursor = 3,0
PUSH "\b"
?cursor = 3,0
!Backspace cancels phantom
PUSH "\e[4;80H"
?cursor = 3,79
PUSH "X"
?cursor = 3,79
PUSH "\b"
?cursor = 3,78
!HT bounded by righthand edge
PUSH "\e[1;78H"
?cursor = 0,77
PUSH "\t"
?cursor = 0,79
PUSH "\t"
?cursor = 0,79
RESET
!Index
PUSH "ABC\eD"
?cursor = 1,3
!Reverse Index
PUSH "\eM"
?cursor = 0,3
!Newline
PUSH "\eE"
?cursor = 1,0
RESET
!Cursor Forward
PUSH "\e[B"
?cursor = 1,0
PUSH "\e[3B"
?cursor = 4,0
PUSH "\e[0B"
?cursor = 5,0
!Cursor Down
PUSH "\e[C"
?cursor = 5,1
PUSH "\e[3C"
?cursor = 5,4
PUSH "\e[0C"
?cursor = 5,5
!Cursor Up
PUSH "\e[A"
?cursor = 4,5
PUSH "\e[3A"
?cursor = 1,5
PUSH "\e[0A"
?cursor = 0,5
!Cursor Backward
PUSH "\e[D"
?cursor = 0,4
PUSH "\e[3D"
?cursor = 0,1
PUSH "\e[0D"
?cursor = 0,0
!Cursor Next Line
PUSH " "
?cursor = 0,3
PUSH "\e[E"
?cursor = 1,0
PUSH " "
?cursor = 1,3
PUSH "\e[2E"
?cursor = 3,0
PUSH "\e[0E"
?cursor = 4,0
!Cursor Previous Line
PUSH " "
?cursor = 4,3
PUSH "\e[F"
?cursor = 3,0
PUSH " "
?cursor = 3,3
PUSH "\e[2F"
?cursor = 1,0
PUSH "\e[0F"
?cursor = 0,0
!Cursor Horizonal Absolute
PUSH "\n"
?cursor = 1,0
PUSH "\e[20G"
?cursor = 1,19
PUSH "\e[G"
?cursor = 1,0
!Cursor Position
PUSH "\e[10;5H"
?cursor = 9,4
PUSH "\e[8H"
?cursor = 7,0
PUSH "\e[H"
?cursor = 0,0
!Cursor Position cancels phantom
PUSH "\e[10;78H"
?cursor = 9,77
PUSH "ABC"
?cursor = 9,79
PUSH "\e[10;80H"
PUSH "C"
?cursor = 9,79
PUSH "X"
?cursor = 10,1
RESET
!Bounds Checking
PUSH "\e[A"
?cursor = 0,0
PUSH "\e[D"
?cursor = 0,0
PUSH "\e[25;80H"
?cursor = 24,79
PUSH "\e[B"
?cursor = 24,79
PUSH "\e[C"
?cursor = 24,79
PUSH "\e[E"
?cursor = 24,0
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[F"
?cursor = 0,0
PUSH "\e[999G"
?cursor = 0,79
PUSH "\e[99;99H"
?cursor = 24,79
RESET
!Horizontal Position Absolute
PUSH "\e[5`"
?cursor = 0,4
!Horizontal Position Relative
PUSH "\e[3a"
?cursor = 0,7
!Horizontal Position Backward
PUSH "\e[3j"
?cursor = 0,4
!Horizontal and Vertical Position
PUSH "\e[3;3f"
?cursor = 2,2
!Vertical Position Absolute
PUSH "\e[5d"
?cursor = 4,2
!Vertical Position Relative
PUSH "\e[2e"
?cursor = 6,2
!Vertical Position Backward
PUSH "\e[2k"
?cursor = 4,2
RESET
!Horizontal Tab
PUSH "\t"
?cursor = 0,8
PUSH " "
?cursor = 0,11
PUSH "\t"
?cursor = 0,16
PUSH " "
?cursor = 0,23
PUSH "\t"
?cursor = 0,24
PUSH " "
?cursor = 0,32
PUSH "\t"
?cursor = 0,40
!Cursor Horizontal Tab
PUSH "\e[I"
?cursor = 0,48
PUSH "\e[2I"
?cursor = 0,64
!Cursor Backward Tab
PUSH "\e[Z"
?cursor = 0,56
PUSH "\e[2Z"
?cursor = 0,40

View File

@@ -0,0 +1,150 @@
INIT
UTF8 1
WANTSTATE s
!Linefeed
PUSH "\n"x24
?cursor = 24,0
PUSH "\n"
scrollrect 0..25,0..80 => +1,+0
?cursor = 24,0
RESET
!Index
PUSH "\e[25H"
PUSH "\eD"
scrollrect 0..25,0..80 => +1,+0
RESET
!Reverse Index
PUSH "\eM"
scrollrect 0..25,0..80 => -1,+0
RESET
!Linefeed in DECSTBM
PUSH "\e[1;10r"
?cursor = 0,0
PUSH "\n"x9
?cursor = 9,0
PUSH "\n"
scrollrect 0..10,0..80 => +1,+0
?cursor = 9,0
!Linefeed outside DECSTBM
PUSH "\e[20H"
?cursor = 19,0
PUSH "\n"
?cursor = 20,0
!Index in DECSTBM
PUSH "\e[10H"
PUSH "\e[9;10r"
PUSH "\eM"
?cursor = 8,0
PUSH "\eM"
scrollrect 8..10,0..80 => -1,+0
!Reverse Index in DECSTBM
PUSH "\e[25H"
?cursor = 24,0
PUSH "\n"
# no scrollrect
?cursor = 24,0
!Linefeed in DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[3;10r\e[10;40s"
PUSH "\e[10;10H\n"
scrollrect 2..10,9..40 => +1,+0
!IND/RI in DECSTBM+DECSLRM
PUSH "\eD"
scrollrect 2..10,9..40 => +1,+0
PUSH "\e[3;10H\eM"
scrollrect 2..10,9..40 => -1,+0
!DECRQSS on DECSTBM
PUSH "\eP\$qr\e\\"
output "\eP1\$r3;10r\e\\"
!DECRQSS on DECSLRM
PUSH "\eP\$qs\e\\"
output "\eP1\$r10;40s\e\\"
!Setting invalid DECSLRM with !DECVSSM is still rejected
PUSH "\e[?69l\e[;0s\e[?69h"
RESET
!Scroll Down
PUSH "\e[S"
scrollrect 0..25,0..80 => +1,+0
?cursor = 0,0
PUSH "\e[2S"
scrollrect 0..25,0..80 => +2,+0
?cursor = 0,0
PUSH "\e[100S"
scrollrect 0..25,0..80 => +25,+0
!Scroll Up
PUSH "\e[T"
scrollrect 0..25,0..80 => -1,+0
?cursor = 0,0
PUSH "\e[2T"
scrollrect 0..25,0..80 => -2,+0
?cursor = 0,0
PUSH "\e[100T"
scrollrect 0..25,0..80 => -25,+0
!SD/SU in DECSTBM
PUSH "\e[5;20r"
PUSH "\e[S"
scrollrect 4..20,0..80 => +1,+0
PUSH "\e[T"
scrollrect 4..20,0..80 => -1,+0
RESET
!SD/SU in DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[3;10r\e[10;40s"
?cursor = 0,0
PUSH "\e[3;10H"
?cursor = 2,9
PUSH "\e[S"
scrollrect 2..10,9..40 => +1,+0
PUSH "\e[?69l"
PUSH "\e[S"
scrollrect 2..10,0..80 => +1,+0
!Invalid boundaries
RESET
PUSH "\e[100;105r\eD"
PUSH "\e[5;2r\eD"
RESET
WANTSTATE -s+me
!Scroll Down move+erase emulation
PUSH "\e[S"
moverect 1..25,0..80 -> 0..24,0..80
erase 24..25,0..80
?cursor = 0,0
PUSH "\e[2S"
moverect 2..25,0..80 -> 0..23,0..80
erase 23..25,0..80
?cursor = 0,0
!Scroll Up move+erase emulation
PUSH "\e[T"
moverect 0..24,0..80 -> 1..25,0..80
erase 0..1,0..80
?cursor = 0,0
PUSH "\e[2T"
moverect 0..23,0..80 -> 2..25,0..80
erase 0..2,0..80
?cursor = 0,0

View File

@@ -0,0 +1,300 @@
INIT
UTF8 1
WANTSTATE se
!ICH
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ACD"
PUSH "\e[2D"
?cursor = 0,1
PUSH "\e[@"
scrollrect 0..1,1..80 => +0,-1
?cursor = 0,1
PUSH "B"
?cursor = 0,2
PUSH "\e[3@"
scrollrect 0..1,2..80 => +0,-3
!ICH with DECSLRM
PUSH "\e[?69h"
PUSH "\e[;50s"
PUSH "\e[20G\e[@"
scrollrect 0..1,19..50 => +0,-1
!ICH outside DECSLRM
PUSH "\e[70G\e[@"
# nothing happens
!DCH
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABBC"
PUSH "\e[3D"
?cursor = 0,1
PUSH "\e[P"
scrollrect 0..1,1..80 => +0,+1
?cursor = 0,1
PUSH "\e[3P"
scrollrect 0..1,1..80 => +0,+3
?cursor = 0,1
!DCH with DECSLRM
PUSH "\e[?69h"
PUSH "\e[;50s"
PUSH "\e[20G\e[P"
scrollrect 0..1,19..50 => +0,+1
!DCH outside DECSLRM
PUSH "\e[70G\e[P"
# nothing happens
!ECH
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABC"
PUSH "\e[2D"
?cursor = 0,1
PUSH "\e[X"
erase 0..1,1..2
?cursor = 0,1
PUSH "\e[3X"
erase 0..1,1..4
?cursor = 0,1
# ECH more columns than there are should be bounded
PUSH "\e[100X"
erase 0..1,1..80
!IL
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "A\r\nC"
?cursor = 1,1
PUSH "\e[L"
scrollrect 1..25,0..80 => -1,+0
# TODO: ECMA-48 says we should move to line home, but neither xterm nor
# xfce4-terminal do this
?cursor = 1,1
PUSH "\rB"
?cursor = 1,1
PUSH "\e[3L"
scrollrect 1..25,0..80 => -3,+0
!IL with DECSTBM
PUSH "\e[5;15r"
PUSH "\e[5H\e[L"
scrollrect 4..15,0..80 => -1,+0
!IL outside DECSTBM
PUSH "\e[20H\e[L"
# nothing happens
!IL with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[10;50s"
PUSH "\e[5;10H\e[L"
scrollrect 4..15,9..50 => -1,+0
!DL
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "A\r\nB\r\nB\r\nC"
?cursor = 3,1
PUSH "\e[2H"
?cursor = 1,0
PUSH "\e[M"
scrollrect 1..25,0..80 => +1,+0
?cursor = 1,0
PUSH "\e[3M"
scrollrect 1..25,0..80 => +3,+0
?cursor = 1,0
!DL with DECSTBM
PUSH "\e[5;15r"
PUSH "\e[5H\e[M"
scrollrect 4..15,0..80 => +1,+0
!DL outside DECSTBM
PUSH "\e[20H\e[M"
# nothing happens
!DL with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[10;50s"
PUSH "\e[5;10H\e[M"
scrollrect 4..15,9..50 => +1,+0
!DECIC
RESET
erase 0..25,0..80
PUSH "\e[20G\e[5'}"
scrollrect 0..25,19..80 => +0,-5
!DECIC with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[4;20r\e[20;60s"
PUSH "\e[4;20H\e[3'}"
scrollrect 3..20,19..60 => +0,-3
!DECIC outside DECSLRM
PUSH "\e[70G\e['}"
# nothing happens
!DECDC
RESET
erase 0..25,0..80
PUSH "\e[20G\e[5'~"
scrollrect 0..25,19..80 => +0,+5
!DECDC with DECSTBM+DECSLRM
PUSH "\e[?69h"
PUSH "\e[4;20r\e[20;60s"
PUSH "\e[4;20H\e[3'~"
scrollrect 3..20,19..60 => +0,+3
!DECDC outside DECSLRM
PUSH "\e[70G\e['~"
# nothing happens
!EL 0
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABCDE"
PUSH "\e[3D"
?cursor = 0,2
PUSH "\e[0K"
erase 0..1,2..80
?cursor = 0,2
!EL 1
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABCDE"
PUSH "\e[3D"
?cursor = 0,2
PUSH "\e[1K"
erase 0..1,0..3
?cursor = 0,2
!EL 2
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABCDE"
PUSH "\e[3D"
?cursor = 0,2
PUSH "\e[2K"
erase 0..1,0..80
?cursor = 0,2
!SEL
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[11G"
?cursor = 0,10
PUSH "\e[?0K"
erase 0..1,10..80 selective
?cursor = 0,10
PUSH "\e[?1K"
erase 0..1,0..11 selective
?cursor = 0,10
PUSH "\e[?2K"
erase 0..1,0..80 selective
?cursor = 0,10
!ED 0
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[0J"
erase 1..2,1..80
erase 2..25,0..80
?cursor = 1,1
!ED 1
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[1J"
erase 0..1,0..80
erase 1..2,0..2
?cursor = 1,1
!ED 2
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[2J"
erase 0..25,0..80
?cursor = 1,1
!SED
RESET
erase 0..25,0..80
PUSH "\e[5;5H"
?cursor = 4,4
PUSH "\e[?0J"
erase 4..5,4..80 selective
erase 5..25,0..80 selective
?cursor = 4,4
PUSH "\e[?1J"
erase 0..4,0..80 selective
erase 4..5,0..5 selective
?cursor = 4,4
PUSH "\e[?2J"
erase 0..25,0..80 selective
?cursor = 4,4
!DECRQSS on DECSCA
PUSH "\e[2\"q"
PUSH "\eP\$q\"q\e\\"
output "\eP1\$r2\"q\e\\"
WANTSTATE -s+m
!ICH move+erase emuation
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ACD"
PUSH "\e[2D"
?cursor = 0,1
PUSH "\e[@"
moverect 0..1,1..79 -> 0..1,2..80
erase 0..1,1..2
?cursor = 0,1
PUSH "B"
?cursor = 0,2
PUSH "\e[3@"
moverect 0..1,2..77 -> 0..1,5..80
erase 0..1,2..5
!DCH move+erase emulation
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "ABBC"
PUSH "\e[3D"
?cursor = 0,1
PUSH "\e[P"
moverect 0..1,2..80 -> 0..1,1..79
erase 0..1,79..80
?cursor = 0,1
PUSH "\e[3P"
moverect 0..1,4..80 -> 0..1,1..77
erase 0..1,77..80
?cursor = 0,1

View File

@@ -0,0 +1,105 @@
INIT
WANTSTATE g
!Default
RESET
PUSH "#"
putglyph 0x23 1 0,0
!Designate G0=UK
RESET
PUSH "\e(A"
PUSH "#"
putglyph 0x00a3 1 0,0
!Designate G0=DEC drawing
RESET
PUSH "\e(0"
PUSH "a"
putglyph 0x2592 1 0,0
!Designate G1 + LS1
RESET
PUSH "\e)0"
PUSH "a"
putglyph 0x61 1 0,0
PUSH "\x0e"
PUSH "a"
putglyph 0x2592 1 0,1
!LS0
PUSH "\x0f"
PUSH "a"
putglyph 0x61 1 0,2
!Designate G2 + LS2
PUSH "\e*0"
PUSH "a"
putglyph 0x61 1 0,3
PUSH "\en"
PUSH "a"
putglyph 0x2592 1 0,4
PUSH "\x0f"
PUSH "a"
putglyph 0x61 1 0,5
!Designate G3 + LS3
PUSH "\e+0"
PUSH "a"
putglyph 0x61 1 0,6
PUSH "\eo"
PUSH "a"
putglyph 0x2592 1 0,7
PUSH "\x0f"
PUSH "a"
putglyph 0x61 1 0,8
!SS2
PUSH "a\x{8e}aa"
putglyph 0x61 1 0,9
putglyph 0x2592 1 0,10
putglyph 0x61 1 0,11
!SS3
PUSH "a\x{8f}aa"
putglyph 0x61 1 0,12
putglyph 0x2592 1 0,13
putglyph 0x61 1 0,14
!LS1R
RESET
PUSH "\e~"
PUSH "\xe1"
putglyph 0x61 1 0,0
PUSH "\e)0"
PUSH "\xe1"
putglyph 0x2592 1 0,1
!LS2R
RESET
PUSH "\e}"
PUSH "\xe1"
putglyph 0x61 1 0,0
PUSH "\e*0"
PUSH "\xe1"
putglyph 0x2592 1 0,1
!LS3R
RESET
PUSH "\e|"
PUSH "\xe1"
putglyph 0x61 1 0,0
PUSH "\e+0"
PUSH "\xe1"
putglyph 0x2592 1 0,1
UTF8 1
!Mixed US-ASCII and UTF-8
# U+0108 == 0xc4 0x88
RESET
PUSH "\e(B"
PUSH "AB\xc4\x88D"
putglyph 0x0041 1 0,0
putglyph 0x0042 1 0,1
putglyph 0x0108 1 0,2
putglyph 0x0044 1 0,3

View File

@@ -0,0 +1,86 @@
INIT
UTF8 1
WANTSTATE gme
!Insert/Replace Mode
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "AC\e[DB"
putglyph 0x41 1 0,0
putglyph 0x43 1 0,1
putglyph 0x42 1 0,1
PUSH "\e[4h"
PUSH "\e[G"
PUSH "AC\e[DB"
moverect 0..1,0..79 -> 0..1,1..80
erase 0..1,0..1
putglyph 0x41 1 0,0
moverect 0..1,1..79 -> 0..1,2..80
erase 0..1,1..2
putglyph 0x43 1 0,1
moverect 0..1,1..79 -> 0..1,2..80
erase 0..1,1..2
putglyph 0x42 1 0,1
!Insert mode only happens once for UTF-8 combining
PUSH "e"
moverect 0..1,2..79 -> 0..1,3..80
erase 0..1,2..3
putglyph 0x65 1 0,2
PUSH "\xCC\x81"
putglyph 0x65,0x301 1 0,2
!Newline/Linefeed mode
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[5G\n"
?cursor = 1,4
PUSH "\e[20h"
PUSH "\e[5G\n"
?cursor = 2,0
!DEC origin mode
RESET
erase 0..25,0..80
?cursor = 0,0
PUSH "\e[5;15r"
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[3;3H"
?cursor = 2,2
PUSH "\e[?6h"
PUSH "\e[H"
?cursor = 4,0
PUSH "\e[3;3H"
?cursor = 6,2
!DECRQM on DECOM
PUSH "\e[?6h"
PUSH "\e[?6\$p"
output "\e[?6;1\$y"
PUSH "\e[?6l"
PUSH "\e[?6\$p"
output "\e[?6;2\$y"
!Origin mode with DECSLRM
PUSH "\e[?6h"
PUSH "\e[?69h"
PUSH "\e[20;60s"
PUSH "\e[H"
?cursor = 4,19
PUSH "\e[?69l"
!Origin mode bounds cursor to scrolling region
PUSH "\e[H"
PUSH "\e[10A"
?cursor = 4,0
PUSH "\e[20B"
?cursor = 14,0
!Origin mode without scroll region
PUSH "\e[?6l"
PUSH "\e[r\e[?6h"
?cursor = 0,0

View File

@@ -0,0 +1,48 @@
INIT
WANTSTATE g
!Placement
RESET
PUSH "AB\e[79GCDE"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1
putglyph 0x43 1 0,78
putglyph 0x44 1 0,79
putglyph 0x45 1 1,0
!Resize
RESET
RESIZE 27,85
PUSH "AB\e[79GCDE"
putglyph 0x41 1 0,0
putglyph 0x42 1 0,1
putglyph 0x43 1 0,78
putglyph 0x44 1 0,79
putglyph 0x45 1 0,80
?cursor = 0,81
!Resize without reset
RESIZE 28,90
?cursor = 0,81
PUSH "FGHI"
putglyph 0x46 1 0,81
putglyph 0x47 1 0,82
putglyph 0x48 1 0,83
putglyph 0x49 1 0,84
?cursor = 0,85
!Resize shrink moves cursor
RESIZE 25,80
?cursor = 0,79
!Resize grow doesn't cancel phantom
RESET
PUSH "\e[79GAB"
putglyph 0x41 1 0,78
putglyph 0x42 1 0,79
?cursor = 0,79
RESIZE 30,100
?cursor = 0,80
PUSH "C"
putglyph 0x43 1 0,80
?cursor = 0,81

View File

@@ -0,0 +1,172 @@
INIT
WANTSTATE p
!DECRQM on with mouse off
PUSH "\e[?1000\$p"
output "\e[?1000;2\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;2\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;2\$y"
!Mouse in simple button report mode
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
PUSH "\e[?1000h"
settermprop 8 1
!Press 1
MOUSEMOVE 0,0 0
MOUSEBTN d 1 0
output "\e[M\x20\x21\x21"
!Release 1
MOUSEBTN u 1 0
output "\e[M\x23\x21\x21"
!Ctrl-Press 1
MOUSEBTN d 1 C
output "\e[M\x30\x21\x21"
MOUSEBTN u 1 C
output "\e[M\x33\x21\x21"
!Button 2
MOUSEBTN d 2 0
output "\e[M\x21\x21\x21"
MOUSEBTN u 2 0
output "\e[M\x23\x21\x21"
!Position
MOUSEMOVE 10,20 0
MOUSEBTN d 1 0
output "\e[M\x20\x35\x2b"
MOUSEBTN u 1 0
output "\e[M\x23\x35\x2b"
MOUSEMOVE 10,21 0
# no output
!Wheel events
MOUSEBTN d 4 0
output "\e[M\x60\x36\x2b"
MOUSEBTN d 4 0
output "\e[M\x60\x36\x2b"
MOUSEBTN d 5 0
output "\e[M\x61\x36\x2b"
!DECRQM on mouse button mode
PUSH "\e[?1000\$p"
output "\e[?1000;1\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;2\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;2\$y"
!Drag events
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
PUSH "\e[?1002h"
settermprop 8 2
MOUSEMOVE 5,5 0
MOUSEBTN d 1 0
output "\e[M\x20\x26\x26"
MOUSEMOVE 5,6 0
output "\e[M\x40\x27\x26"
MOUSEMOVE 6,6 0
output "\e[M\x40\x27\x27"
MOUSEMOVE 6,6 0
# no output
MOUSEBTN u 1 0
output "\e[M\x23\x27\x27"
MOUSEMOVE 6,7
# no output
!DECRQM on mouse drag mode
PUSH "\e[?1000\$p"
output "\e[?1000;2\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;1\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;2\$y"
!Non-drag motion events
PUSH "\e[?1003h"
settermprop 8 3
MOUSEMOVE 6,8 0
output "\e[M\x43\x29\x27"
!DECRQM on mouse motion mode
PUSH "\e[?1000\$p"
output "\e[?1000;2\$y"
PUSH "\e[?1002\$p"
output "\e[?1002;2\$y"
PUSH "\e[?1003\$p"
output "\e[?1003;1\$y"
!Bounds checking
MOUSEMOVE 300,300 0
output "\e[M\x43\xff\xff"
MOUSEBTN d 1 0
output "\e[M\x20\xff\xff"
MOUSEBTN u 1 0
output "\e[M\x23\xff\xff"
!DECRQM on standard encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;2\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;2\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;2\$y"
!UTF-8 extended encoding mode
# 300 + 32 + 1 = 333 = U+014d = \xc5\x8d
PUSH "\e[?1005h"
MOUSEBTN d 1 0
output "\e[M\x20\xc5\x8d\xc5\x8d"
MOUSEBTN u 1 0
output "\e[M\x23\xc5\x8d\xc5\x8d"
!DECRQM on UTF-8 extended encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;1\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;2\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;2\$y"
!SGR extended encoding mode
PUSH "\e[?1006h"
MOUSEBTN d 1 0
output "\e[<0;301;301M"
MOUSEBTN u 1 0
output "\e[<0;301;301m"
!DECRQM on SGR extended encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;2\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;1\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;2\$y"
!rxvt extended encoding mode
PUSH "\e[?1015h"
MOUSEBTN d 1 0
output "\e[0;301;301M"
MOUSEBTN u 1 0
output "\e[3;301;301M"
!DECRQM on rxvt extended encoding mode
PUSH "\e[?1005\$p"
output "\e[?1005;2\$y"
PUSH "\e[?1006\$p"
output "\e[?1006;2\$y"
PUSH "\e[?1015\$p"
output "\e[?1015;1\$y"

View File

@@ -0,0 +1,36 @@
INIT
WANTSTATE p
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
!Cursor visibility
PUSH "\e[?25h"
settermprop 1 true
PUSH "\e[?25\$p"
output "\e[?25;1\$y"
PUSH "\e[?25l"
settermprop 1 false
PUSH "\e[?25\$p"
output "\e[?25;2\$y"
!Cursor blink
PUSH "\e[?12h"
settermprop 2 true
PUSH "\e[?12\$p"
output "\e[?12;1\$y"
PUSH "\e[?12l"
settermprop 2 false
PUSH "\e[?12\$p"
output "\e[?12;2\$y"
!Cursor shape
PUSH "\e[3 q"
settermprop 2 true
settermprop 7 2
!Title
PUSH "\e]2;Here is my title\a"
settermprop 4 "Here is my title"

View File

@@ -0,0 +1,69 @@
INIT
UTF8 1
WANTSTATE gm
!79th Column
PUSH "\e[75G"
PUSH "A"x5
putglyph 0x41 1 0,74
putglyph 0x41 1 0,75
putglyph 0x41 1 0,76
putglyph 0x41 1 0,77
putglyph 0x41 1 0,78
?cursor = 0,79
!80th Column Phantom
PUSH "A"
putglyph 0x41 1 0,79
?cursor = 0,79
!Line Wraparound
PUSH "B"
putglyph 0x42 1 1,0
?cursor = 1,1
!Line Wraparound during combined write
PUSH "\e[78G"
PUSH "BBBCC"
putglyph 0x42 1 1,77
putglyph 0x42 1 1,78
putglyph 0x42 1 1,79
putglyph 0x43 1 2,0
putglyph 0x43 1 2,1
?cursor = 2,2
!DEC Auto Wrap Mode
RESET
PUSH "\e[?7l"
PUSH "\e[75G"
PUSH "D"x6
putglyph 0x44 1 0,74
putglyph 0x44 1 0,75
putglyph 0x44 1 0,76
putglyph 0x44 1 0,77
putglyph 0x44 1 0,78
putglyph 0x44 1 0,79
?cursor = 0,79
PUSH "D"
putglyph 0x44 1 0,79
?cursor = 0,79
PUSH "\e[?7h"
!80th column causes linefeed on wraparound
PUSH "\e[25;78HABC"
putglyph 0x41 1 24,77
putglyph 0x42 1 24,78
putglyph 0x43 1 24,79
?cursor = 24,79
PUSH "D"
moverect 1..25,0..80 -> 0..24,0..80
putglyph 0x44 1 24,0
!80th column phantom linefeed phantom cancelled by explicit cursor move
PUSH "\e[25;78HABC"
putglyph 0x41 1 24,77
putglyph 0x42 1 24,78
putglyph 0x43 1 24,79
?cursor = 24,79
PUSH "\e[25;1HD"
putglyph 0x44 1 24,0

View File

@@ -0,0 +1,60 @@
INIT
WANTSTATE g
!Initial
RESET
PUSH "\tX"
putglyph 0x58 1 0,8
PUSH "\tX"
putglyph 0x58 1 0,16
?cursor = 0,17
!HTS
PUSH "\e[5G\eH"
PUSH "\e[G\tX"
putglyph 0x58 1 0,4
?cursor = 0,5
!TBC 0
PUSH "\e[9G\e[g"
PUSH "\e[G\tX\tX"
putglyph 0x58 1 0,4
putglyph 0x58 1 0,16
?cursor = 0,17
!TBC 3
PUSH "\e[3g\e[50G\eH\e[G"
?cursor = 0,0
PUSH "\tX"
putglyph 0x58 1 0,49
?cursor = 0,50
!Tabstops after resize
RESET
RESIZE 30,100
# Should be 100/8 = 12 tabstops
PUSH "\tX"
putglyph 0x58 1 0,8
PUSH "\tX"
putglyph 0x58 1 0,16
PUSH "\tX"
putglyph 0x58 1 0,24
PUSH "\tX"
putglyph 0x58 1 0,32
PUSH "\tX"
putglyph 0x58 1 0,40
PUSH "\tX"
putglyph 0x58 1 0,48
PUSH "\tX"
putglyph 0x58 1 0,56
PUSH "\tX"
putglyph 0x58 1 0,64
PUSH "\tX"
putglyph 0x58 1 0,72
PUSH "\tX"
putglyph 0x58 1 0,80
PUSH "\tX"
putglyph 0x58 1 0,88
PUSH "\tX"
putglyph 0x58 1 0,96
?cursor = 0,97

View File

@@ -0,0 +1,64 @@
INIT
WANTSTATE p
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
!Set up state
PUSH "\e[2;2H"
?cursor = 1,1
PUSH "\e[1m"
?pen bold = on
!Save
PUSH "\e[?1048h"
!Change state
PUSH "\e[5;5H"
?cursor = 4,4
PUSH "\e[4 q"
settermprop 2 false
settermprop 7 2
PUSH "\e[22;4m"
?pen bold = off
?pen underline = 1
!Restore
PUSH "\e[?1048l"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 1,1
?pen bold = on
?pen underline = 0
!Save/restore using DECSC/DECRC
PUSH "\e[2;2H\e7"
?cursor = 1,1
PUSH "\e[5;5H"
?cursor = 4,4
PUSH "\e8"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 1,1
!Save twice, restore twice happens on both edge transitions
PUSH "\e[2;10H\e[?1048h\e[6;10H\e[?1048h"
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[?1048l"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 5,9
PUSH "\e[H"
?cursor = 0,0
PUSH "\e[?1048l"
settermprop 1 true
settermprop 2 true
settermprop 7 1
?cursor = 5,9

View File

@@ -0,0 +1,132 @@
INIT
WANTSTATE
!Unmodified ASCII
INCHAR 0 41
output "A"
INCHAR 0 61
output "a"
!Ctrl modifier on ASCII letters
INCHAR C 41
output "\e[65;5u"
INCHAR C 61
output "\x01"
!Alt modifier on ASCII letters
INCHAR A 41
output "\eA"
INCHAR A 61
output "\ea"
!Ctrl-Alt modifier on ASCII letters
INCHAR CA 41
output "\e[65;7u"
INCHAR CA 61
output "\e\x01"
!Special handling of Ctrl-I
INCHAR 0 49
output "I"
INCHAR 0 69
output "i"
INCHAR C 49
output "\e[73;5u"
INCHAR C 69
output "\e[105;5u"
INCHAR A 49
output "\eI"
INCHAR A 69
output "\ei"
INCHAR CA 49
output "\e[73;7u"
INCHAR CA 69
output "\e[105;7u"
!Special handling of Space
INCHAR 0 20
output " "
INCHAR S 20
output "\e[32;2u"
INCHAR C 20
output "\0"
INCHAR SC 20
output "\e[32;6u"
INCHAR A 20
output "\e "
INCHAR SA 20
output "\e[32;4u"
INCHAR CA 20
output "\e\0"
INCHAR SCA 20
output "\e[32;8u"
!Cursor keys in reset (cursor) mode
INKEY 0 Up
output "\e[A"
INKEY S Up
output "\e[1;2A"
INKEY C Up
output "\e[1;5A"
INKEY SC Up
output "\e[1;6A"
INKEY A Up
output "\e[1;3A"
INKEY SA Up
output "\e[1;4A"
INKEY CA Up
output "\e[1;7A"
INKEY SCA Up
output "\e[1;8A"
!Cursor keys in application mode
PUSH "\e[?1h"
# Plain "Up" should be SS3 A now
INKEY 0 Up
output "\eOA"
# Modified keys should still use CSI
INKEY S Up
output "\e[1;2A"
INKEY C Up
output "\e[1;5A"
!Shift-Tab should be different
INKEY 0 Tab
output "\x09"
INKEY S Tab
output "\e[Z"
INKEY C Tab
output "\e[9;5u"
INKEY A Tab
output "\e\x09"
INKEY CA Tab
output "\e[9;7u"
!Enter in linefeed mode
INKEY 0 Enter
output "\x0d"
!Enter in newline mode
PUSH "\e[20h"
INKEY 0 Enter
output "\x0d\x0a"
!Keypad in DECKPNM
INKEY 0 KP0
output "0"
!Keypad in DECKPAM
PUSH "\e="
INKEY 0 KP0
output "\eOp"
!Bracketed paste mode off
PASTE START
PASTE END
!Bracketed paste mode on
PUSH "\e[?2004h"
PASTE START
output "\e[200~"
PASTE END
output "\e[201~"

View File

@@ -0,0 +1,62 @@
INIT
WANTSTATE
!DA
RESET
PUSH "\e[c"
output "\e[?1;2c"
!DSR
RESET
PUSH "\e[5n"
output "\e[0n"
!CPR
PUSH "\e[6n"
output "\e[1;1R"
PUSH "\e[10;10H\e[6n"
output "\e[10;10R"
!DECCPR
PUSH "\e[?6n"
output "\e[?10;10R"
!DECRQSS on DECSCUSR
PUSH "\e[3 q"
PUSH "\eP\$q q\e\\"
output "\eP1\$r3 q\e\\"
!DECRQSS on SGR
PUSH "\e[1;5;7m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r1;5;7m\e\\"
!DECRQSS on SGR ANSI colours
PUSH "\e[0;31;42m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r31;42m\e\\"
!DECRQSS on SGR ANSI hi-bright colours
PUSH "\e[0;93;104m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r93;104m\e\\"
!DECRQSS on SGR 256-palette colours
PUSH "\e[0;38:5:56;48:5:78m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r38:5:56;48:5:78m\e\\"
!DECRQSS on SGR RGB8 colours
PUSH "\e[0;38:2:24:68:112;48:2:13:57:101m"
PUSH "\eP\$qm\e\\"
output "\eP1\$r38:2:24:68:112;48:2:13:57:101m\e\\"
!S8C1T on DSR
PUSH "\e G"
PUSH "\e[5n"
output "\x{9b}0n"
PUSH "\e F"
!Truncation on attempted buffer overflow
PUSH "\e[6n" x 20
output "\e[10;10R" x 7

View File

@@ -0,0 +1,32 @@
INIT
WANTSTATE
RESET
!RIS homes cursor
PUSH "\e[5;5H"
?cursor = 4,4
WANTSTATE +m
PUSH "\ec"
?cursor = 0,0
WANTSTATE -m
!RIS cancels scrolling region
PUSH "\e[5;10r"
WANTSTATE +s
PUSH "\ec\e[25H\n"
scrollrect 0..25,0..80 => +1,+0
WANTSTATE -s
!RIS erases screen
PUSH "ABCDE"
WANTSTATE +e
PUSH "\ec"
erase 0..25,0..80
WANTSTATE -e
!RIS clears tabstops
PUSH "\e[5G\eH\e[G\t"
?cursor = 0,4
PUSH "\ec\t"
?cursor = 0,8

View File

@@ -0,0 +1,61 @@
INIT
WANTSTATE g
!Single Width, Single Height
RESET
PUSH "\e#5"
PUSH "Hello"
putglyph 0x48 1 0,0
putglyph 0x65 1 0,1
putglyph 0x6c 1 0,2
putglyph 0x6c 1 0,3
putglyph 0x6f 1 0,4
!Double Width, Single Height
RESET
PUSH "\e#6"
PUSH "Hello"
putglyph 0x48 1 0,0 dwl
putglyph 0x65 1 0,1 dwl
putglyph 0x6c 1 0,2 dwl
putglyph 0x6c 1 0,3 dwl
putglyph 0x6f 1 0,4 dwl
?cursor = 0,5
PUSH "\e[40GAB"
putglyph 0x41 1 0,39 dwl
putglyph 0x42 1 1,0
?cursor = 1,1
!Double Height
RESET
PUSH "\e#3"
PUSH "Hello"
putglyph 0x48 1 0,0 dwl dhl-top
putglyph 0x65 1 0,1 dwl dhl-top
putglyph 0x6c 1 0,2 dwl dhl-top
putglyph 0x6c 1 0,3 dwl dhl-top
putglyph 0x6f 1 0,4 dwl dhl-top
?cursor = 0,5
PUSH "\r\n\e#4"
PUSH "Hello"
putglyph 0x48 1 1,0 dwl dhl-bottom
putglyph 0x65 1 1,1 dwl dhl-bottom
putglyph 0x6c 1 1,2 dwl dhl-bottom
putglyph 0x6c 1 1,3 dwl dhl-bottom
putglyph 0x6f 1 1,4 dwl dhl-bottom
?cursor = 1,5
!Double Width scrolling
RESET
PUSH "\e[20H\e#6ABC"
putglyph 0x41 1 19,0 dwl
putglyph 0x42 1 19,1 dwl
putglyph 0x43 1 19,2 dwl
PUSH "\e[25H\n"
PUSH "\e[19;4HDE"
putglyph 0x44 1 18,3 dwl
putglyph 0x45 1 18,4 dwl
PUSH "\e[H\eM"
PUSH "\e[20;6HFG"
putglyph 0x46 1 19,5 dwl
putglyph 0x47 1 19,6 dwl

View File

@@ -0,0 +1,19 @@
INIT
WANTSTATE f
RESET
!Unrecognised control
PUSH "\x03"
control 03
!Unrecognised CSI
PUSH "\e[?15;2z"
csi 0x7a L=3f 15,2
!Unrecognised OSC
PUSH "\e]27;Something\e\\"
osc "27;Something"
!Unrecognised DCS
PUSH "\ePz123\e\\"
dcs "z123"

106
src/libvterm/t/30pen.test Normal file
View File

@@ -0,0 +1,106 @@
INIT
UTF8 1
WANTSTATE
!Reset
PUSH "\e[m"
?pen bold = off
?pen underline = 0
?pen italic = off
?pen blink = off
?pen reverse = off
?pen font = 0
?pen foreground = rgb(240,240,240)
?pen background = rgb(0,0,0)
!Bold
PUSH "\e[1m"
?pen bold = on
PUSH "\e[22m"
?pen bold = off
PUSH "\e[1m\e[m"
?pen bold = off
!Underline
PUSH "\e[4m"
?pen underline = 1
PUSH "\e[21m"
?pen underline = 2
PUSH "\e[24m"
?pen underline = 0
PUSH "\e[4m\e[m"
?pen underline = 0
!Italic
PUSH "\e[3m"
?pen italic = on
PUSH "\e[23m"
?pen italic = off
PUSH "\e[3m\e[m"
?pen italic = off
!Blink
PUSH "\e[5m"
?pen blink = on
PUSH "\e[25m"
?pen blink = off
PUSH "\e[5m\e[m"
?pen blink = off
!Reverse
PUSH "\e[7m"
?pen reverse = on
PUSH "\e[27m"
?pen reverse = off
PUSH "\e[7m\e[m"
?pen reverse = off
!Font Selection
PUSH "\e[11m"
?pen font = 1
PUSH "\e[19m"
?pen font = 9
PUSH "\e[10m"
?pen font = 0
PUSH "\e[11m\e[m"
?pen font = 0
!Foreground
PUSH "\e[31m"
?pen foreground = rgb(224,0,0)
PUSH "\e[32m"
?pen foreground = rgb(0,224,0)
PUSH "\e[34m"
?pen foreground = rgb(0,0,224)
PUSH "\e[91m"
?pen foreground = rgb(255,64,64)
PUSH "\e[38:2:10:20:30m"
?pen foreground = rgb(10,20,30)
PUSH "\e[38:5:1m"
?pen foreground = rgb(224,0,0)
PUSH "\e[39m"
?pen foreground = rgb(240,240,240)
!Background
PUSH "\e[41m"
?pen background = rgb(224,0,0)
PUSH "\e[42m"
?pen background = rgb(0,224,0)
PUSH "\e[44m"
?pen background = rgb(0,0,224)
PUSH "\e[101m"
?pen background = rgb(255,64,64)
PUSH "\e[48:2:10:20:30m"
?pen background = rgb(10,20,30)
PUSH "\e[48:5:1m"
?pen background = rgb(224,0,0)
PUSH "\e[49m"
?pen background = rgb(0,0,0)
!Bold+ANSI colour == highbright
PUSH "\e[m\e[1;37m"
?pen bold = on
?pen foreground = rgb(255,255,255)
PUSH "\e[m\e[37;1m"
?pen bold = on
?pen foreground = rgb(255,255,255)

View File

@@ -0,0 +1,69 @@
INIT
WANTSCREEN c
!Get
RESET
PUSH "ABC"
movecursor 0,3
?screen_chars 0,0,1,3 = 0x41,0x42,0x43
?screen_chars 0,0,1,80 = 0x41,0x42,0x43
?screen_text 0,0,1,3 = 0x41,0x42,0x43
?screen_text 0,0,1,80 = 0x41,0x42,0x43
?screen_cell 0,0 = {0x41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
?screen_cell 0,1 = {0x42} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
?screen_cell 0,2 = {0x43} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
?screen_row 0 = "ABC"
?screen_eol 0,0 = 0
?screen_eol 0,2 = 0
?screen_eol 0,3 = 1
PUSH "\e[H"
movecursor 0,0
?screen_chars 0,0,1,80 = 0x41,0x42,0x43
?screen_text 0,0,1,80 = 0x41,0x42,0x43
PUSH "E"
movecursor 0,1
?screen_chars 0,0,1,80 = 0x45,0x42,0x43
?screen_text 0,0,1,80 = 0x45,0x42,0x43
WANTSCREEN -c
!Erase
RESET
PUSH "ABCDE\e[H\e[K"
?screen_chars 0,0,1,80 =
?screen_text 0,0,1,80 =
!Copycell
RESET
PUSH "ABC\e[H\e[@"
PUSH "1"
?screen_chars 0,0,1,80 = 0x31,0x41,0x42,0x43
RESET
PUSH "ABC\e[H\e[P"
?screen_chars 0,0,1,1 = 0x42
?screen_chars 0,1,1,2 = 0x43
?screen_chars 0,0,1,80 = 0x42,0x43
!Space padding
RESET
PUSH "Hello\e[CWorld"
?screen_chars 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64
?screen_text 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64
!Linefeed padding
RESET
PUSH "Hello\r\nWorld"
?screen_chars 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64
?screen_text 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64
!Altscreen
RESET
PUSH "P"
?screen_chars 0,0,1,80 = 0x50
PUSH "\e[?1049h"
?screen_chars 0,0,1,80 =
PUSH "\e[2K\e[HA"
?screen_chars 0,0,1,80 = 0x41
PUSH "\e[?1049l"
?screen_chars 0,0,1,80 = 0x50

View File

@@ -0,0 +1,47 @@
INIT
UTF8 1
WANTSCREEN
!Single width UTF-8
# U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE
# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE
RESET
PUSH "\xC3\x81\xC3\xA9"
?screen_chars 0,0,1,80 = 0xc1,0xe9
?screen_text 0,0,1,80 = 0xc3,0x81,0xc3,0xa9
?screen_cell 0,0 = {0xc1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Wide char
# U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO
RESET
PUSH "0123\e[H"
PUSH "\xEF\xBC\x90"
?screen_chars 0,0,1,80 = 0xff10,0x32,0x33
?screen_text 0,0,1,80 = 0xef,0xbc,0x90,0x32,0x33
?screen_cell 0,0 = {0xff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Combining char
# U+0301 = 0xCC 0x81 name: COMBINING ACUTE
RESET
PUSH "0123\e[H"
PUSH "e\xCC\x81"
?screen_chars 0,0,1,80 = 0x65,0x301,0x31,0x32,0x33
?screen_text 0,0,1,80 = 0x65,0xcc,0x81,0x31,0x32,0x33
?screen_cell 0,0 = {0x65,0x301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!10 combining accents should not crash
RESET
PUSH "e\xCC\x81\xCC\x82\xCC\x83\xCC\x84\xCC\x85\xCC\x86\xCC\x87\xCC\x88\xCC\x89\xCC\x8A"
?screen_cell 0,0 = {0x65,0x301,0x302,0x303,0x304,0x305} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!40 combining accents in two split writes of 20 should not crash
RESET
PUSH "e\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81"
PUSH "\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81\xCC\x81"
?screen_cell 0,0 = {0x65,0x301,0x301,0x301,0x301,0x301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Outputing CJK doublewidth in 80th column should wraparound to next line and not crash"
RESET
PUSH "\e[80G\xEF\xBC\x90"
?screen_cell 0,79 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
?screen_cell 1,0 = {0xff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)

View File

@@ -0,0 +1,155 @@
INIT
WANTSCREEN Db
!Putglyph
RESET
damage 0..25,0..80
PUSH "123"
damage 0..1,0..1 = 0<31>
damage 0..1,1..2 = 0<32>
damage 0..1,2..3 = 0<33>
!Erase
PUSH "\e[H"
PUSH "\e[3X"
damage 0..1,0..3
!Scroll damages entire line in two chunks
PUSH "\e[H\e[5@"
damage 0..1,5..80
damage 0..1,0..5
!Scroll down damages entire screen in two chunks
PUSH "\e[T"
damage 1..25,0..80
damage 0..1,0..80
!Altscreen damages entire area
PUSH "\e[?1049h"
damage 0..25,0..80
PUSH "\e[?1049l"
damage 0..25,0..80
WANTSCREEN m
!Scroll invokes moverect but not damage
PUSH "\e[5@"
moverect 0..1,0..75 -> 0..1,5..80
damage 0..1,0..5
WANTSCREEN -m
!Merge to cells
RESET
damage 0..25,0..80
DAMAGEMERGE CELL
PUSH "A"
damage 0..1,0..1 = 0<41>
PUSH "B"
damage 0..1,1..2 = 0<42>
PUSH "C"
damage 0..1,2..3 = 0<43>
!Merge entire rows
RESET
damage 0..25,0..80
DAMAGEMERGE ROW
PUSH "ABCDE\r\nEFGH"
damage 0..1,0..5 = 0<41 42 43 44 45>
DAMAGEFLUSH
damage 1..2,0..4 = 1<45 46 47 48>
PUSH "\e[3;6r\e[6H\eD"
damage 2..5,0..80
DAMAGEFLUSH
damage 5..6,0..80
!Merge entire screen
RESET
damage 0..25,0..80
DAMAGEMERGE SCREEN
PUSH "ABCDE\r\nEFGH"
DAMAGEFLUSH
damage 0..2,0..5 = 0<41 42 43 44 45> 1<45 46 47 48>
PUSH "\e[3;6r\e[6H\eD"
DAMAGEFLUSH
damage 2..6,0..80
!Merge entire screen with moverect
WANTSCREEN m
RESET
damage 0..25,0..80
DAMAGEMERGE SCREEN
PUSH "ABCDE\r\nEFGH"
PUSH "\e[3;6r\e[6H\eD"
damage 0..2,0..5 = 0<41 42 43 44 45> 1<45 46 47 48>
moverect 3..6,0..80 -> 2..5,0..80
DAMAGEFLUSH
damage 5..6,0..80
!Merge scroll
RESET
damage 0..25,0..80
DAMAGEMERGE SCROLL
PUSH "\e[H1\r\n2\r\n3"
PUSH "\e[25H\n\n\n"
sb_pushline 80 = 31
sb_pushline 80 = 32
sb_pushline 80 = 33
DAMAGEFLUSH
moverect 3..25,0..80 -> 0..22,0..80
damage 0..25,0..80
!Merge scroll with damage
PUSH "\e[25H"
PUSH "ABCDE\r\nEFGH\r\n"
sb_pushline 80 =
sb_pushline 80 =
DAMAGEFLUSH
moverect 2..25,0..80 -> 0..23,0..80
damage 22..25,0..80 = 22<41 42 43 44 45> 23<45 46 47 48>
!Merge scroll with damage past region
PUSH "\e[3;6r\e[6H1\r\n2\r\n3\r\n4\r\n5"
DAMAGEFLUSH
damage 2..6,0..80 = 2<32> 3<33> 4<34> 5<35>
!Damage entirely outside scroll region
PUSH "\e[HABC\e[3;6r\e[6H\r\n6"
damage 0..1,0..3 = 0<41 42 43>
DAMAGEFLUSH
moverect 3..6,0..80 -> 2..5,0..80
damage 5..6,0..80 = 5<36>
!Damage overlapping scroll region
PUSH "\e[H\e[2J"
DAMAGEFLUSH
damage 0..25,0..80
PUSH "\e[HABCD\r\nEFGH\r\nIJKL\e[2;5r\e[5H\r\nMNOP"
DAMAGEFLUSH
moverect 2..5,0..80 -> 1..4,0..80
damage 0..5,0..80 = 0<41 42 43 44> 1<49 4A 4B 4C>
## TODO: is this right?
!Merge scroll*2 with damage
RESET
damage 0..25,0..80
DAMAGEMERGE SCROLL
PUSH "\e[25H\r\nABCDE\b\b\b\e[2P\r\n"
sb_pushline 80 =
moverect 1..25,0..80 -> 0..24,0..80
damage 24..25,0..80 = 24<41 42 43 44 45>
moverect 24..25,4..80 -> 24..25,2..78
damage 24..25,78..80
sb_pushline 80 =
DAMAGEFLUSH
moverect 1..25,0..80 -> 0..24,0..80
damage 24..25,0..80
?screen_chars 23,0,24,5 = 0x41,0x42,0x45

View File

@@ -0,0 +1,90 @@
INIT
WANTSTATE
WANTSCREEN
!Resize wider preserves cells
RESET
RESIZE 25,80
PUSH "AB\r\nCD"
?screen_chars 0,0,1,80 = 0x41,0x42
?screen_chars 1,0,2,80 = 0x43,0x44
RESIZE 25,100
?screen_chars 0,0,1,100 = 0x41,0x42
?screen_chars 1,0,2,100 = 0x43,0x44
!Resize wider allows print in new area
RESET
RESIZE 25,80
PUSH "AB\e[79GCD"
?screen_chars 0,0,1,2 = 0x41,0x42
?screen_chars 0,78,1,80 = 0x43,0x44
RESIZE 25,100
?screen_chars 0,0,1,2 = 0x41,0x42
?screen_chars 0,78,1,80 = 0x43,0x44
PUSH "E"
?screen_chars 0,78,1,81 = 0x43,0x44,0x45
!Resize shorter with blanks just truncates
RESET
RESIZE 25,80
PUSH "Top\e[10HLine 10"
?screen_chars 0,0,1,80 = 0x54,0x6f,0x70
?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30
?cursor = 9,7
RESIZE 20,80
?screen_chars 0,0,1,80 = 0x54,0x6f,0x70
?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30
?cursor = 9,7
!Resize shorter with content must scroll
RESET
RESIZE 25,80
PUSH "Top\e[25HLine 25\e[15H"
?screen_chars 0,0,1,80 = 0x54,0x6f,0x70
?screen_chars 24,0,25,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
?cursor = 14,0
WANTSCREEN b
RESIZE 20,80
sb_pushline 80 = 54 6F 70
sb_pushline 80 =
sb_pushline 80 =
sb_pushline 80 =
sb_pushline 80 =
?screen_chars 0,0,1,80 =
?screen_chars 19,0,20,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
?cursor = 9,0
!Resize shorter does not lose line with cursor
# See also https://github.com/neovim/libvterm/commit/1b745d29d45623aa8d22a7b9288c7b0e331c7088
RESET
WANTSCREEN -b
RESIZE 25,80
WANTSCREEN b
PUSH "\e[24HLine 24\r\nLine 25\r\n"
sb_pushline 80 =
?screen_chars 23,0,24,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
?cursor = 24,0
RESIZE 24,80
sb_pushline 80 =
?screen_chars 22,0,23,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35
?cursor = 23,0
!Resize taller attempts to pop scrollback
RESET
WANTSCREEN -b
RESIZE 25,80
PUSH "Line 1\e[25HBottom\e[15H"
?screen_chars 0,0,1,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31
?screen_chars 24,0,25,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d
?cursor = 14,0
WANTSCREEN b
RESIZE 30,80
sb_popline 80
sb_popline 80
sb_popline 80
sb_popline 80
sb_popline 80
?screen_chars 0,0,1,80 = 0x41,0x42,0x43,0x44,0x45
?screen_chars 5,0,6,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31
?screen_chars 29,0,30,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d
?cursor = 19,0

View File

@@ -0,0 +1,55 @@
INIT
WANTSCREEN
RESET
!Plain
PUSH "A"
?screen_cell 0,0 = {0x41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Bold
PUSH "\e[1mB"
?screen_cell 0,1 = {0x42} width=1 attrs={B} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Italic
PUSH "\e[3mC"
?screen_cell 0,2 = {0x43} width=1 attrs={BI} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Underline
PUSH "\e[4mD"
?screen_cell 0,3 = {0x44} width=1 attrs={BU1I} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Reset
PUSH "\e[mE"
?screen_cell 0,4 = {0x45} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Font
PUSH "\e[11mF\e[m"
?screen_cell 0,5 = {0x46} width=1 attrs={F1} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Foreground
PUSH "\e[31mG\e[m"
?screen_cell 0,6 = {0x47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)
!Background
PUSH "\e[42mH\e[m"
?screen_cell 0,7 = {0x48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0)
!EL sets reverse and colours to end of line
PUSH "\e[H\e[7;33;44m\e[K"
?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
!DECSCNM xors reverse for entire screen
PUSH "\e[?5h"
?screen_cell 0,0 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)
?screen_cell 0,79 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)
?screen_cell 1,0 = {} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0)
PUSH "\e[?5\$p"
output "\e[?5;1\$y"
PUSH "\e[?5l"
?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)
?screen_cell 1,0 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
PUSH "\e[?5\$p"
output "\e[?5;2\$y"

View File

@@ -0,0 +1,16 @@
INIT
WANTSCREEN
!Selective erase
RESET
PUSH "A\e[1\"qB\e[\"qC"
?screen_chars 0,0,1,3 = 0x41,0x42,0x43
PUSH "\e[G\e[?J"
?screen_chars 0,0,1,3 = 0x20,0x42
!Non-selective erase
RESET
PUSH "A\e[1\"qB\e[\"qC"
?screen_chars 0,0,1,3 = 0x41,0x42,0x43
PUSH "\e[G\e[J"
?screen_chars 0,0,1,3 =

View File

@@ -0,0 +1,11 @@
INIT
WANTSCREEN
!Bold extent
RESET
PUSH "AB\e[1mCD\e[mE"
?screen_attrs_extent 0,0 = 0,0-1,1
?screen_attrs_extent 0,1 = 0,0-1,1
?screen_attrs_extent 0,2 = 0,2-1,3
?screen_attrs_extent 0,3 = 0,2-1,3
?screen_attrs_extent 0,4 = 0,4-1,79

View File

@@ -0,0 +1,32 @@
INIT
WANTSCREEN
RESET
!Single Width, Single Height
RESET
PUSH "\e#5"
PUSH "abcde"
?screen_cell 0,0 = {0x61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
!Double Width, Single Height
RESET
PUSH "\e#6"
PUSH "abcde"
?screen_cell 0,0 = {0x61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)
!Double Height
RESET
PUSH "\e#3"
PUSH "abcde"
PUSH "\r\n\e#4"
PUSH "abcde"
?screen_cell 0,0 = {0x61} width=1 attrs={} dwl dhl-top fg=rgb(240,240,240) bg=rgb(0,0,0)
?screen_cell 1,0 = {0x61} width=1 attrs={} dwl dhl-bottom fg=rgb(240,240,240) bg=rgb(0,0,0)
!Late change
RESET
PUSH "abcde"
?screen_cell 0,0 = {0x61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)
PUSH "\e#6"
?screen_cell 0,0 = {0x61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)

View File

@@ -0,0 +1,17 @@
INIT
WANTSCREEN p
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
!Cursor visibility
PUSH "\e[?25h"
settermprop 1 true
PUSH "\e[?25l"
settermprop 1 false
!Title
PUSH "\e]2;Here is my title\a"
settermprop 4 "Here is my title"

View File

@@ -0,0 +1,87 @@
INIT
WANTSTATE
WANTSCREEN
RESET
PUSH "\e#8"
PUSH "\e[9;10H\e[1J"
PUSH "\e[18;60H\e[0J\e[1K"
PUSH "\e[9;71H\e[0K"
$SEQ 10 16: PUSH "\e[\#;10H\e[1K\e[\#;71H\e[0K"
PUSH "\e[17;30H\e[2K"
$SEQ 1 80: PUSH "\e[24;\#f*\e[1;\#f*"
PUSH "\e[2;2H"
$REP 22: PUSH "+\e[1D\eD"
PUSH "\e[23;79H"
$REP 22: PUSH "+\e[1D\eM"
PUSH "\e[2;1H"
$SEQ 2 23: PUSH "*\e[\#;80H*\e[10D\eE"
PUSH "\e[2;10H\e[42D\e[2C"
$REP 76: PUSH "+\e[0C\e[2D\e[1C"
PUSH "\e[23;70H\e[42C\e[2D"
$REP 76: PUSH "+\e[1D\e[1C\e[0D\b"
PUSH "\e[1;1H"
PUSH "\e[10A"
PUSH "\e[1A"
PUSH "\e[0A"
PUSH "\e[24;80H"
PUSH "\e[10B"
PUSH "\e[1B"
PUSH "\e[0B"
PUSH "\e[10;12H"
$REP 58: PUSH " "
PUSH "\e[1B\e[58D"
$REP 58: PUSH " "
PUSH "\e[1B\e[58D"
$REP 58: PUSH " "
PUSH "\e[1B\e[58D"
$REP 58: PUSH " "
PUSH "\e[1B\e[58D"
$REP 58: PUSH " "
PUSH "\e[1B\e[58D"
$REP 58: PUSH " "
PUSH "\e[1B\e[58D"
PUSH "\e[5A\e[1CThe screen should be cleared, and have an unbroken bor-"
PUSH "\e[12;13Hder of *'s and +'s around the edge, and exactly in the"
PUSH "\e[13;13Hmiddle there should be a frame of E's around this text"
PUSH "\e[14;13Hwith one (1) free position around it. Push <RETURN>"
# And the result is...
!Output
?screen_row 0 = "********************************************************************************"
?screen_row 1 = "*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*"
$SEQ 2 7: ?screen_row \# = "*+ +*"
?screen_row 8 = "*+ EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +*"
?screen_row 9 = "*+ E E +*"
?screen_row 10 = "*+ E The screen should be cleared, and have an unbroken bor- E +*"
?screen_row 11 = "*+ E der of *'s and +'s around the edge, and exactly in the E +*"
?screen_row 12 = "*+ E middle there should be a frame of E's around this text E +*"
?screen_row 13 = "*+ E with one (1) free position around it. Push <RETURN> E +*"
?screen_row 14 = "*+ E E +*"
?screen_row 15 = "*+ EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +*"
$SEQ 16 21: ?screen_row \# = "*+ +*"
?screen_row 22 = "*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*"
?screen_row 23 = "********************************************************************************"
?cursor = 13,67

View File

@@ -0,0 +1,40 @@
INIT
WANTSTATE
WANTSCREEN
RESET
PUSH "\e[3;21r"
PUSH "\e[?6h"
PUSH "\e[19;1HA\e[19;80Ha\x0a\e[18;80HaB\e[19;80HB\b b\x0a\e[19;80HC\b\b\t\tc\e[19;2H\bC\x0a\e[19;80H\x0a\e[18;1HD\e[18;80Hd"
PUSH "\e[19;1HE\e[19;80He\x0a\e[18;80HeF\e[19;80HF\b f\x0a\e[19;80HG\b\b\t\tg\e[19;2H\bG\x0a\e[19;80H\x0a\e[18;1HH\e[18;80Hh"
PUSH "\e[19;1HI\e[19;80Hi\x0a\e[18;80HiJ\e[19;80HJ\b j\x0a\e[19;80HK\b\b\t\tk\e[19;2H\bK\x0a\e[19;80H\x0a\e[18;1HL\e[18;80Hl"
PUSH "\e[19;1HM\e[19;80Hm\x0a\e[18;80HmN\e[19;80HN\b n\x0a\e[19;80HO\b\b\t\to\e[19;2H\bO\x0a\e[19;80H\x0a\e[18;1HP\e[18;80Hp"
PUSH "\e[19;1HQ\e[19;80Hq\x0a\e[18;80HqR\e[19;80HR\b r\x0a\e[19;80HS\b\b\t\ts\e[19;2H\bS\x0a\e[19;80H\x0a\e[18;1HT\e[18;80Ht"
PUSH "\e[19;1HU\e[19;80Hu\x0a\e[18;80HuV\e[19;80HV\b v\x0a\e[19;80HW\b\b\t\tw\e[19;2H\bW\x0a\e[19;80H\x0a\e[18;1HX\e[18;80Hx"
PUSH "\e[19;1HY\e[19;80Hy\x0a\e[18;80HyZ\e[19;80HZ\b z\x0a"
!Output
?screen_row 2 = "I i"
?screen_row 3 = "J j"
?screen_row 4 = "K k"
?screen_row 5 = "L l"
?screen_row 6 = "M m"
?screen_row 7 = "N n"
?screen_row 8 = "O o"
?screen_row 9 = "P p"
?screen_row 10 = "Q q"
?screen_row 11 = "R r"
?screen_row 12 = "S s"
?screen_row 13 = "T t"
?screen_row 14 = "U u"
?screen_row 15 = "V v"
?screen_row 16 = "W w"
?screen_row 17 = "X x"
?screen_row 18 = "Y y"
?screen_row 19 = "Z z"
?screen_row 20 = ""
?cursor = 20,79

View File

@@ -0,0 +1,21 @@
# Test of cursor-control characters inside ESC sequences
INIT
WANTSTATE
WANTSCREEN
RESET
PUSH "A B C D E F G H I"
PUSH "\x0d\x0a"
PUSH "A\e[2\bCB\e[2\bCC\e[2\bCD\e[2\bCE\e[2\bCF\e[2\bCG\e[2\bCH\e[2\bCI"
PUSH "\x0d\x0a"
PUSH "A \e[\x0d2CB\e[\x0d4CC\e[\x0d6CD\e[\x0d8CE\e[\x0d10CF\e[\x0d12CG\e[\x0d14CH\e[\x0d16CI"
PUSH "\x0d\x0a"
PUSH "A \e[1\x0bAB \e[1\x0bAC \e[1\x0bAD \e[1\x0bAE \e[1\x0bAF \e[1\x0bAG \e[1\x0bAH \e[1\x0bAI \e[1\x0bA"
!Output
$SEQ 0 2: ?screen_row \# = "A B C D E F G H I"
?screen_row 3 = "A B C D E F G H I "
?cursor = 3,18

View File

@@ -0,0 +1,36 @@
# Test of leading zeroes in ESC sequences
INIT
WANTSCREEN
RESET
PUSH "\e[00000000004;000000001HT"
PUSH "\e[00000000004;000000002Hh"
PUSH "\e[00000000004;000000003Hi"
PUSH "\e[00000000004;000000004Hs"
PUSH "\e[00000000004;000000005H "
PUSH "\e[00000000004;000000006Hi"
PUSH "\e[00000000004;000000007Hs"
PUSH "\e[00000000004;000000008H "
PUSH "\e[00000000004;000000009Ha"
PUSH "\e[00000000004;0000000010H "
PUSH "\e[00000000004;0000000011Hc"
PUSH "\e[00000000004;0000000012Ho"
PUSH "\e[00000000004;0000000013Hr"
PUSH "\e[00000000004;0000000014Hr"
PUSH "\e[00000000004;0000000015He"
PUSH "\e[00000000004;0000000016Hc"
PUSH "\e[00000000004;0000000017Ht"
PUSH "\e[00000000004;0000000018H "
PUSH "\e[00000000004;0000000019Hs"
PUSH "\e[00000000004;0000000020He"
PUSH "\e[00000000004;0000000021Hn"
PUSH "\e[00000000004;0000000022Ht"
PUSH "\e[00000000004;0000000023He"
PUSH "\e[00000000004;0000000024Hn"
PUSH "\e[00000000004;0000000025Hc"
PUSH "\e[00000000004;0000000026He"
!Output
?screen_row 3 = "This is a correct sentence"

View File

@@ -0,0 +1,18 @@
# Test of WRAP AROUND mode setting.
INIT
WANTSCREEN
RESET
PUSH "\e[?7h"
$REP 170: PUSH "*"
PUSH "\e[?7l\e[3;1H"
$REP 177: PUSH "*"
PUSH "\e[?7h\e[5;1HOK"
!Output
$SEQ 0 2: ?screen_row \# = "********************************************************************************"
?screen_row 3 = ""
?screen_row 4 = "OK"

View File

@@ -0,0 +1,29 @@
# TAB setting/resetting
INIT
WANTSTATE
WANTSCREEN
RESET
PUSH "\e[2J\e[3g"
PUSH "\e[1;1H"
$REP 26: PUSH "\e[3C\eH"
PUSH "\e[1;4H"
$REP 13: PUSH "\e[0g\e[6C"
PUSH "\e[1;7H"
PUSH "\e[1g\e[2g"
PUSH "\e[1;1H"
$REP 13: PUSH "\t*"
PUSH "\e[2;2H"
$REP 13: PUSH " *"
!Output
?screen_row 0 = " * * * * * * * * * * * * *"
?screen_row 1 = " * * * * * * * * * * * * *"
?cursor = 1,79

View File

@@ -0,0 +1,16 @@
# Origin mode
INIT
WANTSCREEN
RESET
PUSH "\e[?6h"
PUSH "\e[23;24r"
PUSH "\n"
PUSH "Bottom"
PUSH "\e[1;1H"
PUSH "Above"
!Output
?screen_row 22 = "Above"
?screen_row 23 = "Bottom"

View File

@@ -0,0 +1,17 @@
# Origin mode (2)
INIT
WANTSCREEN
RESET
PUSH "\e[?6l"
PUSH "\e[23;24r"
PUSH "\e[24;1H"
PUSH "Bottom"
PUSH "\e[1;1H"
PUSH "Top"
!Output
?screen_row 23 = "Bottom"
?screen_row 0 = "Top"

View File

@@ -0,0 +1,13 @@
INIT
WANTSTATE
!Mouse reporting should not break by idempotent DECSM 1002
PUSH "\e[?1002h"
MOUSEMOVE 0,0 0
MOUSEBTN d 1 0
output "\e[M\x20\x21\x21"
MOUSEMOVE 1,0 0
output "\e[M\x40\x21\x22"
PUSH "\e[?1002h"
MOUSEMOVE 2,0 0
output "\e[M\x40\x21\x23"

929
src/libvterm/t/harness.c Normal file
View File

@@ -0,0 +1,929 @@
#include "vterm.h"
#include "../src/vterm_internal.h" /* We pull in some internal bits too */
#include <stdio.h>
#include <string.h>
#define streq(a,b) (!strcmp(a,b))
#define strstartswith(a,b) (!strncmp(a,b,strlen(b)))
static size_t inplace_hex2bytes(char *s)
{
char *inpos = s, *outpos = s;
while(*inpos) {
unsigned int ch;
sscanf(inpos, "%2x", &ch);
*outpos = ch;
outpos += 1; inpos += 2;
}
return outpos - s;
}
static VTermModifier strpe_modifiers(char **strp)
{
VTermModifier state = 0;
while((*strp)[0]) {
switch(((*strp)++)[0]) {
case 'S': state |= VTERM_MOD_SHIFT; break;
case 'C': state |= VTERM_MOD_CTRL; break;
case 'A': state |= VTERM_MOD_ALT; break;
default: return state;
}
}
return state;
}
static VTermKey strp_key(char *str)
{
static struct {
char *name;
VTermKey key;
} keys[] = {
{ "Up", VTERM_KEY_UP },
{ "Tab", VTERM_KEY_TAB },
{ "Enter", VTERM_KEY_ENTER },
{ "KP0", VTERM_KEY_KP_0 },
{ NULL, VTERM_KEY_NONE },
};
int i;
for(i = 0; keys[i].name; i++) {
if(streq(str, keys[i].name))
return keys[i].key;
}
return VTERM_KEY_NONE;
}
static VTerm *vt;
static VTermState *state;
static VTermScreen *screen;
static VTermEncodingInstance encoding;
static int parser_text(const char bytes[], size_t len, void *user)
{
int i;
printf("text ");
for(i = 0; i < len; i++) {
unsigned char b = bytes[i];
if(b < 0x20 || b == 0x7f || (b >= 0x80 && b < 0xa0))
break;
printf(i ? ",%x" : "%x", b);
}
printf("\n");
return i;
}
static int parser_control(unsigned char control, void *user)
{
printf("control %02x\n", control);
return 1;
}
static int parser_escape(const char bytes[], size_t len, void *user)
{
int i;
if(bytes[0] >= 0x20 && bytes[0] < 0x30) {
if(len < 2)
return -1;
len = 2;
}
else {
len = 1;
}
printf("escape ");
for(i = 0; i < len; i++)
printf("%02x", bytes[i]);
printf("\n");
return len;
}
static int parser_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user)
{
int i;
printf("csi %02x", command);
if(leader && leader[0]) {
printf(" L=");
for(i = 0; leader[i]; i++)
printf("%02x", leader[i]);
}
for(i = 0; i < argcount; i++) {
char sep = i ? ',' : ' ';
if(args[i] == CSI_ARG_MISSING)
printf("%c*", sep);
else
printf("%c%ld%s", sep, CSI_ARG(args[i]), CSI_ARG_HAS_MORE(args[i]) ? "+" : "");
}
if(intermed && intermed[0]) {
printf(" I=");
for(i = 0; intermed[i]; i++)
printf("%02x", intermed[i]);
}
printf("\n");
return 1;
}
static int parser_osc(const char *command, size_t cmdlen, void *user)
{
int i;
printf("osc ");
for(i = 0; i < cmdlen; i++)
printf("%02x", command[i]);
printf("\n");
return 1;
}
static int parser_dcs(const char *command, size_t cmdlen, void *user)
{
int i;
printf("dcs ");
for(i = 0; i < cmdlen; i++)
printf("%02x", command[i]);
printf("\n");
return 1;
}
static VTermParserCallbacks parser_cbs = {
parser_text, /* text */
parser_control, /* control */
parser_escape, /* escape */
parser_csi, /* csi */
parser_osc, /* osc */
parser_dcs, /* dcs */
NULL /* resize */
};
/* These callbacks are shared by State and Screen */
static int want_movecursor = 0;
static VTermPos state_pos;
static int movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user)
{
state_pos = pos;
if(want_movecursor)
printf("movecursor %d,%d\n", pos.row, pos.col);
return 1;
}
static int want_scrollrect = 0;
static int scrollrect(VTermRect rect, int downward, int rightward, void *user)
{
if(!want_scrollrect)
return 0;
printf("scrollrect %d..%d,%d..%d => %+d,%+d\n",
rect.start_row, rect.end_row, rect.start_col, rect.end_col,
downward, rightward);
return 1;
}
static int want_moverect = 0;
static int moverect(VTermRect dest, VTermRect src, void *user)
{
if(!want_moverect)
return 0;
printf("moverect %d..%d,%d..%d -> %d..%d,%d..%d\n",
src.start_row, src.end_row, src.start_col, src.end_col,
dest.start_row, dest.end_row, dest.start_col, dest.end_col);
return 1;
}
static int want_settermprop = 0;
static int settermprop(VTermProp prop, VTermValue *val, void *user)
{
VTermValueType type;
if(!want_settermprop)
return 1;
type = vterm_get_prop_type(prop);
switch(type) {
case VTERM_VALUETYPE_BOOL:
printf("settermprop %d %s\n", prop, val->boolean ? "true" : "false");
return 1;
case VTERM_VALUETYPE_INT:
printf("settermprop %d %d\n", prop, val->number);
return 1;
case VTERM_VALUETYPE_STRING:
printf("settermprop %d \"%s\"\n", prop, val->string);
return 1;
case VTERM_VALUETYPE_COLOR:
printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue);
return 1;
}
return 0;
}
/* These callbacks are for State */
static int want_state_putglyph = 0;
static int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user)
{
int i;
if(!want_state_putglyph)
return 1;
printf("putglyph ");
for(i = 0; info->chars[i]; i++)
printf(i ? ",%x" : "%x", info->chars[i]);
printf(" %d %d,%d", info->width, pos.row, pos.col);
if(info->protected_cell)
printf(" prot");
if(info->dwl)
printf(" dwl");
if(info->dhl)
printf(" dhl-%s", info->dhl == 1 ? "top" : info->dhl == 2 ? "bottom" : "?" );
printf("\n");
return 1;
}
static int want_state_erase = 0;
static int state_erase(VTermRect rect, int selective, void *user)
{
if(!want_state_erase)
return 1;
printf("erase %d..%d,%d..%d%s\n",
rect.start_row, rect.end_row, rect.start_col, rect.end_col,
selective ? " selective" : "");
return 1;
}
static struct {
int bold;
int underline;
int italic;
int blink;
int reverse;
int strike;
int font;
VTermColor foreground;
VTermColor background;
} state_pen;
static int state_setpenattr(VTermAttr attr, VTermValue *val, void *user)
{
switch(attr) {
case VTERM_ATTR_BOLD:
state_pen.bold = val->boolean;
break;
case VTERM_ATTR_UNDERLINE:
state_pen.underline = val->number;
break;
case VTERM_ATTR_ITALIC:
state_pen.italic = val->boolean;
break;
case VTERM_ATTR_BLINK:
state_pen.blink = val->boolean;
break;
case VTERM_ATTR_REVERSE:
state_pen.reverse = val->boolean;
break;
case VTERM_ATTR_STRIKE:
state_pen.strike = val->boolean;
break;
case VTERM_ATTR_FONT:
state_pen.font = val->number;
break;
case VTERM_ATTR_FOREGROUND:
state_pen.foreground = val->color;
break;
case VTERM_ATTR_BACKGROUND:
state_pen.background = val->color;
break;
}
return 1;
}
static int state_setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user)
{
return 1;
}
VTermStateCallbacks state_cbs = {
state_putglyph, /* putglyph */
movecursor, /* movecursor */
scrollrect, /* scrollrect */
moverect, /* moverect */
state_erase, /* erase */
NULL, /* initpen */
state_setpenattr, /* setpenattr */
settermprop, /* settermprop */
NULL, /* bell */
NULL, /* resize */
state_setlineinfo, /* setlineinfo */
};
static int want_screen_damage = 0;
static int want_screen_damage_cells = 0;
static int screen_damage(VTermRect rect, void *user)
{
if(!want_screen_damage)
return 1;
printf("damage %d..%d,%d..%d",
rect.start_row, rect.end_row, rect.start_col, rect.end_col);
if(want_screen_damage_cells) {
bool equals = false;
int row;
int col;
for(row = rect.start_row; row < rect.end_row; row++) {
int eol = rect.end_col;
while(eol > rect.start_col) {
VTermScreenCell cell;
VTermPos pos;
pos.row = row;
pos.col = eol-1;
vterm_screen_get_cell(screen, pos, &cell);
if(cell.chars[0])
break;
eol--;
}
if(eol == rect.start_col)
break;
if(!equals)
printf(" ="), equals = true;
printf(" %d<", row);
for(col = rect.start_col; col < eol; col++) {
VTermScreenCell cell;
VTermPos pos;
pos.row = row;
pos.col = col;
vterm_screen_get_cell(screen, pos, &cell);
printf(col == rect.start_col ? "%02X" : " %02X", cell.chars[0]);
}
printf(">");
}
}
printf("\n");
return 1;
}
static int want_screen_scrollback = 0;
static int screen_sb_pushline(int cols, const VTermScreenCell *cells, void *user)
{
int eol;
int c;
if(!want_screen_scrollback)
return 1;
eol = cols;
while(eol && !cells[eol-1].chars[0])
eol--;
printf("sb_pushline %d =", cols);
for(c = 0; c < eol; c++)
printf(" %02X", cells[c].chars[0]);
printf("\n");
return 1;
}
static int screen_sb_popline(int cols, VTermScreenCell *cells, void *user)
{
int col;
if(!want_screen_scrollback)
return 0;
/* All lines of scrollback contain "ABCDE" */
for(col = 0; col < cols; col++) {
if(col < 5)
cells[col].chars[0] = 'A' + col;
else
cells[col].chars[0] = 0;
cells[col].width = 1;
}
printf("sb_popline %d\n", cols);
return 1;
}
VTermScreenCallbacks screen_cbs = {
screen_damage, /* damage */
moverect, /* moverect */
movecursor, /* movecursor */
settermprop, /* settermprop */
NULL, /* bell */
NULL, /* resize */
screen_sb_pushline, /* sb_pushline */
screen_sb_popline /* sb_popline */
};
int main(int argc, char **argv)
{
char line[1024] = {0};
int flag;
int err;
setvbuf(stdout, NULL, _IONBF, 0);
while(fgets(line, sizeof line, stdin)) {
char *nl;
size_t outlen;
err = 0;
if((nl = strchr(line, '\n')))
*nl = '\0';
if(streq(line, "INIT")) {
if(!vt)
vt = vterm_new(25, 80);
}
else if(streq(line, "WANTPARSER")) {
vterm_parser_set_callbacks(vt, &parser_cbs, NULL);
}
else if(strstartswith(line, "WANTSTATE") && (line[9] == '\0' || line[9] == ' ')) {
int i = 9;
int sense = 1;
if(!state) {
state = vterm_obtain_state(vt);
vterm_state_set_callbacks(state, &state_cbs, NULL);
vterm_state_set_bold_highbright(state, 1);
vterm_state_reset(state, 1);
}
while(line[i] == ' ')
i++;
for( ; line[i]; i++)
switch(line[i]) {
case '+':
sense = 1;
break;
case '-':
sense = 0;
break;
case 'g':
want_state_putglyph = sense;
break;
case 's':
want_scrollrect = sense;
break;
case 'm':
want_moverect = sense;
break;
case 'e':
want_state_erase = sense;
break;
case 'p':
want_settermprop = sense;
break;
case 'f':
vterm_state_set_unrecognised_fallbacks(state, sense ? &parser_cbs : NULL, NULL);
break;
default:
fprintf(stderr, "Unrecognised WANTSTATE flag '%c'\n", line[i]);
}
}
else if(strstartswith(line, "WANTSCREEN") && (line[10] == '\0' || line[10] == ' ')) {
int i = 10;
int sense = 1;
if(!screen)
screen = vterm_obtain_screen(vt);
vterm_screen_enable_altscreen(screen, 1);
vterm_screen_set_callbacks(screen, &screen_cbs, NULL);
while(line[i] == ' ')
i++;
for( ; line[i]; i++)
switch(line[i]) {
case '-':
sense = 0;
break;
case 'd':
want_screen_damage = sense;
break;
case 'D':
want_screen_damage = sense;
want_screen_damage_cells = sense;
break;
case 'm':
want_moverect = sense;
break;
case 'c':
want_movecursor = sense;
break;
case 'p':
want_settermprop = 1;
break;
case 'b':
want_screen_scrollback = sense;
break;
default:
fprintf(stderr, "Unrecognised WANTSCREEN flag '%c'\n", line[i]);
}
}
else if(sscanf(line, "UTF8 %d", &flag)) {
vterm_set_utf8(vt, flag);
}
else if(streq(line, "RESET")) {
if(state) {
vterm_state_reset(state, 1);
vterm_state_get_cursorpos(state, &state_pos);
}
if(screen) {
vterm_screen_reset(screen, 1);
}
}
else if(strstartswith(line, "RESIZE ")) {
int rows, cols;
char *linep = line + 7;
while(linep[0] == ' ')
linep++;
sscanf(linep, "%d, %d", &rows, &cols);
vterm_set_size(vt, rows, cols);
}
else if(strstartswith(line, "PUSH ")) {
char *bytes = line + 5;
size_t len = inplace_hex2bytes(bytes);
size_t written = vterm_input_write(vt, bytes, len);
if(written < len)
fprintf(stderr, "! short write\n");
}
else if(streq(line, "WANTENCODING")) {
/* This isn't really external API but it's hard to get this out any
* other way
*/
encoding.enc = vterm_lookup_encoding(ENC_UTF8, 'u');
if(encoding.enc->init)
(*encoding.enc->init)(encoding.enc, encoding.data);
}
else if(strstartswith(line, "ENCIN ")) {
char *bytes = line + 6;
size_t len = inplace_hex2bytes(bytes);
uint32_t cp[1024];
int cpi = 0;
size_t pos = 0;
(*encoding.enc->decode)(encoding.enc, encoding.data,
cp, &cpi, len, bytes, &pos, len);
if(cpi > 0) {
int i;
printf("encout ");
for(i = 0; i < cpi; i++) {
printf(i ? ",%x" : "%x", cp[i]);
}
printf("\n");
}
}
else if(strstartswith(line, "INCHAR ")) {
char *linep = line + 7;
unsigned int c = 0;
VTermModifier mod;
while(linep[0] == ' ')
linep++;
mod = strpe_modifiers(&linep);
sscanf(linep, " %x", &c);
vterm_keyboard_unichar(vt, c, mod);
}
else if(strstartswith(line, "INKEY ")) {
VTermModifier mod;
VTermKey key;
char *linep = line + 6;
while(linep[0] == ' ')
linep++;
mod = strpe_modifiers(&linep);
while(linep[0] == ' ')
linep++;
key = strp_key(linep);
vterm_keyboard_key(vt, key, mod);
}
else if(strstartswith(line, "PASTE ")) {
char *linep = line + 6;
if(streq(linep, "START"))
vterm_keyboard_start_paste(vt);
else if(streq(linep, "END"))
vterm_keyboard_end_paste(vt);
else
goto abort_line;
}
else if(strstartswith(line, "MOUSEMOVE ")) {
char *linep = line + 10;
int row, col, len;
VTermModifier mod;
while(linep[0] == ' ')
linep++;
sscanf(linep, "%d,%d%n", &row, &col, &len);
linep += len;
while(linep[0] == ' ')
linep++;
mod = strpe_modifiers(&linep);
vterm_mouse_move(vt, row, col, mod);
}
else if(strstartswith(line, "MOUSEBTN ")) {
char *linep = line + 9;
char press;
int button, len;
VTermModifier mod;
while(linep[0] == ' ')
linep++;
sscanf(linep, "%c %d%n", &press, &button, &len);
linep += len;
while(linep[0] == ' ')
linep++;
mod = strpe_modifiers(&linep);
vterm_mouse_button(vt, button, (press == 'd' || press == 'D'), mod);
}
else if(strstartswith(line, "DAMAGEMERGE ")) {
char *linep = line + 12;
while(linep[0] == ' ')
linep++;
if(streq(linep, "CELL"))
vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_CELL);
else if(streq(linep, "ROW"))
vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_ROW);
else if(streq(linep, "SCREEN"))
vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCREEN);
else if(streq(linep, "SCROLL"))
vterm_screen_set_damage_merge(screen, VTERM_DAMAGE_SCROLL);
}
else if(strstartswith(line, "DAMAGEFLUSH")) {
vterm_screen_flush_damage(screen);
}
else if(line[0] == '?') {
if(streq(line, "?cursor")) {
VTermPos pos;
vterm_state_get_cursorpos(state, &pos);
if(pos.row != state_pos.row)
printf("! row mismatch: state=%d,%d event=%d,%d\n",
pos.row, pos.col, state_pos.row, state_pos.col);
else if(pos.col != state_pos.col)
printf("! col mismatch: state=%d,%d event=%d,%d\n",
pos.row, pos.col, state_pos.row, state_pos.col);
else
printf("%d,%d\n", state_pos.row, state_pos.col);
}
else if(strstartswith(line, "?pen ")) {
VTermValue val;
char *linep = line + 5;
while(linep[0] == ' ')
linep++;
#define BOOLSTR(v) ((v) ? "on" : "off")
if(streq(linep, "bold")) {
vterm_state_get_penattr(state, VTERM_ATTR_BOLD, &val);
if(val.boolean != state_pen.bold)
printf("! pen bold mismatch; state=%s, event=%s\n",
BOOLSTR(val.boolean), BOOLSTR(state_pen.bold));
else
printf("%s\n", BOOLSTR(state_pen.bold));
}
else if(streq(linep, "underline")) {
vterm_state_get_penattr(state, VTERM_ATTR_UNDERLINE, &val);
if(val.boolean != state_pen.underline)
printf("! pen underline mismatch; state=%d, event=%d\n",
val.boolean, state_pen.underline);
else
printf("%d\n", state_pen.underline);
}
else if(streq(linep, "italic")) {
vterm_state_get_penattr(state, VTERM_ATTR_ITALIC, &val);
if(val.boolean != state_pen.italic)
printf("! pen italic mismatch; state=%s, event=%s\n",
BOOLSTR(val.boolean), BOOLSTR(state_pen.italic));
else
printf("%s\n", BOOLSTR(state_pen.italic));
}
else if(streq(linep, "blink")) {
vterm_state_get_penattr(state, VTERM_ATTR_BLINK, &val);
if(val.boolean != state_pen.blink)
printf("! pen blink mismatch; state=%s, event=%s\n",
BOOLSTR(val.boolean), BOOLSTR(state_pen.blink));
else
printf("%s\n", BOOLSTR(state_pen.blink));
}
else if(streq(linep, "reverse")) {
vterm_state_get_penattr(state, VTERM_ATTR_REVERSE, &val);
if(val.boolean != state_pen.reverse)
printf("! pen reverse mismatch; state=%s, event=%s\n",
BOOLSTR(val.boolean), BOOLSTR(state_pen.reverse));
else
printf("%s\n", BOOLSTR(state_pen.reverse));
}
else if(streq(linep, "font")) {
vterm_state_get_penattr(state, VTERM_ATTR_FONT, &val);
if(val.boolean != state_pen.font)
printf("! pen font mismatch; state=%d, event=%d\n",
val.boolean, state_pen.font);
else
printf("%d\n", state_pen.font);
}
else if(streq(linep, "foreground")) {
printf("rgb(%d,%d,%d)\n", state_pen.foreground.red, state_pen.foreground.green, state_pen.foreground.blue);
}
else if(streq(linep, "background")) {
printf("rgb(%d,%d,%d)\n", state_pen.background.red, state_pen.background.green, state_pen.background.blue);
}
else
printf("?\n");
}
else if(strstartswith(line, "?screen_chars ")) {
char *linep = line + 13;
VTermRect rect;
size_t len;
while(linep[0] == ' ')
linep++;
if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) {
printf("! screen_chars unrecognised input\n");
goto abort_line;
}
len = vterm_screen_get_chars(screen, NULL, 0, rect);
if(len == (size_t)-1)
printf("! screen_chars error\n");
else if(len == 0)
printf("\n");
else {
uint32_t *chars = malloc(sizeof(uint32_t) * len);
size_t i;
vterm_screen_get_chars(screen, chars, len, rect);
for(i = 0; i < len; i++) {
printf("0x%02x%s", chars[i], i < len-1 ? "," : "\n");
}
free(chars);
}
}
else if(strstartswith(line, "?screen_text ")) {
char *linep = line + 12;
VTermRect rect;
size_t len;
while(linep[0] == ' ')
linep++;
if(sscanf(linep, "%d,%d,%d,%d", &rect.start_row, &rect.start_col, &rect.end_row, &rect.end_col) < 4) {
printf("! screen_text unrecognised input\n");
goto abort_line;
}
len = vterm_screen_get_text(screen, NULL, 0, rect);
if(len == (size_t)-1)
printf("! screen_text error\n");
else if(len == 0)
printf("\n");
else {
/* Put an overwrite guard at both ends of the buffer */
unsigned char *buffer = malloc(len + 4);
unsigned char *text = buffer + 2;
text[-2] = 0x55; text[-1] = 0xAA;
text[len] = 0x55; text[len+1] = 0xAA;
vterm_screen_get_text(screen, (char *)text, len, rect);
if(text[-2] != 0x55 || text[-1] != 0xAA)
printf("! screen_get_text buffer overrun left [%02x,%02x]\n", text[-2], text[-1]);
else if(text[len] != 0x55 || text[len+1] != 0xAA)
printf("! screen_get_text buffer overrun right [%02x,%02x]\n", text[len], text[len+1]);
else
{
size_t i;
for(i = 0; i < len; i++) {
printf("0x%02x%s", text[i], i < len-1 ? "," : "\n");
}
}
free(buffer);
}
}
else if(strstartswith(line, "?screen_cell ")) {
char *linep = line + 12;
int i;
VTermPos pos;
VTermScreenCell cell;
while(linep[0] == ' ')
linep++;
if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) {
printf("! screen_cell unrecognised input\n");
goto abort_line;
}
if(!vterm_screen_get_cell(screen, pos, &cell))
goto abort_line;
printf("{");
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && cell.chars[i]; i++) {
printf("%s0x%x", i ? "," : "", cell.chars[i]);
}
printf("} width=%d attrs={", cell.width);
if(cell.attrs.bold) printf("B");
if(cell.attrs.underline) printf("U%d", cell.attrs.underline);
if(cell.attrs.italic) printf("I");
if(cell.attrs.blink) printf("K");
if(cell.attrs.reverse) printf("R");
if(cell.attrs.font) printf("F%d", cell.attrs.font);
printf("} ");
if(cell.attrs.dwl) printf("dwl ");
if(cell.attrs.dhl) printf("dhl-%s ", cell.attrs.dhl == 2 ? "bottom" : "top");
printf("fg=rgb(%d,%d,%d) ", cell.fg.red, cell.fg.green, cell.fg.blue);
printf("bg=rgb(%d,%d,%d)\n", cell.bg.red, cell.bg.green, cell.bg.blue);
}
else if(strstartswith(line, "?screen_eol ")) {
VTermPos pos;
char *linep = line + 12;
while(linep[0] == ' ')
linep++;
if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) {
printf("! screen_eol unrecognised input\n");
goto abort_line;
}
printf("%d\n", vterm_screen_is_eol(screen, pos));
}
else if(strstartswith(line, "?screen_attrs_extent ")) {
VTermPos pos;
VTermRect rect;
char *linep = line + 21;
while(linep[0] == ' ')
linep++;
if(sscanf(linep, "%d,%d\n", &pos.row, &pos.col) < 2) {
printf("! screen_attrs_extent unrecognised input\n");
goto abort_line;
}
rect.start_col = 0;
rect.end_col = -1;
if(!vterm_screen_get_attrs_extent(screen, &rect, pos, ~0)) {
printf("! screen_attrs_extent failed\n");
goto abort_line;
}
printf("%d,%d-%d,%d\n", rect.start_row, rect.start_col, rect.end_row, rect.end_col);
}
else
printf("?\n");
memset(line, 0, sizeof line);
continue;
}
else
abort_line: err = 1;
outlen = vterm_output_get_buffer_current(vt);
if(outlen > 0) {
int i;
char outbuff[1024];
vterm_output_read(vt, outbuff, outlen);
printf("output ");
for(i = 0; i < outlen; i++)
printf("%x%s", (unsigned char)outbuff[i], i < outlen-1 ? "," : "\n");
}
printf(err ? "?\n" : "DONE\n");
}
vterm_free(vt);
return 0;
}

196
src/libvterm/t/run-test.pl Normal file
View File

@@ -0,0 +1,196 @@
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use IO::Handle;
use IPC::Open2 qw( open2 );
use POSIX qw( WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG );
my $VALGRIND = 0;
GetOptions(
'valgrind|v+' => \$VALGRIND,
) or exit 1;
my ( $hin, $hout, $hpid );
{
local $ENV{LD_LIBRARY_PATH} = ".libs";
my @command = "t/.libs/harness";
unshift @command, "valgrind", "--quiet", "--error-exitcode=126" if $VALGRIND;
$hpid = open2 $hout, $hin, @command or die "Cannot open2 harness - $!";
}
my $exitcode = 0;
my $command;
my @expect;
sub do_onetest
{
$hin->print( "$command\n" );
undef $command;
my $fail_printed = 0;
while( my $outline = <$hout> ) {
last if $outline eq "DONE\n" or $outline eq "?\n";
chomp $outline;
if( !@expect ) {
print "# Test failed\n" unless $fail_printed++;
print "# expected nothing more\n" .
"# Actual: $outline\n";
next;
}
my $expectation = shift @expect;
next if $expectation eq $outline;
print "# Test failed\n" unless $fail_printed++;
print "# Expected: $expectation\n" .
"# Actual: $outline\n";
}
if( @expect ) {
print "# Test failed\n" unless $fail_printed++;
print "# Expected: $_\n" .
"# didn't happen\n" for @expect;
}
$exitcode = 1 if $fail_printed;
}
sub do_line
{
my ( $line ) = @_;
if( $line =~ m/^!(.*)/ ) {
do_onetest if defined $command;
print "> $1\n";
}
# Commands have capitals
elsif( $line =~ m/^([A-Z]+)/ ) {
# Some convenience formatting
if( $line =~ m/^(PUSH|ENCIN) (.*)$/ ) {
# we're evil
my $string = eval($2);
$line = "$1 " . unpack "H*", $string;
}
do_onetest if defined $command;
$command = $line;
undef @expect;
}
# Expectations have lowercase
elsif( $line =~ m/^([a-z]+)/ ) {
# Convenience formatting
if( $line =~ m/^(text|encout) (.*)$/ ) {
$line = "$1 " . join ",", map sprintf("%x", $_), eval($2);
}
elsif( $line =~ m/^(output) (.*)$/ ) {
$line = "$1 " . join ",", map sprintf("%x", $_), unpack "C*", eval($2);
}
elsif( $line =~ m/^control (.*)$/ ) {
$line = sprintf "control %02x", eval($1);
}
elsif( $line =~ m/^csi (\S+) (.*)$/ ) {
$line = sprintf "csi %02x %s", eval($1), $2; # TODO
}
elsif( $line =~ m/^(escape|osc|dcs) (.*)$/ ) {
$line = "$1 " . join "", map sprintf("%02x", $_), unpack "C*", eval($2);
}
elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) {
$line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2";
}
elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc) / ) {
# no conversion
}
else {
warn "Unrecognised test expectation '$line'\n";
}
push @expect, $line;
}
# ?screen_row assertion is emulated here
elsif( $line =~ s/^\?screen_row\s+(\d+)\s*=\s*// ) {
my $row = $1;
my $row1 = $row + 1;
my $want = eval($line);
do_onetest if defined $command;
# TODO: may not be 80
$hin->print( "\?screen_chars $row,0,$row1,80\n" );
my $response = <$hout>;
chomp $response;
$response = pack "C*", map hex, split m/,/, $response;
if( $response ne $want ) {
print "# Assert ?screen_row $row failed:\n" .
"# Expected: $want\n" .
"# Actual: $response\n";
$exitcode = 1;
}
}
# Assertions start with '?'
elsif( $line =~ s/^\?([a-z]+.*?=)\s+// ) {
do_onetest if defined $command;
my ( $assertion ) = $1 =~ m/^(.*)\s+=/;
$hin->print( "\?$assertion\n" );
my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n";
chomp $response;
if( $response ne $line ) {
print "# Assert $assertion failed:\n" .
"# Expected: $line\n" .
"# Actual: $response\n";
$exitcode = 1;
}
}
# Test controls start with '$'
elsif( $line =~ s/\$SEQ\s+(\d+)\s+(\d+):\s*// ) {
my ( $low, $high ) = ( $1, $2 );
foreach my $val ( $low .. $high ) {
( my $inner = $line ) =~ s/\\#/$val/g;
do_line( $inner );
}
}
elsif( $line =~ s/\$REP\s+(\d+):\s*// ) {
my $count = $1;
do_line( $line ) for 1 .. $count;
}
else {
die "Unrecognised TEST line $line\n";
}
}
open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!";
while( my $line = <$test> ) {
$line =~ s/^\s+//;
next if $line =~ m/^(?:#|$)/;
chomp $line;
do_line( $line );
}
do_onetest if defined $command;
close $hin;
close $hout;
waitpid $hpid, 0;
if( $? ) {
printf STDERR "Harness exited %d\n", WEXITSTATUS($?) if WIFEXITED($?);
printf STDERR "Harness exit signal %d\n", WTERMSIG($?) if WIFSIGNALED($?);
$exitcode = WIFEXITED($?) ? WEXITSTATUS($?) : 125;
}
exit $exitcode;