vterm_spec.lua (109402B)
1 local t = require('test.unit.testutil') 2 local itp = t.gen_itp(it) 3 local bit = require('bit') 4 5 --- @class vterm 6 --- @field ENC_UTF8 integer 7 --- @field VTERM_ATTR_BLINK integer 8 --- @field VTERM_ATTR_BOLD integer 9 --- @field VTERM_ATTR_FONT integer 10 --- @field VTERM_ATTR_ITALIC integer 11 --- @field VTERM_ATTR_REVERSE integer 12 --- @field VTERM_ATTR_UNDERLINE integer 13 --- @field VTERM_BASELINE_RAISE integer 14 --- @field VTERM_KEY_ENTER integer 15 --- @field VTERM_KEY_FUNCTION_0 integer 16 --- @field VTERM_KEY_KP_0 integer 17 --- @field VTERM_KEY_NONE integer 18 --- @field VTERM_KEY_TAB integer 19 --- @field VTERM_KEY_UP integer 20 --- @field VTERM_KEY_BACKSPACE integer 21 --- @field VTERM_KEY_ESCAPE integer 22 --- @field VTERM_KEY_DEL integer 23 --- @field VTERM_MOD_ALT integer 24 --- @field VTERM_MOD_CTRL integer 25 --- @field VTERM_MOD_SHIFT integer 26 --- @field parser_apc function 27 --- @field parser_csi function 28 --- @field parser_dcs function 29 --- @field parser_osc function 30 --- @field parser_pm function 31 --- @field parser_sos function 32 --- @field parser_text function 33 --- @field print_color function 34 --- @field schar_get fun(any, any):integer 35 --- @field screen_sb_clear function 36 --- @field screen_sb_popline function 37 --- @field screen_sb_pushline function 38 --- @field selection_query function 39 --- @field selection_set function 40 --- @field state_erase function 41 --- @field state_movecursor function 42 --- @field state_moverect function 43 --- @field state_pos function 44 --- @field state_putglyph function 45 --- @field state_sb_clear function 46 --- @field state_scrollrect function 47 --- @field state_setpenattr function 48 --- @field state_settermprop function 49 --- @field term_output function 50 --- @field utf_ptr2char fun(any):integer 51 --- @field utf_ptr2len fun(any):integer 52 --- @field vterm_input_write function 53 --- @field vterm_keyboard_end_paste function 54 --- @field vterm_keyboard_key function 55 --- @field vterm_keyboard_start_paste function 56 --- @field vterm_keyboard_unichar function 57 --- @field vterm_lookup_encoding fun(any, any):any 58 --- @field vterm_mouse_button function 59 --- @field vterm_mouse_move function 60 --- @field vterm_new fun(any, any):any 61 --- @field vterm_obtain_screen fun(any):any 62 --- @field vterm_obtain_state fun(any): any 63 --- @field vterm_output_set_callback function 64 --- @field vterm_parser_set_callbacks fun(any, any, any):any 65 --- @field vterm_screen_convert_color_to_rgb function 66 --- @field vterm_screen_enable_altscreen function 67 --- @field vterm_screen_enable_reflow function 68 --- @field vterm_screen_get_attrs_extent function 69 --- @field vterm_screen_get_cell function 70 --- @field vterm_screen_get_text fun(any, any, any, any):any 71 --- @field vterm_screen_is_eol fun(any, any):any 72 --- @field vterm_screen_reset function 73 --- @field vterm_screen_set_callbacks function 74 --- @field vterm_set_size function 75 --- @field vterm_set_utf8 fun(any, any, any):any 76 --- @field vterm_state_focus_in function 77 --- @field vterm_state_focus_out function 78 --- @field vterm_state_get_cursorpos fun(any, any) 79 --- @field vterm_state_get_lineinfo fun(any, any):any 80 --- @field vterm_state_get_penattr function 81 --- @field vterm_state_reset function 82 --- @field vterm_state_set_bold_highbright function 83 --- @field vterm_state_set_callbacks function 84 --- @field vterm_state_set_selection_callbacks function 85 --- @field vterm_state_set_unrecognised_fallbacks function 86 local vterm = t.cimport( 87 './src/nvim/grid.h', 88 './src/nvim/mbyte.h', 89 './src/nvim/vterm/encoding.h', 90 './src/nvim/vterm/keyboard.h', 91 './src/nvim/vterm/mouse.h', 92 './src/nvim/vterm/parser.h', 93 './src/nvim/vterm/pen.h', 94 './src/nvim/vterm/screen.h', 95 './src/nvim/vterm/state.h', 96 './src/nvim/vterm/vterm.h', 97 './src/nvim/vterm/vterm_internal_defs.h', 98 './test/unit/fixtures/vterm_test.h' 99 ) 100 101 --- @return string 102 local function read_rm() 103 local f = assert(io.open(t.paths.vterm_test_file, 'rb')) 104 local text = f:read('*a') 105 f:close() 106 vim.fs.rm(t.paths.vterm_test_file, { force = true }) 107 return text 108 end 109 110 local function append(str) 111 local f = assert(io.open(t.paths.vterm_test_file, 'a')) 112 f:write(str) 113 f:close() 114 return 1 115 end 116 117 local function parser_control(control) 118 return append(string.format('control %02x\n', control)) 119 end 120 121 local function parser_escape(bytes) 122 return append(string.format('escape %s\n', t.ffi.string(bytes))) 123 end 124 125 local function wantparser(vt) 126 assert(vt) 127 128 local parser_cbs = t.ffi.new('VTermParserCallbacks') 129 parser_cbs['text'] = vterm.parser_text 130 parser_cbs['control'] = parser_control 131 parser_cbs['escape'] = parser_escape 132 parser_cbs['csi'] = vterm.parser_csi 133 parser_cbs['osc'] = vterm.parser_osc 134 parser_cbs['dcs'] = vterm.parser_dcs 135 parser_cbs['apc'] = vterm.parser_apc 136 parser_cbs['pm'] = vterm.parser_pm 137 parser_cbs['sos'] = vterm.parser_sos 138 139 vterm.vterm_parser_set_callbacks(vt, parser_cbs, nil) 140 end 141 142 --- @return any 143 local function init() 144 local vt = vterm.vterm_new(25, 80) 145 vterm.vterm_output_set_callback(vt, vterm.term_output, nil) 146 vterm.vterm_set_utf8(vt, true) 147 return vt 148 end 149 150 local function state_setlineinfo() 151 return 1 152 end 153 154 --- @return any 155 local function wantstate(vt, opts) 156 opts = opts or {} 157 assert(vt) 158 local state = vterm.vterm_obtain_state(vt) 159 160 local state_cbs = t.ffi.new('VTermStateCallbacks') 161 state_cbs['putglyph'] = vterm.state_putglyph 162 state_cbs['movecursor'] = vterm.state_movecursor 163 state_cbs['scrollrect'] = vterm.state_scrollrect 164 state_cbs['moverect'] = vterm.state_moverect 165 state_cbs['erase'] = vterm.state_erase 166 state_cbs['setpenattr'] = vterm.state_setpenattr 167 state_cbs['settermprop'] = vterm.state_settermprop 168 state_cbs['setlineinfo'] = state_setlineinfo 169 state_cbs['sb_clear'] = vterm.state_sb_clear 170 171 local selection_cbs = t.ffi.new('VTermSelectionCallbacks') 172 selection_cbs['set'] = vterm.selection_set 173 selection_cbs['query'] = vterm.selection_query 174 175 vterm.vterm_state_set_callbacks(state, state_cbs, nil) 176 177 -- In some tests we want to check the behaviour of overflowing the buffer, so make it nicely small 178 vterm.vterm_state_set_selection_callbacks(state, selection_cbs, nil, nil, 16) 179 vterm.vterm_state_set_bold_highbright(state, 1) 180 vterm.vterm_state_reset(state, 1) 181 182 local fallbacks = t.ffi.new('VTermStateFallbacks') 183 fallbacks['control'] = parser_control 184 fallbacks['csi'] = vterm.parser_csi 185 fallbacks['osc'] = vterm.parser_osc 186 fallbacks['dcs'] = vterm.parser_dcs 187 fallbacks['apc'] = vterm.parser_apc 188 fallbacks['pm'] = vterm.parser_pm 189 fallbacks['sos'] = vterm.parser_sos 190 191 vterm.want_state_scrollback = opts.b or false 192 vterm.want_state_erase = opts.e or false 193 vterm.vterm_state_set_unrecognised_fallbacks(state, opts.f and fallbacks or nil, nil) 194 vterm.want_state_putglyph = opts.g or false 195 vterm.want_state_moverect = opts.m or false 196 vterm.want_state_settermprop = opts.p or false 197 vterm.want_state_scrollrect = opts.s or false 198 199 return state 200 end 201 202 --- @return any 203 local function wantscreen(vt, opts) 204 opts = opts or {} 205 local screen = vterm.vterm_obtain_screen(vt) 206 local screen_cbs = t.ffi.new('VTermScreenCallbacks') 207 208 -- TODO(dundargoc): fix 209 -- screen_cbs['damage'] = vterm.screen_damage 210 screen_cbs['moverect'] = vterm.state_moverect 211 screen_cbs['movecursor'] = vterm.state_movecursor 212 screen_cbs['settermprop'] = vterm.state_settermprop 213 screen_cbs['sb_pushline'] = vterm.screen_sb_pushline 214 screen_cbs['sb_popline'] = vterm.screen_sb_popline 215 screen_cbs['sb_clear'] = vterm.screen_sb_clear 216 217 vterm.vterm_screen_set_callbacks(screen, screen_cbs, nil) 218 219 if opts.a then 220 vterm.vterm_screen_enable_altscreen(screen, 1) 221 end 222 vterm.want_screen_scrollback = opts.b or false 223 vterm.want_state_movecursor = opts.c or false 224 -- TODO(dundargoc): fix 225 -- vterm.want_screen_damage = opts.d or opts.D or false 226 -- vterm.want_screen_cells = opts.D or false 227 vterm.want_state_moverect = opts.m or false 228 vterm.want_state_settermprop = opts.p or false 229 if opts.r then 230 vterm.vterm_screen_enable_reflow(screen, true) 231 end 232 233 return screen 234 end 235 236 local function reset(state, screen) 237 if state then 238 vterm.vterm_state_reset(state, 1) 239 vterm.vterm_state_get_cursorpos(state, vterm.state_pos) 240 end 241 if screen then 242 vterm.vterm_screen_reset(screen, 1) 243 end 244 end 245 246 local function push(input, vt) 247 vterm.vterm_input_write(vt, input, string.len(input)) 248 end 249 250 local function expect(expected) 251 local actual = read_rm() 252 t.eq(expected .. '\n', actual) 253 end 254 255 local function expect_output(expected_preformat) 256 local actual = read_rm() 257 local expected = 'output ' 258 259 for c in string.gmatch(expected_preformat, '.') do 260 if expected ~= 'output ' then 261 expected = expected .. ',' 262 end 263 expected = string.format('%s%x', expected, string.byte(c)) 264 end 265 266 t.eq(expected .. '\n', actual) 267 end 268 269 local function cursor(row, col, state) 270 local pos = t.ffi.new('VTermPos') --- @type {row: integer, col: integer} 271 vterm.vterm_state_get_cursorpos(state, pos) 272 t.eq(row, pos.row) 273 t.eq(col, pos.col) 274 end 275 276 local function lineinfo(row, expected, state) 277 local info = vterm.vterm_state_get_lineinfo(state, row) 278 local dwl = info.doublewidth == 1 279 local dhl = info.doubleheight == 1 280 local cont = info.continuation == 1 281 282 t.eq(dwl, expected.dwl or false) 283 t.eq(dhl, expected.dhl or false) 284 t.eq(cont, expected.cont or false) 285 end 286 287 local function pen(attribute, expected, state) 288 local is_bool = 289 { bold = true, italic = true, blink = true, reverse = true, dim = true, overline = true } 290 local vterm_attribute = { 291 bold = vterm.VTERM_ATTR_BOLD, 292 underline = vterm.VTERM_ATTR_UNDERLINE, 293 italic = vterm.VTERM_ATTR_ITALIC, 294 blink = vterm.VTERM_ATTR_BLINK, 295 reverse = vterm.VTERM_ATTR_REVERSE, 296 font = vterm.VTERM_ATTR_FONT, 297 dim = vterm.VTERM_ATTR_DIM, 298 overline = vterm.VTERM_ATTR_OVERLINE, 299 } 300 301 local val = t.ffi.new('VTermValue') --- @type {boolean: integer} 302 vterm.vterm_state_get_penattr(state, vterm_attribute[attribute], val) 303 local actual = val.boolean --- @type integer|boolean 304 if is_bool[attribute] then 305 actual = val.boolean == 1 306 end 307 t.eq(expected, actual) 308 end 309 310 local function resize(rows, cols, vt) 311 vterm.vterm_set_size(vt, rows, cols) 312 end 313 314 local function screen_chars(start_row, start_col, end_row, end_col, expected, screen) 315 local rect = t.ffi.new('VTermRect') 316 rect['start_row'] = start_row 317 rect['start_col'] = start_col 318 rect['end_row'] = end_row 319 rect['end_col'] = end_col 320 321 local len = vterm.vterm_screen_get_text(screen, nil, 0, rect) 322 323 local text = t.ffi.new('unsigned char[?]', len) 324 vterm.vterm_screen_get_text(screen, text, len, rect) 325 326 local actual = t.ffi.string(text, len) 327 t.eq(expected, actual) 328 end 329 330 local function screen_text(start_row, start_col, end_row, end_col, expected, screen) 331 local rect = t.ffi.new('VTermRect') 332 rect['start_row'] = start_row 333 rect['start_col'] = start_col 334 rect['end_row'] = end_row 335 rect['end_col'] = end_col 336 337 local len = vterm.vterm_screen_get_text(screen, nil, 0, rect) 338 339 local text = t.ffi.new('unsigned char[?]', len) 340 vterm.vterm_screen_get_text(screen, text, len, rect) 341 342 local actual = '' 343 for i = 0, tonumber(len) - 1 do 344 actual = string.format('%s%02x,', actual, text[i]) 345 end 346 actual = actual:sub(1, -2) 347 348 t.eq(expected, actual) 349 end 350 351 --- @param row integer 352 local function screen_row(row, expected, screen, end_col) 353 local rect = t.ffi.new('VTermRect') 354 rect['start_row'] = row 355 rect['start_col'] = 0 356 rect['end_row'] = row + 1 357 rect['end_col'] = end_col or 80 358 359 local len = vterm.vterm_screen_get_text(screen, nil, 0, rect) 360 361 local text = t.ffi.new('unsigned char[?]', len) 362 vterm.vterm_screen_get_text(screen, text, len, rect) 363 364 t.eq(expected, t.ffi.string(text, len)) 365 end 366 367 local function screen_cell(row, col, expected, screen) 368 local pos = t.ffi.new('VTermPos') 369 pos['row'] = row 370 pos['col'] = col 371 372 local cell = t.ffi.new('VTermScreenCell') ---@type any 373 vterm.vterm_screen_get_cell(screen, pos, cell) 374 375 local buf = t.ffi.new('unsigned char[32]') 376 vterm.schar_get(buf, cell.schar) 377 378 local actual = '{' 379 local i = 0 380 while buf[i] > 0 do 381 local char = vterm.utf_ptr2char(buf + i) 382 local charlen = vterm.utf_ptr2len(buf + i) 383 if i > 0 then 384 actual = actual .. ',' 385 end 386 local invalid = char >= 128 and charlen == 1 387 actual = string.format('%s%s%02x', actual, invalid and '?' or '', char) 388 i = i + charlen 389 end 390 actual = string.format('%s} width=%d attrs={', actual, cell['width']) 391 actual = actual .. (cell['attrs'].bold ~= 0 and 'B' or '') 392 actual = actual .. (cell['attrs'].dim ~= 0 and 'D' or '') 393 actual = actual 394 .. (cell['attrs'].underline ~= 0 and string.format('U%d', cell['attrs'].underline) or '') 395 actual = actual .. (cell['attrs'].italic ~= 0 and 'I' or '') 396 actual = actual .. (cell['attrs'].blink ~= 0 and 'K' or '') 397 actual = actual .. (cell['attrs'].reverse ~= 0 and 'R' or '') 398 actual = actual .. (cell['attrs'].overline ~= 0 and 'O' or '') 399 actual = actual .. (cell['attrs'].font ~= 0 and string.format('F%d', cell['attrs'].font) or '') 400 actual = actual .. (cell['attrs'].small ~= 0 and 'S' or '') 401 if cell['attrs'].baseline ~= 0 then 402 actual = actual .. (cell['attrs'].baseline == vterm.VTERM_BASELINE_RAISE and '^' or '_') 403 end 404 actual = actual .. '} ' 405 406 actual = actual .. (cell['attrs'].dwl ~= 0 and 'dwl ' or '') 407 if cell['attrs'].dhl ~= 0 then 408 actual = actual .. string.format('dhl-%s ', cell['attrs'].dhl == 2 and 'bottom' or 'top') 409 end 410 411 actual = string.format('%sfg=', actual) 412 vterm.vterm_screen_convert_color_to_rgb(screen, cell['fg']) 413 vterm.print_color(cell['fg']) 414 415 actual = actual .. read_rm() 416 actual = actual .. ' bg=' 417 418 vterm.vterm_screen_convert_color_to_rgb(screen, cell['bg']) 419 vterm.print_color(cell['bg']) 420 421 actual = actual .. read_rm() 422 423 t.eq(expected, actual) 424 end 425 426 local function screen_eol(row, col, expected, screen) 427 local pos = t.ffi.new('VTermPos') 428 pos['row'] = row 429 pos['col'] = col 430 431 local is_eol = vterm.vterm_screen_is_eol(screen, pos) 432 t.eq(expected, is_eol) 433 end 434 435 local function screen_attrs_extent(row, col, expected, screen) 436 local pos = t.ffi.new('VTermPos') 437 pos['row'] = row 438 pos['col'] = col 439 440 local rect = t.ffi.new('VTermRect') 441 rect['start_col'] = 0 442 rect['end_col'] = -1 443 vterm.vterm_screen_get_attrs_extent(screen, rect, pos, 1) 444 445 local actual = string.format( 446 '%d,%d-%d,%d', 447 rect['start_row'], 448 rect['start_col'], 449 rect['end_row'], 450 rect['end_col'] 451 ) 452 453 t.eq(expected, actual) 454 end 455 456 local function wantencoding() 457 local encoding = t.ffi.new('VTermEncodingInstance') 458 encoding['enc'] = vterm.vterm_lookup_encoding(vterm.ENC_UTF8, string.byte('u')) 459 if encoding.enc.init then 460 encoding.enc.init(encoding.enc, encoding['data']) 461 end 462 return encoding 463 end 464 465 local function encin(input, encoding) 466 local len = string.len(input) 467 468 local cp = t.ffi.new('uint32_t[?]', len) 469 local cpi = t.ffi.new('int[1]') 470 local pos = t.ffi.new('size_t[1]', 0) 471 472 encoding.enc.decode(encoding.enc, encoding.data, cp, cpi, len, input, pos, len) 473 474 local f = assert(io.open(t.paths.vterm_test_file, 'w')) 475 if tonumber(cpi[0]) > 0 then 476 f:write('encout ') 477 for i = 0, cpi[0] - 1 do 478 if i == 0 then 479 f:write(string.format('%x', cp[i])) 480 else 481 f:write(string.format(',%x', cp[i])) 482 end 483 end 484 f:write('\n') 485 end 486 f:close() 487 end 488 489 local function strpe_modifiers(input_mod) 490 local mod = t.ffi.new('VTermModifier') ---@type any 491 if input_mod.C then 492 mod = bit.bor(mod, vterm.VTERM_MOD_CTRL) 493 end 494 if input_mod.S then 495 mod = bit.bor(mod, vterm.VTERM_MOD_SHIFT) 496 end 497 if input_mod.A then 498 mod = bit.bor(mod, vterm.VTERM_MOD_ALT) 499 end 500 return mod 501 end 502 503 local function strp_key(input_key) 504 if input_key == 'up' then 505 return vterm.VTERM_KEY_UP 506 end 507 508 if input_key == 'tab' then 509 return vterm.VTERM_KEY_TAB 510 end 511 512 if input_key == 'enter' then 513 return vterm.VTERM_KEY_ENTER 514 end 515 516 if input_key == 'bs' then 517 return vterm.VTERM_KEY_BACKSPACE 518 end 519 520 if input_key == 'del' then 521 return vterm.VTERM_KEY_DEL 522 end 523 524 if input_key == 'esc' then 525 return vterm.VTERM_KEY_ESCAPE 526 end 527 528 if input_key == 'f1' then 529 return vterm.VTERM_KEY_FUNCTION_0 + 1 530 end 531 532 if input_key == 'kp0' then 533 return vterm.VTERM_KEY_KP_0 534 end 535 536 return vterm.VTERM_KEY_NONE 537 end 538 539 local function mousemove(row, col, vt, input_mod) 540 input_mod = input_mod or {} 541 local mod = strpe_modifiers(input_mod) 542 vterm.vterm_mouse_move(vt, row, col, mod) 543 end 544 545 local function mousebtn(press, button, vt, input_mod) 546 input_mod = input_mod or {} 547 local mod = strpe_modifiers(input_mod) 548 local flag = press == 'd' or press == 'D' 549 vterm.vterm_mouse_button(vt, button, flag, mod) 550 end 551 552 local function inchar(c, vt, input_mod) 553 input_mod = input_mod or {} 554 local mod = strpe_modifiers(input_mod) 555 vterm.vterm_keyboard_unichar(vt, c, mod) 556 end 557 558 local function inkey(input_key, vt, input_mod) 559 input_mod = input_mod or {} 560 local mod = strpe_modifiers(input_mod) 561 local key = strp_key(input_key) 562 vterm.vterm_keyboard_key(vt, key, mod) 563 end 564 565 before_each(function() 566 vim.fs.rm(t.paths.vterm_test_file, { force = true }) 567 end) 568 569 describe('vterm', function() 570 itp('02parser', function() 571 local vt = init() 572 vterm.vterm_set_utf8(vt, false) 573 wantparser(vt) 574 575 -- Basic text 576 push('hello', vt) 577 expect('text 68,65,6c,6c,6f') 578 579 -- C0 580 push('\x03', vt) 581 expect('control 03') 582 push('\x1f', vt) 583 expect('control 1f') 584 585 -- C1 8bit 586 push('\x83', vt) 587 expect('control 83') 588 push('\x99', vt) 589 expect('control 99') 590 591 -- C1 7bit 592 push('\x1b\x43', vt) 593 expect('control 83') 594 push('\x1b\x59', vt) 595 expect('control 99') 596 597 -- High bytes 598 push('\xa0\xcc\xfe', vt) 599 expect('text a0,cc,fe') 600 601 -- Mixed 602 push('1\n2', vt) 603 expect('text 31\ncontrol 0a\ntext 32') 604 605 -- Escape 606 push('\x1b=', vt) 607 expect('escape =') 608 609 -- Escape 2-byte 610 push('\x1b(X', vt) 611 expect('escape (X') 612 613 -- Split write Escape 614 push('\x1b(', vt) 615 push('Y', vt) 616 expect('escape (Y') 617 618 -- Escape cancels Escape, starts another 619 push('\x1b(\x1b)Z', vt) 620 expect('escape )Z') 621 622 -- CAN cancels Escape, returns to normal mode 623 push('\x1b(\x18AB', vt) 624 expect('text 41,42') 625 626 -- C0 in Escape interrupts and continues 627 push('\x1b(\nX', vt) 628 expect('control 0a\nescape (X') 629 630 -- CSI 0 args 631 push('\x1b[a', vt) 632 expect('csi 61 *') 633 634 -- CSI 1 arg 635 push('\x1b[9b', vt) 636 expect('csi 62 9') 637 638 -- CSI 2 args 639 push('\x1b[3;4c', vt) 640 expect('csi 63 3,4') 641 642 -- CSI 1 arg 1 sub 643 push('\x1b[1:2c', vt) 644 expect('csi 63 1+,2') 645 646 -- CSI many digits 647 push('\x1b[678d', vt) 648 expect('csi 64 678') 649 650 -- CSI leading zero 651 push('\x1b[007e', vt) 652 expect('csi 65 7') 653 654 -- CSI qmark 655 push('\x1b[?2;7f', vt) 656 expect('csi 66 L=3f 2,7') 657 658 -- CSI greater 659 push('\x1b[>c', vt) 660 expect('csi 63 L=3e *') 661 662 -- CSI SP 663 push('\x1b[12 q', vt) 664 expect('csi 71 12 I=20') 665 666 -- Mixed CSI 667 push('A\x1b[8mB', vt) 668 expect('text 41\ncsi 6d 8\ntext 42') 669 670 -- Split write 671 push('\x1b', vt) 672 push('[a', vt) 673 expect('csi 61 *') 674 push('foo\x1b[', vt) 675 expect('text 66,6f,6f') 676 push('4b', vt) 677 expect('csi 62 4') 678 push('\x1b[12;', vt) 679 push('3c', vt) 680 expect('csi 63 12,3') 681 682 -- Escape cancels CSI, starts Escape 683 push('\x1b[123\x1b9', vt) 684 expect('escape 9') 685 686 -- CAN cancels CSI, returns to normal mode 687 push('\x1b[12\x18AB', vt) 688 expect('text 41,42') 689 690 -- C0 in Escape interrupts and continues 691 push('\x1b(\nX', vt) 692 expect('control 0a\nescape (X') 693 694 -- OSC BEL 695 push('\x1b]1;Hello\x07', vt) 696 expect('osc [1;Hello]') 697 698 -- OSC ST (7bit) 699 push('\x1b]1;Hello\x1b\\', vt) 700 expect('osc [1;Hello]') 701 702 -- OSC ST (8bit) 703 push('\x9d1;Hello\x9c', vt) 704 expect('osc [1;Hello]') 705 706 -- OSC in parts 707 push('\x1b]52;abc', vt) 708 expect('osc [52;abc') 709 push('def', vt) 710 expect('osc def') 711 push('ghi\x1b\\', vt) 712 expect('osc ghi]') 713 714 -- OSC BEL without semicolon 715 push('\x1b]1234\x07', vt) 716 expect('osc [1234;]') 717 718 -- OSC ST without semicolon 719 push('\x1b]1234\x1b\\', vt) 720 expect('osc [1234;]') 721 722 -- Escape cancels OSC, starts Escape 723 push('\x1b]Something\x1b9', vt) 724 expect('escape 9') 725 726 -- CAN cancels OSC, returns to normal mode 727 push('\x1b]12\x18AB', vt) 728 expect('text 41,42') 729 730 -- C0 in OSC interrupts and continues 731 push('\x1b]2;\nBye\x07', vt) 732 expect('osc [2;\ncontrol 0a\nosc Bye]') 733 734 -- DCS BEL 735 push('\x1bPHello\x07', vt) 736 expect('dcs [Hello]') 737 738 -- DCS ST (7bit) 739 push('\x1bPHello\x1b\\', vt) 740 expect('dcs [Hello]') 741 742 -- DCS ST (8bit) 743 push('\x90Hello\x9c', vt) 744 expect('dcs [Hello]') 745 746 -- Split write of 7bit ST 747 push('\x1bPABC\x1b', vt) 748 expect('dcs [ABC') 749 push('\\', vt) 750 expect('dcs ]') 751 752 -- Escape cancels DCS, starts Escape 753 push('\x1bPSomething\x1b9', vt) 754 expect('escape 9') 755 756 -- CAN cancels DCS, returns to normal mode 757 push('\x1bP12\x18AB', vt) 758 expect('text 41,42') 759 760 -- C0 in OSC interrupts and continues 761 push('\x1bPBy\ne\x07', vt) 762 expect('dcs [By\ncontrol 0a\ndcs e]') 763 764 -- APC BEL 765 push('\x1b_Hello\x07', vt) 766 expect('apc [Hello]') 767 768 -- APC ST (7bit) 769 push('\x1b_Hello\x1b\\', vt) 770 expect('apc [Hello]') 771 772 -- APC ST (8bit) 773 push('\x9fHello\x9c', vt) 774 expect('apc [Hello]') 775 776 -- PM BEL 777 push('\x1b^Hello\x07', vt) 778 expect('pm [Hello]') 779 780 -- PM ST (7bit) 781 push('\x1b^Hello\x1b\\', vt) 782 expect('pm [Hello]') 783 784 -- PM ST (8bit) 785 push('\x9eHello\x9c', vt) 786 expect('pm [Hello]') 787 788 -- SOS BEL 789 push('\x1bXHello\x07', vt) 790 expect('sos [Hello]') 791 792 -- SOS ST (7bit) 793 push('\x1bXHello\x1b\\', vt) 794 expect('sos [Hello]') 795 796 -- SOS ST (8bit) 797 push('\x98Hello\x9c', vt) 798 expect('sos [Hello]') 799 800 push('\x1bXABC\x01DEF\x1b\\', vt) 801 expect('sos [ABC\x01DEF]') 802 push('\x1bXABC\x99DEF\x1b\\', vt) 803 expect('sos [ABC\x99DEF]') 804 805 -- NUL ignored 806 push('\x00', vt) 807 808 -- NUL ignored within CSI 809 push('\x1b[12\x003m', vt) 810 expect('csi 6d 123') 811 812 -- DEL ignored 813 push('\x7f', vt) 814 815 -- DEL ignored within CSI 816 push('\x1b[12\x7f3m', vt) 817 expect('csi 6d 123') 818 819 -- DEL inside text" 820 push('AB\x7fC', vt) 821 expect('text 41,42\ntext 43') 822 end) 823 824 itp('03encoding_utf8', function() 825 local encoding = wantencoding() 826 827 -- Low 828 encin('123', encoding) 829 expect('encout 31,32,33') 830 831 -- We want to prove the UTF-8 parser correctly handles all the sequences. 832 -- Easy way to do this is to check it does low/high boundary cases, as that 833 -- leaves only two for each sequence length 834 -- 835 -- These ranges are therefore: 836 -- 837 -- Two bytes: 838 -- U+0080 = 000 10000000 => 00010 000000 839 -- => 11000010 10000000 = C2 80 840 -- U+07FF = 111 11111111 => 11111 111111 841 -- => 11011111 10111111 = DF BF 842 -- 843 -- Three bytes: 844 -- U+0800 = 00001000 00000000 => 0000 100000 000000 845 -- => 11100000 10100000 10000000 = E0 A0 80 846 -- U+FFFD = 11111111 11111101 => 1111 111111 111101 847 -- => 11101111 10111111 10111101 = EF BF BD 848 -- (We avoid U+FFFE and U+FFFF as they're invalid codepoints) 849 -- 850 -- Four bytes: 851 -- U+10000 = 00001 00000000 00000000 => 000 010000 000000 000000 852 -- => 11110000 10010000 10000000 10000000 = F0 90 80 80 853 -- U+1FFFFF = 11111 11111111 11111111 => 111 111111 111111 111111 854 -- => 11110111 10111111 10111111 10111111 = F7 BF BF BF 855 856 -- 2 byte 857 encin('\xC2\x80\xDF\xBF', encoding) 858 expect('encout 80,7ff') 859 860 -- 3 byte 861 encin('\xE0\xA0\x80\xEF\xBF\xBD', encoding) 862 expect('encout 800,fffd') 863 864 -- 4 byte 865 encin('\xF0\x90\x80\x80\xF7\xBF\xBF\xBF', encoding) 866 expect('encout 10000,1fffff') 867 868 -- Next up, we check some invalid sequences 869 -- + Early termination (back to low bytes too soon) 870 -- + Early restart (another sequence introduction before the previous one was finished) 871 872 -- Early termination 873 encin('\xC2!', encoding) 874 expect('encout fffd,21') 875 876 encin('\xE0!\xE0\xA0!', encoding) 877 expect('encout fffd,21,fffd,21') 878 879 encin('\xF0!\xF0\x90!\xF0\x90\x80!', encoding) 880 expect('encout fffd,21,fffd,21,fffd,21') 881 882 -- Early restart 883 encin('\xC2\xC2\x90', encoding) 884 expect('encout fffd,90') 885 886 encin('\xE0\xC2\x90\xE0\xA0\xC2\x90', encoding) 887 expect('encout fffd,90,fffd,90') 888 889 encin('\xF0\xC2\x90\xF0\x90\xC2\x90\xF0\x90\x80\xC2\x90', encoding) 890 expect('encout fffd,90,fffd,90,fffd,90') 891 892 -- Test the overlong sequences by giving an overlong encoding of U+0000 and 893 -- an encoding of the highest codepoint still too short 894 -- 895 -- Two bytes: 896 -- U+0000 = C0 80 897 -- U+007F = 000 01111111 => 00001 111111 => 898 -- => 11000001 10111111 => C1 BF 899 -- 900 -- Three bytes: 901 -- U+0000 = E0 80 80 902 -- U+07FF = 00000111 11111111 => 0000 011111 111111 903 -- => 11100000 10011111 10111111 = E0 9F BF 904 -- 905 -- Four bytes: 906 -- U+0000 = F0 80 80 80 907 -- U+FFFF = 11111111 11111111 => 000 001111 111111 111111 908 -- => 11110000 10001111 10111111 10111111 = F0 8F BF BF 909 910 -- Overlong 911 encin('\xC0\x80\xC1\xBF', encoding) 912 expect('encout fffd,fffd') 913 914 encin('\xE0\x80\x80\xE0\x9F\xBF', encoding) 915 expect('encout fffd,fffd') 916 917 encin('\xF0\x80\x80\x80\xF0\x8F\xBF\xBF', encoding) 918 expect('encout fffd,fffd') 919 920 -- UTF-16 surrogates U+D800 and U+DFFF 921 -- UTF-16 Surrogates 922 encin('\xED\xA0\x80\xED\xBF\xBF', encoding) 923 expect('encout fffd,fffd') 924 925 -- Split write 926 encin('\xC2', encoding) 927 encin('\xA0', encoding) 928 expect('encout a0') 929 930 encin('\xE0', encoding) 931 encin('\xA0\x80', encoding) 932 expect('encout 800') 933 encin('\xE0\xA0', encoding) 934 encin('\x80', encoding) 935 expect('encout 800') 936 937 encin('\xF0', encoding) 938 encin('\x90\x80\x80', encoding) 939 expect('encout 10000') 940 encin('\xF0\x90', encoding) 941 encin('\x80\x80', encoding) 942 expect('encout 10000') 943 encin('\xF0\x90\x80', encoding) 944 encin('\x80', encoding) 945 expect('encout 10000') 946 end) 947 948 itp('10state_putglyph', function() 949 local vt = init() 950 local state = wantstate(vt, { g = true }) 951 952 -- Low 953 reset(state, nil) 954 push('ABC', vt) 955 expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,2') 956 957 -- UTF-8 1 char 958 -- U+00C1 = 0xC3 0x81 name: LATIN CAPITAL LETTER A WITH ACUTE 959 -- U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE 960 reset(state, nil) 961 push('\xC3\x81\xC3\xA9', vt) 962 expect('putglyph c1 1 0,0\nputglyph e9 1 0,1') 963 964 -- UTF-8 split writes 965 reset(state, nil) 966 push('\xC3', vt) 967 push('\x81', vt) 968 expect('putglyph c1 1 0,0') 969 970 -- UTF-8 wide char 971 -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO 972 reset(state, nil) 973 push('\xEF\xBC\x90 ', vt) 974 expect('putglyph ff10 2 0,0\nputglyph 20 1 0,2') 975 976 -- UTF-8 emoji wide char 977 -- U+1F600 = F0 9F 98 80 name: GRINNING FACE 978 reset(state, nil) 979 push('\xF0\x9F\x98\x80 ', vt) 980 expect('putglyph 1f600 2 0,0\nputglyph 20 1 0,2') 981 982 -- UTF-8 combining chars 983 -- U+0301 = CC 81 name: COMBINING ACUTE 984 reset(state, nil) 985 push('e\xCC\x81Z', vt) 986 expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1') 987 988 -- Combining across buffers 989 reset(state, nil) 990 push('e', vt) 991 expect('putglyph 65 1 0,0') 992 push('\xCC\x81Z', vt) 993 expect('putglyph 65,301 1 0,0\nputglyph 5a 1 0,1') 994 995 -- Spare combining chars get truncated 996 reset(state, nil) 997 push('e' .. string.rep('\xCC\x81', 20), vt) 998 expect('putglyph 65,301,301,301,301,301,301,301,301,301,301,301,301,301,301 1 0,0') -- and nothing more 999 1000 -- Combining across buffers multiple times 1001 reset(state, nil) 1002 push('e', vt) 1003 expect('putglyph 65 1 0,0') 1004 push('\xCC\x81', vt) 1005 expect('putglyph 65,301 1 0,0') 1006 push('\xCC\x82', vt) 1007 expect('putglyph 65,301,302 1 0,0') 1008 1009 -- Combining across buffers at right edge 1010 reset(state, nil) 1011 push('\x1b[5;80H', vt) 1012 push('e', vt) 1013 expect('putglyph 65 1 4,79') 1014 push('\xCC\x81', vt) 1015 expect('putglyph 65,301 1 4,79') 1016 push('\xCC\x82Z', vt) 1017 expect('putglyph 65,301,302 1 4,79\nputglyph 5a 1 5,0') 1018 1019 -- Combining regional indicators 1020 reset(state, nil) 1021 push('\x1b[5;77H', vt) 1022 push('🇦', vt) 1023 expect('putglyph 1f1e6 2 4,76') 1024 push('🇩', vt) 1025 expect('putglyph 1f1e6,1f1e9 2 4,76') 1026 push('🇱', vt) 1027 expect('putglyph 1f1f1 2 4,78') 1028 push('🇮', vt) 1029 expect('putglyph 1f1f1,1f1ee 2 4,78') 1030 push('🇲', vt) 1031 expect('putglyph 1f1f2 2 5,0') 1032 push('🇨', vt) 1033 expect('putglyph 1f1f2,1f1e8 2 5,0') 1034 1035 -- emoji with ZWJ and variant selectors, as one chunk 1036 reset(state, nil) 1037 push('🏳️🌈🏳️⚧️🏴☠️', vt) 1038 expect([[putglyph 1f3f3,fe0f,200d,1f308 2 0,0 1039 putglyph 1f3f3,fe0f,200d,26a7,fe0f 2 0,2 1040 putglyph 1f3f4,200d,2620,fe0f 2 0,4]]) 1041 1042 -- emoji, one code point at a time 1043 reset(state, nil) 1044 push('🏳', vt) 1045 expect('putglyph 1f3f3 2 0,0') 1046 push('\xef\xb8\x8f', vt) 1047 expect('putglyph 1f3f3,fe0f 2 0,0') 1048 push('\xe2\x80\x8d', vt) 1049 expect('putglyph 1f3f3,fe0f,200d 2 0,0') 1050 push('🌈', vt) 1051 expect('putglyph 1f3f3,fe0f,200d,1f308 2 0,0') 1052 1053 -- modifier can change width 1054 push('❤', vt) 1055 expect('putglyph 2764 1 0,2') 1056 push('\xef\xb8\x8f', vt) 1057 expect('putglyph 2764,fe0f 2 0,2') 1058 1059 -- also works batched 1060 push('❤️', vt) 1061 expect('putglyph 2764,fe0f 2 0,4') 1062 1063 -- DECSCA protected 1064 reset(state, nil) 1065 push('A\x1b[1"qB\x1b[2"qC', vt) 1066 expect('putglyph 41 1 0,0\nputglyph 42 1 0,1 prot\nputglyph 43 1 0,2') 1067 end) 1068 1069 itp('11state_movecursor', function() 1070 local vt = init() 1071 local state = wantstate(vt) 1072 1073 -- Implicit 1074 push('ABC', vt) 1075 cursor(0, 3, state) 1076 1077 -- Backspace 1078 push('\b', vt) 1079 cursor(0, 2, state) 1080 -- Horizontal Tab 1081 push('\t', vt) 1082 cursor(0, 8, state) 1083 -- Carriage Return 1084 push('\r', vt) 1085 cursor(0, 0, state) 1086 -- Linefeed 1087 push('\n', vt) 1088 cursor(1, 0, state) 1089 1090 -- Backspace bounded by lefthand edge 1091 push('\x1b[4;2H', vt) 1092 cursor(3, 1, state) 1093 push('\b', vt) 1094 cursor(3, 0, state) 1095 push('\b', vt) 1096 cursor(3, 0, state) 1097 1098 -- Backspace cancels phantom 1099 push('\x1b[4;80H', vt) 1100 cursor(3, 79, state) 1101 push('X', vt) 1102 cursor(3, 79, state) 1103 push('\b', vt) 1104 cursor(3, 78, state) 1105 1106 -- HT bounded by righthand edge 1107 push('\x1b[1;78H', vt) 1108 cursor(0, 77, state) 1109 push('\t', vt) 1110 cursor(0, 79, state) 1111 push('\t', vt) 1112 cursor(0, 79, state) 1113 1114 reset(state, nil) 1115 1116 -- Index 1117 push('ABC\x1bD', vt) 1118 cursor(1, 3, state) 1119 -- Reverse Index 1120 push('\x1bM', vt) 1121 cursor(0, 3, state) 1122 -- Newline 1123 push('\x1bE', vt) 1124 cursor(1, 0, state) 1125 1126 reset(state, nil) 1127 1128 -- Cursor Forward 1129 push('\x1b[B', vt) 1130 cursor(1, 0, state) 1131 push('\x1b[3B', vt) 1132 cursor(4, 0, state) 1133 push('\x1b[0B', vt) 1134 cursor(5, 0, state) 1135 1136 -- Cursor Down 1137 push('\x1b[C', vt) 1138 cursor(5, 1, state) 1139 push('\x1b[3C', vt) 1140 cursor(5, 4, state) 1141 push('\x1b[0C', vt) 1142 cursor(5, 5, state) 1143 1144 -- Cursor Up 1145 push('\x1b[A', vt) 1146 cursor(4, 5, state) 1147 push('\x1b[3A', vt) 1148 cursor(1, 5, state) 1149 push('\x1b[0A', vt) 1150 cursor(0, 5, state) 1151 1152 -- Cursor Backward 1153 push('\x1b[D', vt) 1154 cursor(0, 4, state) 1155 push('\x1b[3D', vt) 1156 cursor(0, 1, state) 1157 push('\x1b[0D', vt) 1158 cursor(0, 0, state) 1159 1160 -- Cursor Next Line 1161 push(' ', vt) 1162 cursor(0, 3, state) 1163 push('\x1b[E', vt) 1164 cursor(1, 0, state) 1165 push(' ', vt) 1166 cursor(1, 3, state) 1167 push('\x1b[2E', vt) 1168 cursor(3, 0, state) 1169 push('\x1b[0E', vt) 1170 cursor(4, 0, state) 1171 1172 -- Cursor Previous Line 1173 push(' ', vt) 1174 cursor(4, 3, state) 1175 push('\x1b[F', vt) 1176 cursor(3, 0, state) 1177 push(' ', vt) 1178 cursor(3, 3, state) 1179 push('\x1b[2F', vt) 1180 cursor(1, 0, state) 1181 push('\x1b[0F', vt) 1182 cursor(0, 0, state) 1183 1184 -- Cursor Horizontal Absolute 1185 push('\n', vt) 1186 cursor(1, 0, state) 1187 push('\x1b[20G', vt) 1188 cursor(1, 19, state) 1189 push('\x1b[G', vt) 1190 cursor(1, 0, state) 1191 1192 -- Cursor Position 1193 push('\x1b[10;5H', vt) 1194 cursor(9, 4, state) 1195 push('\x1b[8H', vt) 1196 cursor(7, 0, state) 1197 push('\x1b[H', vt) 1198 cursor(0, 0, state) 1199 1200 -- Cursor Position cancels phantom 1201 push('\x1b[10;78H', vt) 1202 cursor(9, 77, state) 1203 push('ABC', vt) 1204 cursor(9, 79, state) 1205 push('\x1b[10;80H', vt) 1206 push('C', vt) 1207 cursor(9, 79, state) 1208 push('X', vt) 1209 cursor(10, 1, state) 1210 1211 reset(state, nil) 1212 1213 -- Bounds Checking 1214 push('\x1b[A', vt) 1215 cursor(0, 0, state) 1216 push('\x1b[D', vt) 1217 cursor(0, 0, state) 1218 push('\x1b[25;80H', vt) 1219 cursor(24, 79, state) 1220 push('\x1b[B', vt) 1221 cursor(24, 79, state) 1222 push('\x1b[C', vt) 1223 cursor(24, 79, state) 1224 push('\x1b[E', vt) 1225 cursor(24, 0, state) 1226 push('\x1b[H', vt) 1227 cursor(0, 0, state) 1228 push('\x1b[F', vt) 1229 cursor(0, 0, state) 1230 push('\x1b[999G', vt) 1231 cursor(0, 79, state) 1232 push('\x1b[99;99H', vt) 1233 cursor(24, 79, state) 1234 1235 reset(state, nil) 1236 1237 -- Horizontal Position Absolute 1238 push('\x1b[5`', vt) 1239 cursor(0, 4, state) 1240 1241 -- Horizontal Position Relative 1242 push('\x1b[3a', vt) 1243 cursor(0, 7, state) 1244 1245 -- Horizontal Position Backward 1246 push('\x1b[3j', vt) 1247 cursor(0, 4, state) 1248 1249 -- Horizontal and Vertical Position 1250 push('\x1b[3;3f', vt) 1251 cursor(2, 2, state) 1252 1253 -- Vertical Position Absolute 1254 push('\x1b[5d', vt) 1255 cursor(4, 2, state) 1256 1257 -- Vertical Position Relative 1258 push('\x1b[2e', vt) 1259 cursor(6, 2, state) 1260 1261 -- Vertical Position Backward 1262 push('\x1b[2k', vt) 1263 cursor(4, 2, state) 1264 1265 reset(state, nil) 1266 1267 -- Horizontal Tab 1268 push('\t', vt) 1269 cursor(0, 8, state) 1270 push(' ', vt) 1271 cursor(0, 11, state) 1272 push('\t', vt) 1273 cursor(0, 16, state) 1274 push(' ', vt) 1275 cursor(0, 23, state) 1276 push('\t', vt) 1277 cursor(0, 24, state) 1278 push(' ', vt) 1279 cursor(0, 32, state) 1280 push('\t', vt) 1281 cursor(0, 40, state) 1282 1283 -- Cursor Horizontal Tab 1284 push('\x1b[I', vt) 1285 cursor(0, 48, state) 1286 push('\x1b[2I', vt) 1287 cursor(0, 64, state) 1288 1289 -- Cursor Backward Tab 1290 push('\x1b[Z', vt) 1291 cursor(0, 56, state) 1292 push('\x1b[2Z', vt) 1293 cursor(0, 40, state) 1294 end) 1295 1296 itp('12state_scroll', function() 1297 local vt = init() 1298 local state = wantstate(vt, { s = true }) 1299 1300 -- Linefeed 1301 push(string.rep('\n', 24), vt) 1302 cursor(24, 0, state) 1303 push('\n', vt) 1304 expect('scrollrect 0..25,0..80 => +1,+0') 1305 cursor(24, 0, state) 1306 1307 reset(state, nil) 1308 1309 -- Index 1310 push('\x1b[25H', vt) 1311 push('\x1bD', vt) 1312 expect('scrollrect 0..25,0..80 => +1,+0') 1313 1314 reset(state, nil) 1315 1316 -- Reverse Index 1317 push('\x1bM', vt) 1318 expect('scrollrect 0..25,0..80 => -1,+0') 1319 1320 reset(state, nil) 1321 1322 -- Linefeed in DECSTBM 1323 push('\x1b[1;10r', vt) 1324 cursor(0, 0, state) 1325 push(string.rep('\n', 9), vt) 1326 cursor(9, 0, state) 1327 push('\n', vt) 1328 expect('scrollrect 0..10,0..80 => +1,+0') 1329 cursor(9, 0, state) 1330 1331 -- Linefeed outside DECSTBM 1332 push('\x1b[20H', vt) 1333 cursor(19, 0, state) 1334 push('\n', vt) 1335 cursor(20, 0, state) 1336 1337 -- Index in DECSTBM 1338 push('\x1b[9;10r', vt) 1339 push('\x1b[10H', vt) 1340 push('\x1bM', vt) 1341 cursor(8, 0, state) 1342 push('\x1bM', vt) 1343 expect('scrollrect 8..10,0..80 => -1,+0') 1344 1345 -- Reverse Index in DECSTBM 1346 push('\x1b[25H', vt) 1347 cursor(24, 0, state) 1348 push('\n', vt) 1349 -- no scrollrect 1350 cursor(24, 0, state) 1351 1352 -- Linefeed in DECSTBM+DECSLRM 1353 push('\x1b[?69h', vt) 1354 push('\x1b[3;10r\x1b[10;40s', vt) 1355 push('\x1b[10;10H\n', vt) 1356 expect('scrollrect 2..10,9..40 => +1,+0') 1357 1358 -- IND/RI in DECSTBM+DECSLRM 1359 push('\x1bD', vt) 1360 expect('scrollrect 2..10,9..40 => +1,+0') 1361 push('\x1b[3;10H\x1bM', vt) 1362 expect('scrollrect 2..10,9..40 => -1,+0') 1363 1364 -- DECRQSS on DECSTBM 1365 push('\x1bP$qr\x1b\\', vt) 1366 expect_output('\x1bP1$r3;10r\x1b\\') 1367 1368 -- DECRQSS on DECSLRM 1369 push('\x1bP$qs\x1b\\', vt) 1370 expect_output('\x1bP1$r10;40s\x1b\\') 1371 1372 -- Setting invalid DECSLRM with !DECVSSM is still rejected 1373 push('\x1b[?69l\x1b[;0s\x1b[?69h', vt) 1374 1375 reset(state, nil) 1376 1377 -- Scroll Down 1378 push('\x1b[S', vt) 1379 expect('scrollrect 0..25,0..80 => +1,+0') 1380 cursor(0, 0, state) 1381 push('\x1b[2S', vt) 1382 expect('scrollrect 0..25,0..80 => +2,+0') 1383 cursor(0, 0, state) 1384 push('\x1b[100S', vt) 1385 expect('scrollrect 0..25,0..80 => +25,+0') 1386 1387 -- Scroll Up 1388 push('\x1b[T', vt) 1389 expect('scrollrect 0..25,0..80 => -1,+0') 1390 cursor(0, 0, state) 1391 push('\x1b[2T', vt) 1392 expect('scrollrect 0..25,0..80 => -2,+0') 1393 cursor(0, 0, state) 1394 push('\x1b[100T', vt) 1395 expect('scrollrect 0..25,0..80 => -25,+0') 1396 1397 -- SD/SU in DECSTBM 1398 push('\x1b[5;20r', vt) 1399 push('\x1b[S', vt) 1400 expect('scrollrect 4..20,0..80 => +1,+0') 1401 push('\x1b[T', vt) 1402 expect('scrollrect 4..20,0..80 => -1,+0') 1403 1404 reset(state, nil) 1405 1406 -- SD/SU in DECSTBM+DECSLRM 1407 push('\x1b[?69h', vt) 1408 push('\x1b[3;10r\x1b[10;40s', vt) 1409 cursor(0, 0, state) 1410 push('\x1b[3;10H', vt) 1411 cursor(2, 9, state) 1412 push('\x1b[S', vt) 1413 expect('scrollrect 2..10,9..40 => +1,+0') 1414 push('\x1b[?69l', vt) 1415 push('\x1b[S', vt) 1416 expect('scrollrect 2..10,0..80 => +1,+0') 1417 1418 -- Invalid boundaries 1419 reset(state, nil) 1420 1421 push('\x1b[100;105r\x1bD', vt) 1422 push('\x1b[5;2r\x1bD', vt) 1423 1424 reset(state, nil) 1425 state = wantstate(vt, { m = true, e = true }) 1426 1427 -- Scroll Down move+erase emulation 1428 push('\x1b[S', vt) 1429 expect('moverect 1..25,0..80 -> 0..24,0..80\nerase 24..25,0..80') 1430 cursor(0, 0, state) 1431 push('\x1b[2S', vt) 1432 expect('moverect 2..25,0..80 -> 0..23,0..80\nerase 23..25,0..80') 1433 cursor(0, 0, state) 1434 1435 -- Scroll Up move+erase emulation 1436 push('\x1b[T', vt) 1437 expect('moverect 0..24,0..80 -> 1..25,0..80\nerase 0..1,0..80') 1438 cursor(0, 0, state) 1439 push('\x1b[2T', vt) 1440 expect('moverect 0..23,0..80 -> 2..25,0..80\nerase 0..2,0..80') 1441 cursor(0, 0, state) 1442 1443 -- DECSTBM resets cursor position 1444 push('\x1b[5;5H', vt) 1445 cursor(4, 4, state) 1446 push('\x1b[r', vt) 1447 cursor(0, 0, state) 1448 end) 1449 1450 itp('13state_edit', function() 1451 local vt = init() 1452 local state = wantstate(vt, { s = true, e = true, b = true }) 1453 1454 -- ICH 1455 reset(state, nil) 1456 expect('erase 0..25,0..80') 1457 cursor(0, 0, state) 1458 push('ACD', vt) 1459 push('\x1b[2D', vt) 1460 cursor(0, 1, state) 1461 push('\x1b[@', vt) 1462 expect('scrollrect 0..1,1..80 => +0,-1') 1463 cursor(0, 1, state) 1464 push('B', vt) 1465 cursor(0, 2, state) 1466 push('\x1b[3@', vt) 1467 expect('scrollrect 0..1,2..80 => +0,-3') 1468 1469 -- ICH with DECSLRM 1470 push('\x1b[?69h', vt) 1471 push('\x1b[;50s', vt) 1472 push('\x1b[20G\x1b[@', vt) 1473 expect('scrollrect 0..1,19..50 => +0,-1') 1474 1475 -- ICH outside DECSLRM 1476 push('\x1b[70G\x1b[@', vt) 1477 -- nothing happens 1478 1479 -- DCH 1480 reset(state, nil) 1481 expect('erase 0..25,0..80') 1482 cursor(0, 0, state) 1483 push('ABBC', vt) 1484 push('\x1b[3D', vt) 1485 cursor(0, 1, state) 1486 push('\x1b[P', vt) 1487 expect('scrollrect 0..1,1..80 => +0,+1') 1488 cursor(0, 1, state) 1489 push('\x1b[3P', vt) 1490 expect('scrollrect 0..1,1..80 => +0,+3') 1491 cursor(0, 1, state) 1492 1493 -- DCH with DECSLRM 1494 push('\x1b[?69h', vt) 1495 push('\x1b[;50s', vt) 1496 push('\x1b[20G\x1b[P', vt) 1497 expect('scrollrect 0..1,19..50 => +0,+1') 1498 1499 -- DCH outside DECSLRM 1500 push('\x1b[70G\x1b[P', vt) 1501 -- nothing happens 1502 1503 -- ECH 1504 reset(state, nil) 1505 expect('erase 0..25,0..80') 1506 cursor(0, 0, state) 1507 push('ABC', vt) 1508 push('\x1b[2D', vt) 1509 cursor(0, 1, state) 1510 push('\x1b[X', vt) 1511 expect('erase 0..1,1..2') 1512 cursor(0, 1, state) 1513 push('\x1b[3X', vt) 1514 expect('erase 0..1,1..4') 1515 cursor(0, 1, state) 1516 -- ECH more columns than there are should be bounded 1517 push('\x1b[100X', vt) 1518 expect('erase 0..1,1..80') 1519 1520 -- IL 1521 reset(state, nil) 1522 expect('erase 0..25,0..80') 1523 cursor(0, 0, state) 1524 push('A\r\nC', vt) 1525 cursor(1, 1, state) 1526 push('\x1b[L', vt) 1527 expect('scrollrect 1..25,0..80 => -1,+0') 1528 -- TODO(libvterm): ECMA-48 says we should move to line home, but neither xterm nor xfce4-terminal do this 1529 cursor(1, 1, state) 1530 push('\rB', vt) 1531 cursor(1, 1, state) 1532 push('\x1b[3L', vt) 1533 expect('scrollrect 1..25,0..80 => -3,+0') 1534 1535 -- IL with DECSTBM 1536 push('\x1b[5;15r', vt) 1537 push('\x1b[5H\x1b[L', vt) 1538 expect('scrollrect 4..15,0..80 => -1,+0') 1539 1540 -- IL outside DECSTBM 1541 push('\x1b[20H\x1b[L', vt) 1542 -- nothing happens 1543 1544 -- IL with DECSTBM+DECSLRM 1545 push('\x1b[?69h', vt) 1546 push('\x1b[10;50s', vt) 1547 push('\x1b[5;10H\x1b[L', vt) 1548 expect('scrollrect 4..15,9..50 => -1,+0') 1549 1550 -- DL 1551 reset(state, nil) 1552 expect('erase 0..25,0..80') 1553 cursor(0, 0, state) 1554 push('A\r\nB\r\nB\r\nC', vt) 1555 cursor(3, 1, state) 1556 push('\x1b[2H', vt) 1557 cursor(1, 0, state) 1558 push('\x1b[M', vt) 1559 expect('scrollrect 1..25,0..80 => +1,+0') 1560 cursor(1, 0, state) 1561 push('\x1b[3M', vt) 1562 expect('scrollrect 1..25,0..80 => +3,+0') 1563 cursor(1, 0, state) 1564 1565 -- DL with DECSTBM 1566 push('\x1b[5;15r', vt) 1567 push('\x1b[5H\x1b[M', vt) 1568 expect('scrollrect 4..15,0..80 => +1,+0') 1569 1570 -- DL outside DECSTBM 1571 push('\x1b[20H\x1b[M', vt) 1572 -- nothing happens 1573 1574 -- DL with DECSTBM+DECSLRM 1575 push('\x1b[?69h', vt) 1576 push('\x1b[10;50s', vt) 1577 push('\x1b[5;10H\x1b[M', vt) 1578 expect('scrollrect 4..15,9..50 => +1,+0') 1579 1580 -- DECIC 1581 reset(state, nil) 1582 expect('erase 0..25,0..80') 1583 push("\x1b[20G\x1b[5'}", vt) 1584 expect('scrollrect 0..25,19..80 => +0,-5') 1585 1586 -- DECIC with DECSTBM+DECSLRM 1587 push('\x1b[?69h', vt) 1588 push('\x1b[4;20r\x1b[20;60s', vt) 1589 push("\x1b[4;20H\x1b[3'}", vt) 1590 expect('scrollrect 3..20,19..60 => +0,-3') 1591 1592 -- DECIC outside DECSLRM 1593 push("\x1b[70G\x1b['}", vt) 1594 -- nothing happens 1595 1596 -- DECDC 1597 reset(state, nil) 1598 expect('erase 0..25,0..80') 1599 push("\x1b[20G\x1b[5'~", vt) 1600 expect('scrollrect 0..25,19..80 => +0,+5') 1601 1602 -- DECDC with DECSTBM+DECSLRM 1603 push('\x1b[?69h', vt) 1604 push('\x1b[4;20r\x1b[20;60s', vt) 1605 push("\x1b[4;20H\x1b[3'~", vt) 1606 expect('scrollrect 3..20,19..60 => +0,+3') 1607 1608 -- DECDC outside DECSLRM 1609 push("\x1b[70G\x1b['~", vt) 1610 -- nothing happens 1611 1612 -- EL 0 1613 reset(state, nil) 1614 expect('erase 0..25,0..80') 1615 cursor(0, 0, state) 1616 push('ABCDE', vt) 1617 push('\x1b[3D', vt) 1618 cursor(0, 2, state) 1619 push('\x1b[0K', vt) 1620 expect('erase 0..1,2..80') 1621 cursor(0, 2, state) 1622 1623 -- EL 1 1624 reset(state, nil) 1625 expect('erase 0..25,0..80') 1626 cursor(0, 0, state) 1627 push('ABCDE', vt) 1628 push('\x1b[3D', vt) 1629 cursor(0, 2, state) 1630 push('\x1b[1K', vt) 1631 expect('erase 0..1,0..3') 1632 cursor(0, 2, state) 1633 1634 -- EL 2 1635 reset(state, nil) 1636 expect('erase 0..25,0..80') 1637 cursor(0, 0, state) 1638 push('ABCDE', vt) 1639 push('\x1b[3D', vt) 1640 cursor(0, 2, state) 1641 push('\x1b[2K', vt) 1642 expect('erase 0..1,0..80') 1643 cursor(0, 2, state) 1644 1645 -- SEL 1646 reset(state, nil) 1647 expect('erase 0..25,0..80') 1648 cursor(0, 0, state) 1649 push('\x1b[11G', vt) 1650 cursor(0, 10, state) 1651 push('\x1b[?0K', vt) 1652 expect('erase 0..1,10..80 selective') 1653 cursor(0, 10, state) 1654 push('\x1b[?1K', vt) 1655 expect('erase 0..1,0..11 selective') 1656 cursor(0, 10, state) 1657 push('\x1b[?2K', vt) 1658 expect('erase 0..1,0..80 selective') 1659 cursor(0, 10, state) 1660 1661 -- ED 0 1662 reset(state, nil) 1663 expect('erase 0..25,0..80') 1664 cursor(0, 0, state) 1665 push('\x1b[2;2H', vt) 1666 cursor(1, 1, state) 1667 push('\x1b[0J', vt) 1668 expect('erase 1..2,1..80\nerase 2..25,0..80') 1669 cursor(1, 1, state) 1670 1671 -- ED 1 1672 reset(state, nil) 1673 expect('erase 0..25,0..80') 1674 cursor(0, 0, state) 1675 push('\x1b[2;2H', vt) 1676 cursor(1, 1, state) 1677 push('\x1b[1J', vt) 1678 expect('erase 0..1,0..80\nerase 1..2,0..2') 1679 cursor(1, 1, state) 1680 1681 -- ED 2 1682 reset(state, nil) 1683 expect('erase 0..25,0..80') 1684 cursor(0, 0, state) 1685 push('\x1b[2;2H', vt) 1686 cursor(1, 1, state) 1687 push('\x1b[2J', vt) 1688 expect('erase 0..25,0..80') 1689 cursor(1, 1, state) 1690 1691 -- ED 3 1692 push('\x1b[3J', vt) 1693 expect('sb_clear') 1694 1695 -- SED 1696 reset(state, nil) 1697 expect('erase 0..25,0..80') 1698 push('\x1b[5;5H', vt) 1699 cursor(4, 4, state) 1700 push('\x1b[?0J', vt) 1701 expect('erase 4..5,4..80 selective\nerase 5..25,0..80 selective') 1702 cursor(4, 4, state) 1703 push('\x1b[?1J', vt) 1704 expect('erase 0..4,0..80 selective\nerase 4..5,0..5 selective') 1705 cursor(4, 4, state) 1706 push('\x1b[?2J', vt) 1707 expect('erase 0..25,0..80 selective') 1708 cursor(4, 4, state) 1709 1710 -- DECRQSS on DECSCA 1711 push('\x1b[2"q', vt) 1712 push('\x1bP$q"q\x1b\\', vt) 1713 expect_output('\x1bP1$r2"q\x1b\\') 1714 1715 state = wantstate(vt, { m = true, e = true, b = true }) 1716 expect('erase 0..25,0..80') -- TODO(dundargoc): strange, this should not be needed according to the original code 1717 1718 -- ICH move+erase emuation 1719 reset(state, nil) 1720 expect('erase 0..25,0..80') 1721 cursor(0, 0, state) 1722 push('ACD', vt) 1723 push('\x1b[2D', vt) 1724 cursor(0, 1, state) 1725 push('\x1b[@', vt) 1726 expect('moverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2') 1727 cursor(0, 1, state) 1728 push('B', vt) 1729 cursor(0, 2, state) 1730 push('\x1b[3@', vt) 1731 expect('moverect 0..1,2..77 -> 0..1,5..80\nerase 0..1,2..5') 1732 1733 -- DCH move+erase emulation 1734 reset(state, nil) 1735 expect('erase 0..25,0..80') 1736 cursor(0, 0, state) 1737 push('ABBC', vt) 1738 push('\x1b[3D', vt) 1739 cursor(0, 1, state) 1740 push('\x1b[P', vt) 1741 expect('moverect 0..1,2..80 -> 0..1,1..79\nerase 0..1,79..80') 1742 cursor(0, 1, state) 1743 push('\x1b[3P', vt) 1744 expect('moverect 0..1,4..80 -> 0..1,1..77\nerase 0..1,77..80') 1745 cursor(0, 1, state) 1746 end) 1747 1748 itp('14state_encoding', function() 1749 local vt = init() 1750 vterm.vterm_set_utf8(vt, false) 1751 local state = wantstate(vt, { g = true }) 1752 1753 -- Default 1754 reset(state, nil) 1755 push('#', vt) 1756 expect('putglyph 23 1 0,0') 1757 1758 -- Designate G0=DEC drawing 1759 reset(state, nil) 1760 push('\x1b(0', vt) 1761 push('a', vt) 1762 expect('putglyph 2592 1 0,0') 1763 1764 -- Designate G1 + LS1 1765 reset(state, nil) 1766 push('\x1b)0', vt) 1767 push('a', vt) 1768 expect('putglyph 61 1 0,0') 1769 push('\x0e', vt) 1770 push('a', vt) 1771 expect('putglyph 2592 1 0,1') 1772 -- LS0 1773 push('\x0f', vt) 1774 push('a', vt) 1775 expect('putglyph 61 1 0,2') 1776 1777 -- Designate G2 + LS2 1778 push('\x1b*0', vt) 1779 push('a', vt) 1780 expect('putglyph 61 1 0,3') 1781 push('\x1bn', vt) 1782 push('a', vt) 1783 expect('putglyph 2592 1 0,4') 1784 push('\x0f', vt) 1785 push('a', vt) 1786 expect('putglyph 61 1 0,5') 1787 1788 -- Designate G3 + LS3 1789 push('\x1b+0', vt) 1790 push('a', vt) 1791 expect('putglyph 61 1 0,6') 1792 push('\x1bo', vt) 1793 push('a', vt) 1794 expect('putglyph 2592 1 0,7') 1795 push('\x0f', vt) 1796 push('a', vt) 1797 expect('putglyph 61 1 0,8') 1798 1799 -- SS2 1800 push('a\x8eaa', vt) 1801 expect('putglyph 61 1 0,9\nputglyph 2592 1 0,10\nputglyph 61 1 0,11') 1802 1803 -- SS3 1804 push('a\x8faa', vt) 1805 expect('putglyph 61 1 0,12\nputglyph 2592 1 0,13\nputglyph 61 1 0,14') 1806 1807 -- LS1R 1808 reset(state, nil) 1809 push('\x1b~', vt) 1810 push('\xe1', vt) 1811 expect('putglyph 61 1 0,0') 1812 push('\x1b)0', vt) 1813 push('\xe1', vt) 1814 expect('putglyph 2592 1 0,1') 1815 1816 -- LS2R 1817 reset(state, nil) 1818 push('\x1b}', vt) 1819 push('\xe1', vt) 1820 expect('putglyph 61 1 0,0') 1821 push('\x1b*0', vt) 1822 push('\xe1', vt) 1823 expect('putglyph 2592 1 0,1') 1824 1825 -- LS3R 1826 reset(state, nil) 1827 push('\x1b|', vt) 1828 push('\xe1', vt) 1829 expect('putglyph 61 1 0,0') 1830 push('\x1b+0', vt) 1831 push('\xe1', vt) 1832 expect('putglyph 2592 1 0,1') 1833 1834 vterm.vterm_set_utf8(vt, true) 1835 1836 -- Mixed US-ASCII and UTF-8 1837 -- U+0108 == c4 88 1838 reset(state, nil) 1839 push('\x1b(B', vt) 1840 push('AB\xc4\x88D', vt) 1841 expect('putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 108 1 0,2\nputglyph 44 1 0,3') 1842 1843 -- Split UTF-8 after US-ASCII 1844 reset(state, nil) 1845 push('AB\xc4', vt) 1846 expect('putglyph 41 1 0,0\nputglyph 42 1 0,1') 1847 push('\x88D', vt) 1848 expect('putglyph 108 1 0,2\nputglyph 44 1 0,3') 1849 end) 1850 1851 itp('15state_mode', function() 1852 local vt = init() 1853 local state = wantstate(vt, { g = true, m = true, e = true }) 1854 1855 -- Insert/Replace Mode 1856 reset(state, nil) 1857 expect('erase 0..25,0..80') 1858 cursor(0, 0, state) 1859 push('AC\x1b[DB', vt) 1860 expect('putglyph 41 1 0,0\nputglyph 43 1 0,1\nputglyph 42 1 0,1') 1861 push('\x1b[4h', vt) 1862 push('\x1b[G', vt) 1863 push('AC\x1b[DB', vt) 1864 expect( 1865 'moverect 0..1,0..79 -> 0..1,1..80\nerase 0..1,0..1\nputglyph 41 1 0,0\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 43 1 0,1\nmoverect 0..1,1..79 -> 0..1,2..80\nerase 0..1,1..2\nputglyph 42 1 0,1' 1866 ) 1867 1868 -- Insert mode only happens once for UTF-8 combining 1869 push('e', vt) 1870 expect('moverect 0..1,2..79 -> 0..1,3..80\nerase 0..1,2..3\nputglyph 65 1 0,2') 1871 push('\xCC\x81', vt) 1872 expect('putglyph 65,301 1 0,2') 1873 1874 -- Newline/Linefeed mode 1875 reset(state, nil) 1876 expect('erase 0..25,0..80') 1877 cursor(0, 0, state) 1878 push('\x1b[5G\n', vt) 1879 cursor(1, 4, state) 1880 push('\x1b[20h', vt) 1881 push('\x1b[5G\n', vt) 1882 cursor(2, 0, state) 1883 1884 -- DEC origin mode 1885 reset(state, nil) 1886 expect('erase 0..25,0..80') 1887 cursor(0, 0, state) 1888 push('\x1b[5;15r', vt) 1889 push('\x1b[H', vt) 1890 cursor(0, 0, state) 1891 push('\x1b[3;3H', vt) 1892 cursor(2, 2, state) 1893 push('\x1b[?6h', vt) 1894 push('\x1b[H', vt) 1895 cursor(4, 0, state) 1896 push('\x1b[3;3H', vt) 1897 cursor(6, 2, state) 1898 1899 -- DECRQM on DECOM 1900 push('\x1b[?6h', vt) 1901 push('\x1b[?6$p', vt) 1902 expect_output('\x1b[?6;1$y') 1903 push('\x1b[?6l', vt) 1904 push('\x1b[?6$p', vt) 1905 expect_output('\x1b[?6;2$y') 1906 1907 -- Origin mode with DECSLRM 1908 push('\x1b[?6h', vt) 1909 push('\x1b[?69h', vt) 1910 push('\x1b[20;60s', vt) 1911 push('\x1b[H', vt) 1912 cursor(4, 19, state) 1913 1914 push('\x1b[?69l', vt) 1915 1916 -- Origin mode bounds cursor to scrolling region 1917 push('\x1b[H', vt) 1918 push('\x1b[10A', vt) 1919 cursor(4, 0, state) 1920 push('\x1b[20B', vt) 1921 cursor(14, 0, state) 1922 1923 -- Origin mode without scroll region 1924 push('\x1b[?6l', vt) 1925 push('\x1b[r\x1b[?6h', vt) 1926 cursor(0, 0, state) 1927 end) 1928 1929 itp('16state_resize', function() 1930 local vt = init() 1931 local state = wantstate(vt, { g = true }) 1932 1933 -- Placement 1934 reset(state, nil) 1935 push('AB\x1b[79GCDE', vt) 1936 expect( 1937 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 1,0' 1938 ) 1939 1940 -- Resize 1941 reset(state, nil) 1942 resize(27, 85, vt) 1943 push('AB\x1b[79GCDE', vt) 1944 expect( 1945 'putglyph 41 1 0,0\nputglyph 42 1 0,1\nputglyph 43 1 0,78\nputglyph 44 1 0,79\nputglyph 45 1 0,80' 1946 ) 1947 cursor(0, 81, state) 1948 1949 -- Resize without reset 1950 resize(28, 90, vt) 1951 cursor(0, 81, state) 1952 push('FGHI', vt) 1953 expect('putglyph 46 1 0,81\nputglyph 47 1 0,82\nputglyph 48 1 0,83\nputglyph 49 1 0,84') 1954 cursor(0, 85, state) 1955 1956 -- Resize shrink moves cursor 1957 resize(25, 80, vt) 1958 cursor(0, 79, state) 1959 1960 -- Resize grow doesn't cancel phantom 1961 reset(state, nil) 1962 push('\x1b[79GAB', vt) 1963 expect('putglyph 41 1 0,78\nputglyph 42 1 0,79') 1964 cursor(0, 79, state) 1965 resize(30, 100, vt) 1966 cursor(0, 80, state) 1967 push('C', vt) 1968 expect('putglyph 43 1 0,80') 1969 cursor(0, 81, state) 1970 end) 1971 1972 itp('17state_mouse', function() 1973 local vt = init() 1974 local state = wantstate(vt, { p = true }) 1975 1976 -- DECRQM on with mouse off 1977 push('\x1b[?1000$p', vt) 1978 expect_output('\x1b[?1000;2$y') 1979 push('\x1b[?1002$p', vt) 1980 expect_output('\x1b[?1002;2$y') 1981 push('\x1b[?1003$p', vt) 1982 expect_output('\x1b[?1003;2$y') 1983 1984 -- Mouse in simple button report mode 1985 reset(state, nil) 1986 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 1987 push('\x1b[?1000h', vt) 1988 expect('settermprop 8 1') 1989 1990 -- Press 1 1991 mousemove(0, 0, vt) 1992 mousebtn('d', 1, vt) 1993 expect_output('\x1b[M\x20\x21\x21') 1994 1995 -- Release 1 1996 mousebtn('u', 1, vt) 1997 expect_output('\x1b[M\x23\x21\x21') 1998 1999 -- Ctrl-Press 1 2000 mousebtn('d', 1, vt, { C = true }) 2001 expect_output('\x1b[M\x30\x21\x21') 2002 mousebtn('u', 1, vt, { C = true }) 2003 expect_output('\x1b[M\x33\x21\x21') 2004 2005 -- Button 2 2006 mousebtn('d', 2, vt) 2007 expect_output('\x1b[M\x21\x21\x21') 2008 mousebtn('u', 2, vt) 2009 expect_output('\x1b[M\x23\x21\x21') 2010 2011 -- Position 2012 mousemove(10, 20, vt) 2013 mousebtn('d', 1, vt) 2014 expect_output('\x1b[M\x20\x35\x2b') 2015 2016 mousebtn('u', 1, vt) 2017 expect_output('\x1b[M\x23\x35\x2b') 2018 mousemove(10, 21, vt) 2019 -- no output 2020 2021 -- Wheel events 2022 mousebtn('d', 4, vt) 2023 expect_output('\x1b[M\x60\x36\x2b') 2024 mousebtn('d', 4, vt) 2025 expect_output('\x1b[M\x60\x36\x2b') 2026 mousebtn('d', 5, vt) 2027 expect_output('\x1b[M\x61\x36\x2b') 2028 mousebtn('d', 6, vt) 2029 expect_output('\x1b[M\x62\x36\x2b') 2030 mousebtn('d', 7, vt) 2031 expect_output('\x1b[M\x63\x36\x2b') 2032 2033 -- DECRQM on mouse button mode 2034 push('\x1b[?1000$p', vt) 2035 expect_output('\x1b[?1000;1$y') 2036 push('\x1b[?1002$p', vt) 2037 expect_output('\x1b[?1002;2$y') 2038 push('\x1b[?1003$p', vt) 2039 expect_output('\x1b[?1003;2$y') 2040 2041 -- Drag events 2042 reset(state, nil) 2043 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2044 push('\x1b[?1002h', vt) 2045 expect('settermprop 8 2') 2046 2047 mousemove(5, 5, vt) 2048 mousebtn('d', 1, vt) 2049 expect_output('\x1b[M\x20\x26\x26') 2050 mousemove(5, 6, vt) 2051 expect_output('\x1b[M\x40\x27\x26') 2052 mousemove(6, 6, vt) 2053 expect_output('\x1b[M\x40\x27\x27') 2054 mousemove(6, 6, vt) 2055 -- no output 2056 mousebtn('u', 1, vt) 2057 expect_output('\x1b[M\x23\x27\x27') 2058 mousemove(6, 7, vt) 2059 -- no output 2060 2061 -- DECRQM on mouse drag mode 2062 push('\x1b[?1000$p', vt) 2063 expect_output('\x1b[?1000;2$y') 2064 push('\x1b[?1002$p', vt) 2065 expect_output('\x1b[?1002;1$y') 2066 push('\x1b[?1003$p', vt) 2067 expect_output('\x1b[?1003;2$y') 2068 2069 -- Non-drag motion events 2070 push('\x1b[?1003h', vt) 2071 expect('settermprop 8 3') 2072 2073 mousemove(6, 8, vt) 2074 expect_output('\x1b[M\x43\x29\x27') 2075 2076 -- DECRQM on mouse motion mode 2077 push('\x1b[?1000$p', vt) 2078 expect_output('\x1b[?1000;2$y') 2079 push('\x1b[?1002$p', vt) 2080 expect_output('\x1b[?1002;2$y') 2081 push('\x1b[?1003$p', vt) 2082 expect_output('\x1b[?1003;1$y') 2083 2084 -- Bounds checking 2085 mousemove(300, 300, vt) 2086 expect_output('\x1b[M\x43\xff\xff') 2087 mousebtn('d', 1, vt) 2088 expect_output('\x1b[M\x20\xff\xff') 2089 mousebtn('u', 1, vt) 2090 expect_output('\x1b[M\x23\xff\xff') 2091 2092 -- DECRQM on standard encoding mode 2093 push('\x1b[?1005$p', vt) 2094 expect_output('\x1b[?1005;2$y') 2095 push('\x1b[?1006$p', vt) 2096 expect_output('\x1b[?1006;2$y') 2097 push('\x1b[?1015$p', vt) 2098 expect_output('\x1b[?1015;2$y') 2099 2100 -- UTF-8 extended encoding mode 2101 -- 300 + 32 + 1 = 333 = U+014d = \xc5\x8d 2102 push('\x1b[?1005h', vt) 2103 mousebtn('d', 1, vt) 2104 expect_output('\x1b[M\x20\xc5\x8d\xc5\x8d') 2105 mousebtn('u', 1, vt) 2106 expect_output('\x1b[M\x23\xc5\x8d\xc5\x8d') 2107 2108 -- DECRQM on UTF-8 extended encoding mode 2109 push('\x1b[?1005$p', vt) 2110 expect_output('\x1b[?1005;1$y') 2111 push('\x1b[?1006$p', vt) 2112 expect_output('\x1b[?1006;2$y') 2113 push('\x1b[?1015$p', vt) 2114 expect_output('\x1b[?1015;2$y') 2115 2116 -- SGR extended encoding mode 2117 push('\x1b[?1006h', vt) 2118 mousebtn('d', 1, vt) 2119 expect_output('\x1b[<0;301;301M') 2120 mousebtn('u', 1, vt) 2121 expect_output('\x1b[<0;301;301m') 2122 2123 -- Button 8 on SGR extended encoding mode 2124 mousebtn('d', 8, vt) 2125 expect_output('\x1b[<128;301;301M') 2126 mousebtn('u', 8, vt) 2127 expect_output('\x1b[<128;301;301m') 2128 2129 -- Button 9 on SGR extended encoding mode 2130 mousebtn('d', 9, vt) 2131 expect_output('\x1b[<129;301;301M') 2132 mousebtn('u', 9, vt) 2133 expect_output('\x1b[<129;301;301m') 2134 2135 -- DECRQM on SGR extended encoding mode 2136 push('\x1b[?1005$p', vt) 2137 expect_output('\x1b[?1005;2$y') 2138 push('\x1b[?1006$p', vt) 2139 expect_output('\x1b[?1006;1$y') 2140 push('\x1b[?1015$p', vt) 2141 expect_output('\x1b[?1015;2$y') 2142 2143 -- rxvt extended encoding mode 2144 push('\x1b[?1015h', vt) 2145 mousebtn('d', 1, vt) 2146 expect_output('\x1b[0;301;301M') 2147 mousebtn('u', 1, vt) 2148 expect_output('\x1b[3;301;301M') 2149 2150 -- Button 8 on rxvt extended encoding mode 2151 mousebtn('d', 8, vt) 2152 expect_output('\x1b[128;301;301M') 2153 mousebtn('u', 8, vt) 2154 expect_output('\x1b[3;301;301M') 2155 2156 -- Button 9 on rxvt extended encoding mode 2157 mousebtn('d', 9, vt) 2158 expect_output('\x1b[129;301;301M') 2159 mousebtn('u', 9, vt) 2160 expect_output('\x1b[3;301;301M') 2161 2162 -- DECRQM on rxvt extended encoding mode 2163 push('\x1b[?1005$p', vt) 2164 expect_output('\x1b[?1005;2$y') 2165 push('\x1b[?1006$p', vt) 2166 expect_output('\x1b[?1006;2$y') 2167 push('\x1b[?1015$p', vt) 2168 expect_output('\x1b[?1015;1$y') 2169 2170 -- Mouse disabled reports nothing 2171 reset(state, nil) 2172 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2173 mousemove(0, 0, vt) 2174 mousebtn('d', 1, vt) 2175 mousebtn('u', 1, vt) 2176 2177 -- DECSM can set multiple modes at once 2178 push('\x1b[?1002;1006h', vt) 2179 expect('settermprop 8 2') 2180 mousebtn('d', 1, vt) 2181 expect_output('\x1b[<0;1;1M') 2182 end) 2183 2184 itp('18state_termprops', function() 2185 local vt = init() 2186 local state = wantstate(vt, { p = true }) 2187 2188 reset(state, nil) 2189 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2190 2191 -- Cursor visibility 2192 push('\x1b[?25h', vt) 2193 expect('settermprop 1 true') 2194 push('\x1b[?25$p', vt) 2195 expect_output('\x1b[?25;1$y') 2196 push('\x1b[?25l', vt) 2197 expect('settermprop 1 false') 2198 push('\x1b[?25$p', vt) 2199 expect_output('\x1b[?25;2$y') 2200 2201 -- Cursor blink 2202 push('\x1b[?12h', vt) 2203 expect('settermprop 2 true') 2204 push('\x1b[?12$p', vt) 2205 expect_output('\x1b[?12;1$y') 2206 push('\x1b[?12l', vt) 2207 expect('settermprop 2 false') 2208 push('\x1b[?12$p', vt) 2209 expect_output('\x1b[?12;2$y') 2210 2211 -- Cursor shape 2212 push('\x1b[3 q', vt) 2213 expect('settermprop 2 true\nsettermprop 7 2') 2214 2215 -- Title 2216 push('\x1b]2;Here is my title\a', vt) 2217 expect('settermprop 4 ["Here is my title"]') 2218 2219 -- Title split write 2220 push('\x1b]2;Here is', vt) 2221 expect('settermprop 4 ["Here is"') 2222 push(' another title\a', vt) 2223 expect('settermprop 4 " another title"]') 2224 end) 2225 2226 itp('20state_wrapping', function() 2227 local vt = init() 2228 local state = wantstate(vt, { g = true, m = true }) 2229 2230 -- 79th Column 2231 push('\x1b[75G', vt) 2232 push(string.rep('A', 5), vt) 2233 expect( 2234 'putglyph 41 1 0,74\nputglyph 41 1 0,75\nputglyph 41 1 0,76\nputglyph 41 1 0,77\nputglyph 41 1 0,78' 2235 ) 2236 cursor(0, 79, state) 2237 2238 -- 80th Column Phantom 2239 push('A', vt) 2240 expect('putglyph 41 1 0,79') 2241 cursor(0, 79, state) 2242 2243 -- Line Wraparound 2244 push('B', vt) 2245 expect('putglyph 42 1 1,0') 2246 cursor(1, 1, state) 2247 2248 -- Line Wraparound during combined write 2249 push('\x1b[78G', vt) 2250 push('BBBCC', vt) 2251 expect( 2252 'putglyph 42 1 1,77\nputglyph 42 1 1,78\nputglyph 42 1 1,79\nputglyph 43 1 2,0\nputglyph 43 1 2,1' 2253 ) 2254 cursor(2, 2, state) 2255 2256 -- DEC Auto Wrap Mode 2257 reset(state, nil) 2258 push('\x1b[?7l', vt) 2259 push('\x1b[75G', vt) 2260 push(string.rep('D', 6), vt) 2261 expect( 2262 'putglyph 44 1 0,74\nputglyph 44 1 0,75\nputglyph 44 1 0,76\nputglyph 44 1 0,77\nputglyph 44 1 0,78\nputglyph 44 1 0,79' 2263 ) 2264 cursor(0, 79, state) 2265 push('D', vt) 2266 expect('putglyph 44 1 0,79') 2267 cursor(0, 79, state) 2268 push('\x1b[?7h', vt) 2269 2270 -- 80th column causes linefeed on wraparound 2271 push('\x1b[25;78HABC', vt) 2272 expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79') 2273 cursor(24, 79, state) 2274 push('D', vt) 2275 expect('moverect 1..25,0..80 -> 0..24,0..80\nputglyph 44 1 24,0') 2276 2277 -- 80th column phantom linefeed phantom cancelled by explicit cursor move 2278 push('\x1b[25;78HABC', vt) 2279 expect('putglyph 41 1 24,77\nputglyph 42 1 24,78\nputglyph 43 1 24,79') 2280 cursor(24, 79, state) 2281 push('\x1b[25;1HD', vt) 2282 expect('putglyph 44 1 24,0') 2283 end) 2284 2285 itp('21state_tabstops', function() 2286 local vt = init() 2287 local state = wantstate(vt, { g = true }) 2288 2289 -- Initial 2290 reset(state, nil) 2291 push('\tX', vt) 2292 expect('putglyph 58 1 0,8') 2293 push('\tX', vt) 2294 expect('putglyph 58 1 0,16') 2295 cursor(0, 17, state) 2296 2297 -- HTS 2298 push('\x1b[5G\x1bH', vt) 2299 push('\x1b[G\tX', vt) 2300 expect('putglyph 58 1 0,4') 2301 cursor(0, 5, state) 2302 2303 -- TBC 0 2304 push('\x1b[9G\x1b[g', vt) 2305 push('\x1b[G\tX\tX', vt) 2306 expect('putglyph 58 1 0,4\nputglyph 58 1 0,16') 2307 cursor(0, 17, state) 2308 2309 -- TBC 3 2310 push('\x1b[3g\x1b[50G\x1bH\x1b[G', vt) 2311 cursor(0, 0, state) 2312 push('\tX', vt) 2313 expect('putglyph 58 1 0,49') 2314 cursor(0, 50, state) 2315 2316 -- Tabstops after resize 2317 reset(state, nil) 2318 resize(30, 100, vt) 2319 -- Should be 100/8 = 12 tabstops 2320 push('\tX', vt) 2321 expect('putglyph 58 1 0,8') 2322 push('\tX', vt) 2323 expect('putglyph 58 1 0,16') 2324 push('\tX', vt) 2325 expect('putglyph 58 1 0,24') 2326 push('\tX', vt) 2327 expect('putglyph 58 1 0,32') 2328 push('\tX', vt) 2329 expect('putglyph 58 1 0,40') 2330 push('\tX', vt) 2331 expect('putglyph 58 1 0,48') 2332 push('\tX', vt) 2333 expect('putglyph 58 1 0,56') 2334 push('\tX', vt) 2335 expect('putglyph 58 1 0,64') 2336 push('\tX', vt) 2337 expect('putglyph 58 1 0,72') 2338 push('\tX', vt) 2339 expect('putglyph 58 1 0,80') 2340 push('\tX', vt) 2341 expect('putglyph 58 1 0,88') 2342 push('\tX', vt) 2343 expect('putglyph 58 1 0,96') 2344 cursor(0, 97, state) 2345 end) 2346 2347 itp('22state_save', function() 2348 local vt = init() 2349 local state = wantstate(vt, { p = true }) 2350 2351 reset(state, nil) 2352 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2353 2354 -- Set up state 2355 push('\x1b[2;2H', vt) 2356 cursor(1, 1, state) 2357 push('\x1b[1m', vt) 2358 pen('bold', true, state) 2359 2360 -- Save 2361 push('\x1b[?1048h', vt) 2362 2363 -- Change state 2364 push('\x1b[5;5H', vt) 2365 cursor(4, 4, state) 2366 push('\x1b[4 q', vt) 2367 expect('settermprop 2 false\nsettermprop 7 2') 2368 push('\x1b[22;4m', vt) 2369 pen('bold', false, state) 2370 pen('underline', 1, state) 2371 2372 -- Restore 2373 push('\x1b[?1048l', vt) 2374 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2375 cursor(1, 1, state) 2376 pen('bold', true, state) 2377 pen('underline', 0, state) 2378 2379 -- Save/restore using DECSC/DECRC 2380 push('\x1b[2;2H\x1b7', vt) 2381 cursor(1, 1, state) 2382 2383 push('\x1b[5;5H', vt) 2384 cursor(4, 4, state) 2385 push('\x1b8', vt) 2386 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2387 cursor(1, 1, state) 2388 2389 -- Save twice, restore twice happens on both edge transitions 2390 push('\x1b[2;10H\x1b[?1048h\x1b[6;10H\x1b[?1048h', vt) 2391 push('\x1b[H', vt) 2392 cursor(0, 0, state) 2393 push('\x1b[?1048l', vt) 2394 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2395 cursor(5, 9, state) 2396 push('\x1b[H', vt) 2397 cursor(0, 0, state) 2398 push('\x1b[?1048l', vt) 2399 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 2400 cursor(5, 9, state) 2401 end) 2402 2403 itp('25state_input', function() 2404 local vt = init() 2405 local state = wantstate(vt) 2406 2407 -- Disambiguate escape codes enabled 2408 push('\x1b[>1u', vt) 2409 2410 -- Unmodified ASCII 2411 inchar(0x41, vt) 2412 expect_output('A') 2413 inchar(0x61, vt) 2414 expect_output('a') 2415 2416 -- Ctrl modifier on ASCII letters 2417 inchar(0x41, vt, { C = true }) 2418 expect_output('\x1b[97;6u') 2419 inchar(0x61, vt, { C = true }) 2420 expect_output('\x1b[97;5u') 2421 2422 -- Alt modifier on ASCII letters 2423 inchar(0x41, vt, { A = true }) 2424 expect_output('\x1b[97;4u') 2425 inchar(0x61, vt, { A = true }) 2426 expect_output('\x1b[97;3u') 2427 2428 -- Ctrl-Alt modifier on ASCII letters 2429 inchar(0x41, vt, { C = true, A = true }) 2430 expect_output('\x1b[97;8u') 2431 inchar(0x61, vt, { C = true, A = true }) 2432 expect_output('\x1b[97;7u') 2433 2434 -- Ctrl-I is disambiguated 2435 inchar(0x49, vt) 2436 expect_output('I') 2437 inchar(0x69, vt) 2438 expect_output('i') 2439 inchar(0x49, vt, { C = true }) 2440 expect_output('\x1b[105;6u') 2441 inchar(0x69, vt, { C = true }) 2442 expect_output('\x1b[105;5u') 2443 inchar(0x49, vt, { A = true }) 2444 expect_output('\x1b[105;4u') 2445 inchar(0x69, vt, { A = true }) 2446 expect_output('\x1b[105;3u') 2447 inchar(0x49, vt, { A = true, C = true }) 2448 expect_output('\x1b[105;8u') 2449 inchar(0x69, vt, { A = true, C = true }) 2450 expect_output('\x1b[105;7u') 2451 2452 -- Ctrl+Digits 2453 for i = 0, 9 do 2454 local c = 0x30 + i 2455 inchar(c, vt) 2456 expect_output(tostring(i)) 2457 inchar(c, vt, { C = true }) 2458 expect_output(string.format('\x1b[%d;5u', c)) 2459 inchar(c, vt, { C = true, S = true }) 2460 expect_output(string.format('\x1b[%d;6u', c)) 2461 inchar(c, vt, { C = true, A = true }) 2462 expect_output(string.format('\x1b[%d;7u', c)) 2463 inchar(c, vt, { C = true, A = true, S = true }) 2464 expect_output(string.format('\x1b[%d;8u', c)) 2465 end 2466 2467 -- Special handling of Space 2468 inchar(0x20, vt) 2469 expect_output(' ') 2470 inchar(0x20, vt, { S = true }) 2471 expect_output('\x1b[32;2u') 2472 inchar(0x20, vt, { C = true }) 2473 expect_output('\x1b[32;5u') 2474 inchar(0x20, vt, { C = true, S = true }) 2475 expect_output('\x1b[32;6u') 2476 inchar(0x20, vt, { A = true }) 2477 expect_output('\x1b[32;3u') 2478 inchar(0x20, vt, { S = true, A = true }) 2479 expect_output('\x1b[32;4u') 2480 inchar(0x20, vt, { C = true, A = true }) 2481 expect_output('\x1b[32;7u') 2482 inchar(0x20, vt, { S = true, C = true, A = true }) 2483 expect_output('\x1b[32;8u') 2484 2485 -- Cursor keys in reset (cursor) mode 2486 inkey('up', vt) 2487 expect_output('\x1b[A') 2488 inkey('up', vt, { S = true }) 2489 expect_output('\x1b[1;2A') 2490 inkey('up', vt, { C = true }) 2491 expect_output('\x1b[1;5A') 2492 inkey('up', vt, { S = true, C = true }) 2493 expect_output('\x1b[1;6A') 2494 inkey('up', vt, { A = true }) 2495 expect_output('\x1b[1;3A') 2496 inkey('up', vt, { S = true, A = true }) 2497 expect_output('\x1b[1;4A') 2498 inkey('up', vt, { C = true, A = true }) 2499 expect_output('\x1b[1;7A') 2500 inkey('up', vt, { S = true, C = true, A = true }) 2501 expect_output('\x1b[1;8A') 2502 2503 -- Cursor keys in application mode 2504 push('\x1b[?1h', vt) 2505 -- Plain "Up" should be SS3 A now 2506 inkey('up', vt) 2507 expect_output('\x1bOA') 2508 -- Modified keys should still use CSI 2509 inkey('up', vt, { S = true }) 2510 expect_output('\x1b[1;2A') 2511 inkey('up', vt, { C = true }) 2512 expect_output('\x1b[1;5A') 2513 2514 -- Tab 2515 inkey('tab', vt) 2516 expect_output('\x09') 2517 inkey('tab', vt, { S = true }) 2518 expect_output('\x1b[9;2u') 2519 inkey('tab', vt, { C = true }) 2520 expect_output('\x1b[9;5u') 2521 inkey('tab', vt, { A = true }) 2522 expect_output('\x1b[9;3u') 2523 inkey('tab', vt, { C = true, A = true }) 2524 expect_output('\x1b[9;7u') 2525 2526 -- Backspace 2527 inkey('bs', vt) 2528 expect_output('\x7f') 2529 inkey('bs', vt, { S = true }) 2530 expect_output('\x1b[127;2u') 2531 inkey('bs', vt, { C = true }) 2532 expect_output('\x1b[127;5u') 2533 inkey('bs', vt, { A = true }) 2534 expect_output('\x1b[127;3u') 2535 inkey('bs', vt, { C = true, A = true }) 2536 expect_output('\x1b[127;7u') 2537 2538 -- DEL 2539 inkey('del', vt) 2540 expect_output('\x1b[3~') 2541 inkey('del', vt, { S = true }) 2542 expect_output('\x1b[3;2~') 2543 inkey('del', vt, { C = true }) 2544 expect_output('\x1b[3;5~') 2545 inkey('del', vt, { A = true }) 2546 expect_output('\x1b[3;3~') 2547 inkey('del', vt, { C = true, A = true }) 2548 expect_output('\x1b[3;7~') 2549 2550 -- ESC 2551 inkey('esc', vt) 2552 expect_output('\x1b[27;1u') 2553 inkey('esc', vt, { S = true }) 2554 expect_output('\x1b[27;2u') 2555 inkey('esc', vt, { C = true }) 2556 expect_output('\x1b[27;5u') 2557 inkey('esc', vt, { A = true }) 2558 expect_output('\x1b[27;3u') 2559 inkey('esc', vt, { C = true, A = true }) 2560 expect_output('\x1b[27;7u') 2561 2562 -- Enter in linefeed mode 2563 inkey('enter', vt) 2564 expect_output('\x0d') 2565 inkey('enter', vt, { S = true }) 2566 expect_output('\x1b[13;2u') 2567 inkey('enter', vt, { C = true }) 2568 expect_output('\x1b[13;5u') 2569 inkey('enter', vt, { A = true }) 2570 expect_output('\x1b[13;3u') 2571 inkey('enter', vt, { C = true, A = true }) 2572 expect_output('\x1b[13;7u') 2573 2574 -- Enter in newline mode 2575 push('\x1b[20h', vt) 2576 inkey('enter', vt) 2577 expect_output('\x0d\x0a') 2578 2579 -- Unmodified F1 is SS3 P 2580 inkey('f1', vt) 2581 expect_output('\x1bOP') 2582 2583 -- Modified F1 is CSI P 2584 inkey('f1', vt, { S = true }) 2585 expect_output('\x1b[1;2P') 2586 inkey('f1', vt, { A = true }) 2587 expect_output('\x1b[1;3P') 2588 inkey('f1', vt, { C = true }) 2589 expect_output('\x1b[1;5P') 2590 2591 -- Keypad in DECKPNM 2592 inkey('kp0', vt) 2593 expect_output('\x1b[57399;1u') 2594 2595 -- Keypad in DECKPAM 2596 push('\x1b=', vt) 2597 inkey('kp0', vt) 2598 expect_output('\x1bOp') 2599 2600 -- Bracketed paste mode off 2601 vterm.vterm_keyboard_start_paste(vt) 2602 vterm.vterm_keyboard_end_paste(vt) 2603 2604 -- Bracketed paste mode on 2605 push('\x1b[?2004h', vt) 2606 vterm.vterm_keyboard_start_paste(vt) 2607 expect_output('\x1b[200~') 2608 vterm.vterm_keyboard_end_paste(vt) 2609 expect_output('\x1b[201~') 2610 2611 -- Focus reporting disabled 2612 vterm.vterm_state_focus_in(state) 2613 vterm.vterm_state_focus_out(state) 2614 2615 -- Focus reporting enabled 2616 state = wantstate(vt, { p = true }) 2617 push('\x1b[?1004h', vt) 2618 expect('settermprop 9 true') 2619 vterm.vterm_state_focus_in(state) 2620 expect_output('\x1b[I') 2621 vterm.vterm_state_focus_out(state) 2622 expect_output('\x1b[O') 2623 2624 -- Disambiguate escape codes disabled 2625 push('\x1b[<u', vt) 2626 2627 -- Unmodified ASCII 2628 inchar(0x41, vt) 2629 expect_output('A') 2630 inchar(0x61, vt) 2631 expect_output('a') 2632 2633 -- Ctrl modifier on ASCII letters 2634 inchar(0x41, vt, { C = true }) 2635 expect_output('\x01') 2636 inchar(0x61, vt, { C = true }) 2637 expect_output('\x01') 2638 2639 -- Alt modifier on ASCII letters 2640 inchar(0x41, vt, { A = true }) 2641 expect_output('\x1bA') 2642 inchar(0x61, vt, { A = true }) 2643 expect_output('\x1ba') 2644 2645 -- Ctrl-Alt modifier on ASCII letters 2646 inchar(0x41, vt, { C = true, A = true }) 2647 expect_output('\x1b\x01') 2648 inchar(0x61, vt, { C = true, A = true }) 2649 expect_output('\x1b\x01') 2650 2651 -- Ctrl-I is ambiguous 2652 inchar(0x49, vt) 2653 expect_output('I') 2654 inchar(0x69, vt) 2655 expect_output('i') 2656 inchar(0x49, vt, { C = true }) 2657 expect_output('\x09') 2658 inchar(0x69, vt, { C = true }) 2659 expect_output('\x09') 2660 inchar(0x49, vt, { A = true }) 2661 expect_output('\x1bI') 2662 inchar(0x69, vt, { A = true }) 2663 expect_output('\x1bi') 2664 inchar(0x49, vt, { A = true, C = true }) 2665 expect_output('\x1b\x09') 2666 inchar(0x69, vt, { A = true, C = true }) 2667 expect_output('\x1b\x09') 2668 2669 -- Ctrl+Digits 2670 inchar(0x30, vt, { C = true }) 2671 expect_output('0') 2672 inchar(0x31, vt, { C = true }) 2673 expect_output('1') 2674 inchar(0x32, vt, { C = true }) 2675 expect_output('\x00') 2676 inchar(0x33, vt, { C = true }) 2677 expect_output('\x1b') 2678 inchar(0x34, vt, { C = true }) 2679 expect_output('\x1c') 2680 inchar(0x35, vt, { C = true }) 2681 expect_output('\x1d') 2682 inchar(0x36, vt, { C = true }) 2683 expect_output('\x1e') 2684 inchar(0x37, vt, { C = true }) 2685 expect_output('\x1f') 2686 inchar(0x38, vt, { C = true }) 2687 expect_output('\x7f') 2688 inchar(0x39, vt, { C = true }) 2689 expect_output('9') 2690 2691 -- Ctrl+/ 2692 inchar(0x2F, vt, { C = true }) 2693 expect_output('\x1f') 2694 end) 2695 2696 itp('26state_query', function() 2697 local vt = init() 2698 local state = wantstate(vt) 2699 2700 -- DA 2701 reset(state, nil) 2702 push('\x1b[c', vt) 2703 expect_output('\x1b[?61;22;52c') 2704 2705 -- XTVERSION 2706 reset(state, nil) 2707 push('\x1b[>q', vt) 2708 expect_output('\x1bP>|libvterm(0.3)\x1b\\') 2709 2710 -- DSR 2711 reset(state, nil) 2712 push('\x1b[5n', vt) 2713 expect_output('\x1b[0n') 2714 2715 -- CPR 2716 push('\x1b[6n', vt) 2717 expect_output('\x1b[1;1R') 2718 push('\x1b[10;10H\x1b[6n', vt) 2719 expect_output('\x1b[10;10R') 2720 2721 -- DECCPR 2722 push('\x1b[?6n', vt) 2723 expect_output('\x1b[?10;10R') 2724 2725 -- DECRQSS on DECSCUSR 2726 push('\x1b[3 q', vt) 2727 push('\x1bP$q q\x1b\\', vt) 2728 expect_output('\x1bP1$r3 q\x1b\\') 2729 2730 -- DECRQSS on SGR 2731 push('\x1b[1;5;7m', vt) 2732 push('\x1bP$qm\x1b\\', vt) 2733 expect_output('\x1bP1$r1;5;7m\x1b\\') 2734 2735 -- DECRQSS on SGR ANSI colours 2736 push('\x1b[0;31;42m', vt) 2737 push('\x1bP$qm\x1b\\', vt) 2738 expect_output('\x1bP1$r31;42m\x1b\\') 2739 2740 -- DECRQSS on SGR ANSI hi-bright colours 2741 push('\x1b[0;93;104m', vt) 2742 push('\x1bP$qm\x1b\\', vt) 2743 expect_output('\x1bP1$r93;104m\x1b\\') 2744 2745 -- DECRQSS on SGR 256-palette colours 2746 push('\x1b[0;38:5:56;48:5:78m', vt) 2747 push('\x1bP$qm\x1b\\', vt) 2748 expect_output('\x1bP1$r38:5:56;48:5:78m\x1b\\') 2749 2750 -- DECRQSS on SGR RGB8 colours 2751 push('\x1b[0;38:2:24:68:112;48:2:13:57:101m', vt) 2752 push('\x1bP$qm\x1b\\', vt) 2753 expect_output('\x1bP1$r38:2:24:68:112;48:2:13:57:101m\x1b\\') 2754 2755 -- S8C1T on DSR 2756 push('\x1b G', vt) 2757 push('\x1b[5n', vt) 2758 expect_output('\x9b0n') 2759 push('\x1b F', vt) 2760 end) 2761 2762 itp('27state_reset', function() 2763 local vt = init() 2764 local state = wantstate(vt) 2765 2766 reset(state, nil) 2767 2768 -- RIS homes cursor 2769 push('\x1b[5;5H', vt) 2770 cursor(4, 4, state) 2771 state = wantstate(vt, { m = true }) 2772 push('\x1bc', vt) 2773 cursor(0, 0, state) 2774 wantstate(vt) 2775 2776 -- RIS cancels scrolling region 2777 push('\x1b[5;10r', vt) 2778 wantstate(vt, { s = true }) 2779 push('\x1bc\x1b[25H\n', vt) 2780 expect('scrollrect 0..25,0..80 => +1,+0') 2781 wantstate(vt) 2782 2783 -- RIS erases screen 2784 push('ABCDE', vt) 2785 state = wantstate(vt, { e = true }) 2786 push('\x1bc', vt) 2787 expect('erase 0..25,0..80') 2788 wantstate(vt) 2789 2790 -- RIS clears tabstops 2791 push('\x1b[5G\x1bH\x1b[G\t', vt) 2792 cursor(0, 4, state) 2793 push('\x1bc\t', vt) 2794 cursor(0, 8, state) 2795 end) 2796 2797 itp('28state_dbl_wh', function() 2798 local vt = init() 2799 local state = wantstate(vt, { g = true }) 2800 2801 -- Single Width, Single Height 2802 reset(state, nil) 2803 push('\x1b#5', vt) 2804 push('Hello', vt) 2805 expect( 2806 'putglyph 48 1 0,0\nputglyph 65 1 0,1\nputglyph 6c 1 0,2\nputglyph 6c 1 0,3\nputglyph 6f 1 0,4' 2807 ) 2808 2809 -- Double Width, Single Height 2810 reset(state, nil) 2811 push('\x1b#6', vt) 2812 push('Hello', vt) 2813 expect( 2814 'putglyph 48 1 0,0 dwl\nputglyph 65 1 0,1 dwl\nputglyph 6c 1 0,2 dwl\nputglyph 6c 1 0,3 dwl\nputglyph 6f 1 0,4 dwl' 2815 ) 2816 cursor(0, 5, state) 2817 push('\x1b[40GAB', vt) 2818 expect('putglyph 41 1 0,39 dwl\nputglyph 42 1 1,0') 2819 cursor(1, 1, state) 2820 2821 -- Double Height 2822 reset(state, nil) 2823 push('\x1b#3', vt) 2824 push('Hello', vt) 2825 expect( 2826 'putglyph 48 1 0,0 dwl dhl-top\nputglyph 65 1 0,1 dwl dhl-top\nputglyph 6c 1 0,2 dwl dhl-top\nputglyph 6c 1 0,3 dwl dhl-top\nputglyph 6f 1 0,4 dwl dhl-top' 2827 ) 2828 cursor(0, 5, state) 2829 push('\r\n\x1b#4', vt) 2830 push('Hello', vt) 2831 expect( 2832 'putglyph 48 1 1,0 dwl dhl-bottom\nputglyph 65 1 1,1 dwl dhl-bottom\nputglyph 6c 1 1,2 dwl dhl-bottom\nputglyph 6c 1 1,3 dwl dhl-bottom\nputglyph 6f 1 1,4 dwl dhl-bottom' 2833 ) 2834 cursor(1, 5, state) 2835 2836 -- Double Width scrolling 2837 reset(state, nil) 2838 push('\x1b[20H\x1b#6ABC', vt) 2839 expect('putglyph 41 1 19,0 dwl\nputglyph 42 1 19,1 dwl\nputglyph 43 1 19,2 dwl') 2840 push('\x1b[25H\n', vt) 2841 push('\x1b[19;4HDE', vt) 2842 expect('putglyph 44 1 18,3 dwl\nputglyph 45 1 18,4 dwl') 2843 push('\x1b[H\x1bM', vt) 2844 push('\x1b[20;6HFG', vt) 2845 expect('putglyph 46 1 19,5 dwl\nputglyph 47 1 19,6 dwl') 2846 end) 2847 2848 itp('29state_fallback', function() 2849 local vt = init() 2850 local state = wantstate(vt, { f = true }) 2851 reset(state, nil) 2852 2853 -- Unrecognised control 2854 push('\x03', vt) 2855 expect('control 03') 2856 2857 -- Unrecognised CSI 2858 push('\x1b[?15;2z', vt) 2859 expect('csi 7a L=3f 15,2') 2860 2861 -- Unrecognised OSC 2862 push('\x1b]27;Something\x1b\\', vt) 2863 expect('osc [27;Something]') 2864 2865 -- Unrecognised DCS 2866 push('\x1bPz123\x1b\\', vt) 2867 expect('dcs [z123]') 2868 2869 -- Unrecognised APC 2870 push('\x1b_z123\x1b\\', vt) 2871 expect('apc [z123]') 2872 2873 -- Unrecognised PM 2874 push('\x1b^z123\x1b\\', vt) 2875 expect('pm [z123]') 2876 2877 -- Unrecognised SOS 2878 push('\x1bXz123\x1b\\', vt) 2879 expect('sos [z123]') 2880 end) 2881 2882 itp('30state_pen', function() 2883 local vt = init() 2884 local state = wantstate(vt) 2885 2886 -- Reset 2887 push('\x1b[m', vt) 2888 pen('bold', false, state) 2889 pen('underline', 0, state) 2890 pen('italic', false, state) 2891 pen('blink', false, state) 2892 pen('reverse', false, state) 2893 pen('font', 0, state) 2894 -- TODO(dundargoc): fix 2895 -- ?pen foreground = rgb(240,240,240,is_default_fg) 2896 -- ?pen background = rgb(0,0,0,is_default_bg) 2897 2898 -- Bold 2899 push('\x1b[1m', vt) 2900 pen('bold', true, state) 2901 push('\x1b[22m', vt) 2902 pen('bold', false, state) 2903 push('\x1b[1m\x1b[m', vt) 2904 pen('bold', false, state) 2905 2906 -- Underline 2907 push('\x1b[4m', vt) 2908 pen('underline', 1, state) 2909 push('\x1b[21m', vt) 2910 pen('underline', 2, state) 2911 push('\x1b[24m', vt) 2912 pen('underline', 0, state) 2913 push('\x1b[4m\x1b[4:0m', vt) 2914 pen('underline', 0, state) 2915 push('\x1b[4:1m', vt) 2916 pen('underline', 1, state) 2917 push('\x1b[4:2m', vt) 2918 pen('underline', 2, state) 2919 push('\x1b[4:3m', vt) 2920 pen('underline', 3, state) 2921 push('\x1b[4m\x1b[m', vt) 2922 pen('underline', 0, state) 2923 2924 -- Italic 2925 push('\x1b[3m', vt) 2926 pen('italic', true, state) 2927 push('\x1b[23m', vt) 2928 pen('italic', false, state) 2929 push('\x1b[3m\x1b[m', vt) 2930 pen('italic', false, state) 2931 2932 -- Blink 2933 push('\x1b[5m', vt) 2934 pen('blink', true, state) 2935 push('\x1b[25m', vt) 2936 pen('blink', false, state) 2937 push('\x1b[5m\x1b[m', vt) 2938 pen('blink', false, state) 2939 2940 -- Reverse 2941 push('\x1b[7m', vt) 2942 pen('reverse', true, state) 2943 push('\x1b[27m', vt) 2944 pen('reverse', false, state) 2945 push('\x1b[7m\x1b[m', vt) 2946 pen('reverse', false, state) 2947 2948 -- Font Selection 2949 push('\x1b[11m', vt) 2950 pen('font', 1, state) 2951 push('\x1b[19m', vt) 2952 pen('font', 9, state) 2953 push('\x1b[10m', vt) 2954 pen('font', 0, state) 2955 push('\x1b[11m\x1b[m', vt) 2956 pen('font', 0, state) 2957 2958 -- Dim 2959 push('\x1b[2m', vt) 2960 pen('dim', true, state) 2961 push('\x1b[22m', vt) 2962 pen('dim', false, state) 2963 push('\x1b[2m\x1b[m', vt) 2964 pen('dim', false, state) 2965 2966 -- Bold and Dim interaction (SGR 22 turns off both) 2967 push('\x1b[1;2m', vt) 2968 pen('bold', true, state) 2969 pen('dim', true, state) 2970 push('\x1b[22m', vt) 2971 pen('bold', false, state) 2972 pen('dim', false, state) 2973 2974 -- Overline 2975 push('\x1b[53m', vt) 2976 pen('overline', true, state) 2977 push('\x1b[55m', vt) 2978 pen('overline', false, state) 2979 push('\x1b[53m\x1b[m', vt) 2980 pen('overline', false, state) 2981 2982 -- TODO(dundargoc): fix 2983 -- Foreground 2984 -- push "\x1b[31m" 2985 -- ?pen foreground = idx(1) 2986 -- push "\x1b[32m" 2987 -- ?pen foreground = idx(2) 2988 -- push "\x1b[34m" 2989 -- ?pen foreground = idx(4) 2990 -- push "\x1b[91m" 2991 -- ?pen foreground = idx(9) 2992 -- push "\x1b[38:2:10:20:30m" 2993 -- ?pen foreground = rgb(10,20,30) 2994 -- push "\x1b[38:5:1m" 2995 -- ?pen foreground = idx(1) 2996 -- push "\x1b[39m" 2997 -- ?pen foreground = rgb(240,240,240,is_default_fg) 2998 -- 2999 -- Background 3000 -- push "\x1b[41m" 3001 -- ?pen background = idx(1) 3002 -- push "\x1b[42m" 3003 -- ?pen background = idx(2) 3004 -- push "\x1b[44m" 3005 -- ?pen background = idx(4) 3006 -- push "\x1b[101m" 3007 -- ?pen background = idx(9) 3008 -- push "\x1b[48:2:10:20:30m" 3009 -- ?pen background = rgb(10,20,30) 3010 -- push "\x1b[48:5:1m" 3011 -- ?pen background = idx(1) 3012 -- push "\x1b[49m" 3013 -- ?pen background = rgb(0,0,0,is_default_bg) 3014 -- 3015 -- Bold+ANSI colour == highbright 3016 -- push "\x1b[m\x1b[1;37m" 3017 -- ?pen bold = on 3018 -- ?pen foreground = idx(15) 3019 -- push "\x1b[m\x1b[37;1m" 3020 -- ?pen bold = on 3021 -- ?pen foreground = idx(15) 3022 -- 3023 -- Super/Subscript 3024 -- push "\x1b[73m" 3025 -- ?pen small = on 3026 -- ?pen baseline = raise 3027 -- push "\x1b[74m" 3028 -- ?pen small = on 3029 -- ?pen baseline = lower 3030 -- push "\x1b[75m" 3031 -- ?pen small = off 3032 -- ?pen baseline = normal 3033 -- 3034 -- DECSTR resets pen attributes 3035 -- push "\x1b[1;4m" 3036 -- ?pen bold = on 3037 -- ?pen underline = 1 3038 -- push "\x1b[!p" 3039 -- ?pen bold = off 3040 -- ?pen underline = 0 3041 end) 3042 3043 itp('31state_rep', function() 3044 local vt = init() 3045 local state = wantstate(vt, { g = true }) 3046 3047 -- REP no argument 3048 reset(state, nil) 3049 push('a\x1b[b', vt) 3050 expect('putglyph 61 1 0,0\nputglyph 61 1 0,1') 3051 3052 -- REP zero (zero should be interpreted as one) 3053 reset(state, nil) 3054 push('a\x1b[0b', vt) 3055 expect('putglyph 61 1 0,0\nputglyph 61 1 0,1') 3056 3057 -- REP lowercase a times two 3058 reset(state, nil) 3059 push('a\x1b[2b', vt) 3060 expect('putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2') 3061 3062 -- REP with UTF-8 1 char 3063 -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE 3064 reset(state, nil) 3065 push('\xC3\xA9\x1b[b', vt) 3066 expect('putglyph e9 1 0,0\nputglyph e9 1 0,1') 3067 3068 -- REP with UTF-8 wide char 3069 -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE 3070 reset(state, nil) 3071 push('\xEF\xBC\x90\x1b[b', vt) 3072 expect('putglyph ff10 2 0,0\nputglyph ff10 2 0,2') 3073 3074 -- REP with UTF-8 combining character 3075 reset(state, nil) 3076 push('e\xCC\x81\x1b[b', vt) 3077 expect('putglyph 65,301 1 0,0\nputglyph 65,301 1 0,1') 3078 3079 -- REP till end of line 3080 reset(state, nil) 3081 push('a\x1b[1000bb', vt) 3082 expect( 3083 'putglyph 61 1 0,0\nputglyph 61 1 0,1\nputglyph 61 1 0,2\nputglyph 61 1 0,3\nputglyph 61 1 0,4\nputglyph 61 1 0,5\nputglyph 61 1 0,6\nputglyph 61 1 0,7\nputglyph 61 1 0,8\nputglyph 61 1 0,9\nputglyph 61 1 0,10\nputglyph 61 1 0,11\nputglyph 61 1 0,12\nputglyph 61 1 0,13\nputglyph 61 1 0,14\nputglyph 61 1 0,15\nputglyph 61 1 0,16\nputglyph 61 1 0,17\nputglyph 61 1 0,18\nputglyph 61 1 0,19\nputglyph 61 1 0,20\nputglyph 61 1 0,21\nputglyph 61 1 0,22\nputglyph 61 1 0,23\nputglyph 61 1 0,24\nputglyph 61 1 0,25\nputglyph 61 1 0,26\nputglyph 61 1 0,27\nputglyph 61 1 0,28\nputglyph 61 1 0,29\nputglyph 61 1 0,30\nputglyph 61 1 0,31\nputglyph 61 1 0,32\nputglyph 61 1 0,33\nputglyph 61 1 0,34\nputglyph 61 1 0,35\nputglyph 61 1 0,36\nputglyph 61 1 0,37\nputglyph 61 1 0,38\nputglyph 61 1 0,39\nputglyph 61 1 0,40\nputglyph 61 1 0,41\nputglyph 61 1 0,42\nputglyph 61 1 0,43\nputglyph 61 1 0,44\nputglyph 61 1 0,45\nputglyph 61 1 0,46\nputglyph 61 1 0,47\nputglyph 61 1 0,48\nputglyph 61 1 0,49\nputglyph 61 1 0,50\nputglyph 61 1 0,51\nputglyph 61 1 0,52\nputglyph 61 1 0,53\nputglyph 61 1 0,54\nputglyph 61 1 0,55\nputglyph 61 1 0,56\nputglyph 61 1 0,57\nputglyph 61 1 0,58\nputglyph 61 1 0,59\nputglyph 61 1 0,60\nputglyph 61 1 0,61\nputglyph 61 1 0,62\nputglyph 61 1 0,63\nputglyph 61 1 0,64\nputglyph 61 1 0,65\nputglyph 61 1 0,66\nputglyph 61 1 0,67\nputglyph 61 1 0,68\nputglyph 61 1 0,69\nputglyph 61 1 0,70\nputglyph 61 1 0,71\nputglyph 61 1 0,72\nputglyph 61 1 0,73\nputglyph 61 1 0,74\nputglyph 61 1 0,75\nputglyph 61 1 0,76\nputglyph 61 1 0,77\nputglyph 61 1 0,78\nputglyph 61 1 0,79\nputglyph 62 1 1,0' 3084 ) 3085 end) 3086 3087 itp('32state_flow', function() 3088 local vt = init() 3089 local state = wantstate(vt) 3090 3091 -- Many of these test cases inspired by 3092 -- https://blueprints.launchpad.net/libvterm/+spec/reflow-cases 3093 3094 -- Spillover text marks continuation on second line 3095 reset(state, nil) 3096 push(string.rep('A', 100), vt) 3097 push('\r\n', vt) 3098 lineinfo(0, {}, state) 3099 lineinfo(1, { cont = true }, state) 3100 3101 -- CRLF in column 80 does not mark continuation 3102 reset(state, nil) 3103 push(string.rep('B', 80), vt) 3104 push('\r\n', vt) 3105 push(string.rep('B', 20), vt) 3106 push('\r\n', vt) 3107 lineinfo(0, {}, state) 3108 lineinfo(1, {}, state) 3109 3110 -- EL cancels continuation of following line 3111 reset(state, nil) 3112 push(string.rep('D', 100), vt) 3113 lineinfo(1, { cont = true }, state) 3114 push('\x1bM\x1b[79G\x1b[K', vt) 3115 lineinfo(1, {}, state) 3116 end) 3117 3118 itp('40state_selection', function() 3119 local vt = init() 3120 wantstate(vt) 3121 3122 -- Set clipboard; final chunk len 4 3123 push('\x1b]52;c;SGVsbG8s\x1b\\', vt) 3124 expect('selection-set mask=0001 [Hello,]') 3125 3126 -- Set clipboard; final chunk len 3 3127 push('\x1b]52;c;SGVsbG8sIHc=\x1b\\', vt) 3128 expect('selection-set mask=0001 [Hello, w]') 3129 3130 -- Set clipboard; final chunk len 2 3131 push('\x1b]52;c;SGVsbG8sIHdvcmxkCg==\x1b\\', vt) 3132 expect('selection-set mask=0001 [Hello, world\n]') 3133 3134 -- Set clipboard; split between chunks 3135 push('\x1b]52;c;SGVs', vt) 3136 expect('selection-set mask=0001 [Hel') 3137 push('bG8s\x1b\\', vt) 3138 expect('selection-set mask=0001 lo,]') 3139 3140 -- Set clipboard; split within chunk 3141 push('\x1b]52;c;SGVsbG', vt) 3142 expect('selection-set mask=0001 [Hel') 3143 push('8s\x1b\\', vt) 3144 expect('selection-set mask=0001 lo,]') 3145 3146 -- Set clipboard; empty first chunk 3147 push('\x1b]52;c;', vt) 3148 push('SGVsbG8s\x1b\\', vt) 3149 expect('selection-set mask=0001 [Hello,]') 3150 3151 -- Set clipboard; empty final chunk 3152 push('\x1b]52;c;SGVsbG8s', vt) 3153 expect('selection-set mask=0001 [Hello,') 3154 push('\x1b\\', vt) 3155 expect('selection-set mask=0001 ]') 3156 3157 -- Set clipboard; longer than buffer 3158 push('\x1b]52;c;' .. string.rep('LS0t', 10) .. '\x1b\\', vt) 3159 expect('selection-set mask=0001 [---------------\nselection-set mask=0001 ---------------]') 3160 3161 -- Clear clipboard 3162 push('\x1b]52;c;\x1b\\', vt) 3163 expect('selection-set mask=0001 []') 3164 3165 -- Set invalid data clears and ignores 3166 push('\x1b]52;c;SGVs*SGVsbG8s\x1b\\', vt) 3167 expect('selection-set mask=0001 []') 3168 3169 -- Query clipboard 3170 push('\x1b]52;c;?\x1b\\', vt) 3171 expect('selection-query mask=0001') 3172 3173 -- TODO(dundargoc): fix 3174 -- Send clipboard; final chunk len 4 3175 -- SELECTION 1 ["Hello,"] 3176 -- output "\x1b]52;c;" 3177 -- output "SGVsbG8s" 3178 -- output "\x1b\\" 3179 -- 3180 -- Send clipboard; final chunk len 3 3181 -- SELECTION 1 ["Hello, w"] 3182 -- output "\x1b]52;c;" 3183 -- output "SGVsbG8s" 3184 -- output "IHc=\x1b\\" 3185 -- 3186 -- Send clipboard; final chunk len 2 3187 -- SELECTION 1 ["Hello, world\n"] 3188 -- output "\x1b]52;c;" 3189 -- output "SGVsbG8sIHdvcmxk" 3190 -- output "Cg==\x1b\\" 3191 -- 3192 -- Send clipboard; split between chunks 3193 -- SELECTION 1 ["Hel" 3194 -- output "\x1b]52;c;" 3195 -- output "SGVs" 3196 -- SELECTION 1 "lo,"] 3197 -- output "bG8s" 3198 -- output "\x1b\\" 3199 -- 3200 -- Send clipboard; split within chunk 3201 -- SELECTION 1 ["Hello" 3202 -- output "\x1b]52;c;" 3203 -- output "SGVs" 3204 -- SELECTION 1 ","] 3205 -- output "bG8s" 3206 -- output "\x1b\\" 3207 end) 3208 3209 itp('60screen_ascii', function() 3210 local vt = init() 3211 local screen = wantscreen(vt, { a = true, c = true }) 3212 3213 -- Get 3214 reset(nil, screen) 3215 push('ABC', vt) 3216 expect('movecursor 0,3') 3217 screen_chars(0, 0, 1, 3, 'ABC', screen) 3218 screen_chars(0, 0, 1, 80, 'ABC', screen) 3219 screen_text(0, 0, 1, 3, '41,42,43', screen) 3220 screen_text(0, 0, 1, 80, '41,42,43', screen) 3221 screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3222 screen_cell(0, 1, '{42} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3223 screen_cell(0, 2, '{43} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3224 screen_row(0, 'ABC', screen) 3225 screen_eol(0, 0, 0, screen) 3226 screen_eol(0, 2, 0, screen) 3227 screen_eol(0, 3, 1, screen) 3228 push('\x1b[H', vt) 3229 expect('movecursor 0,0') 3230 screen_row(0, 'ABC', screen) 3231 screen_text(0, 0, 1, 80, '41,42,43', screen) 3232 push('E', vt) 3233 expect('movecursor 0,1') 3234 screen_row(0, 'EBC', screen) 3235 screen_text(0, 0, 1, 80, '45,42,43', screen) 3236 3237 screen = wantscreen(vt, { a = true }) 3238 3239 -- Erase 3240 reset(nil, screen) 3241 push('ABCDE\x1b[H\x1b[K', vt) 3242 -- TODO(dundargoc): fix 3243 -- screen_row(0, '', screen) 3244 screen_text(0, 0, 1, 80, '', screen) 3245 3246 -- Copycell 3247 reset(nil, screen) 3248 push('ABC\x1b[H\x1b[@', vt) 3249 push('1', vt) 3250 screen_row(0, '1ABC', screen) 3251 3252 reset(nil, screen) 3253 push('ABC\x1b[H\x1b[P', vt) 3254 screen_chars(0, 0, 1, 1, 'B', screen) 3255 screen_chars(0, 1, 1, 2, 'C', screen) 3256 screen_chars(0, 0, 1, 80, 'BC', screen) 3257 3258 -- Space padding 3259 reset(nil, screen) 3260 push('Hello\x1b[CWorld', vt) 3261 screen_row(0, 'Hello World', screen) 3262 screen_text(0, 0, 1, 80, '48,65,6c,6c,6f,20,57,6f,72,6c,64', screen) 3263 3264 -- Linefeed padding 3265 reset(nil, screen) 3266 push('Hello\r\nWorld', vt) 3267 screen_chars(0, 0, 2, 80, 'Hello\nWorld', screen) 3268 screen_text(0, 0, 2, 80, '48,65,6c,6c,6f,0a,57,6f,72,6c,64', screen) 3269 3270 -- Altscreen 3271 reset(nil, screen) 3272 push('P', vt) 3273 screen_row(0, 'P', screen) 3274 -- TODO(dundargoc): fix 3275 -- push('\x1b[?1049h', vt) 3276 -- screen_row(0, '', screen) 3277 -- push('\x1b[2K\x1b[HA', vt) 3278 -- screen_row(0, 'A', screen) 3279 -- push('\x1b[?1049l', vt) 3280 -- screen_row(0, 'P', screen) 3281 end) 3282 3283 itp('61screen_unicode', function() 3284 local vt = init() 3285 local screen = wantscreen(vt) 3286 3287 -- Single width UTF-8 3288 -- U+00C1 = C3 81 name: LATIN CAPITAL LETTER A WITH ACUTE 3289 -- U+00E9 = C3 A9 name: LATIN SMALL LETTER E WITH ACUTE 3290 reset(nil, screen) 3291 push('\xC3\x81\xC3\xA9', vt) 3292 screen_row(0, 'Áé', screen) 3293 screen_text(0, 0, 1, 80, 'c3,81,c3,a9', screen) 3294 screen_cell(0, 0, '{c1} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3295 3296 -- Wide char 3297 -- U+FF10 = EF BC 90 name: FULLWIDTH DIGIT ZERO 3298 reset(nil, screen) 3299 push('0123\x1b[H', vt) 3300 push('\xEF\xBC\x90', vt) 3301 screen_row(0, '023', screen) 3302 screen_text(0, 0, 1, 80, 'ef,bc,90,32,33', screen) 3303 screen_cell(0, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3304 3305 -- Combining char 3306 -- U+0301 = CC 81 name: COMBINING ACUTE 3307 reset(nil, screen) 3308 push('0123\x1b[H', vt) 3309 push('e\xCC\x81', vt) 3310 screen_row(0, 'é123', screen) 3311 screen_text(0, 0, 1, 80, '65,cc,81,31,32,33', screen) 3312 screen_cell(0, 0, '{65,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3313 3314 -- 10 combining accents should not crash 3315 reset(nil, screen) 3316 push('e\xCC\x81\xCC\x82\xCC\x83\xCC\x84\xCC\x85\xCC\x86\xCC\x87\xCC\x88\xCC\x89\xCC\x8A', vt) 3317 screen_cell( 3318 0, 3319 0, 3320 '{65,301,302,303,304,305,306,307,308,309,30a} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', 3321 screen 3322 ) 3323 3324 -- 40 combining accents in two split writes of 20 should not crash 3325 reset(nil, screen) 3326 push( 3327 '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', 3328 vt 3329 ) 3330 push( 3331 '\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', 3332 vt 3333 ) 3334 screen_cell( 3335 0, 3336 0, 3337 '{65,301,301,301,301,301,301,301,301,301,301,301,301,301,301} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', 3338 screen 3339 ) 3340 3341 -- Outputting CJK doublewidth in 80th column should wraparound to next line and not crash" 3342 reset(nil, screen) 3343 push('\x1b[80G\xEF\xBC\x90', vt) 3344 screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3345 screen_cell(1, 0, '{ff10} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3346 3347 -- Outputting emoji with ZWJ and variant selectors 3348 reset(nil, screen) 3349 push('🏳️🌈🏳️⚧️🏴☠️', vt) 3350 3351 -- stylua: ignore start 3352 screen_cell(0, 0, '{1f3f3,fe0f,200d,1f308} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3353 screen_cell(0, 2, '{1f3f3,fe0f,200d,26a7,fe0f} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3354 screen_cell(0, 4, '{1f3f4,200d,2620,fe0f} width=2 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3355 -- stylua: ignore end 3356 end) 3357 3358 pending('62screen_damage', function() end) 3359 3360 itp('63screen_resize', function() 3361 local vt = init() 3362 local state = wantstate(vt) 3363 local screen = wantscreen(vt) 3364 3365 -- Resize wider preserves cells 3366 reset(state, screen) 3367 resize(25, 80, vt) 3368 push('AB\r\nCD', vt) 3369 screen_chars(0, 0, 1, 80, 'AB', screen) 3370 screen_chars(1, 0, 2, 80, 'CD', screen) 3371 resize(25, 100, vt) 3372 screen_chars(0, 0, 1, 100, 'AB', screen) 3373 screen_chars(1, 0, 2, 100, 'CD', screen) 3374 3375 -- Resize wider allows print in new area 3376 reset(state, screen) 3377 resize(25, 80, vt) 3378 push('AB\x1b[79GCD', vt) 3379 screen_chars(0, 0, 1, 2, 'AB', screen) 3380 screen_chars(0, 78, 1, 80, 'CD', screen) 3381 resize(25, 100, vt) 3382 screen_chars(0, 0, 1, 2, 'AB', screen) 3383 screen_chars(0, 78, 1, 80, 'CD', screen) 3384 push('E', vt) 3385 screen_chars(0, 78, 1, 81, 'CDE', screen) 3386 3387 -- Resize shorter with blanks just truncates 3388 reset(state, screen) 3389 resize(25, 80, vt) 3390 push('Top\x1b[10HLine 10', vt) 3391 screen_row(0, 'Top', screen) 3392 screen_row(9, 'Line 10', screen) 3393 cursor(9, 7, state) 3394 resize(20, 80, vt) 3395 screen_row(0, 'Top', screen) 3396 screen_row(9, 'Line 10', screen) 3397 cursor(9, 7, state) 3398 3399 -- Resize shorter with content must scroll 3400 reset(state, screen) 3401 resize(25, 80, vt) 3402 push('Top\x1b[25HLine 25\x1b[15H', vt) 3403 screen_row(0, 'Top', screen) 3404 screen_row(24, 'Line 25', screen) 3405 cursor(14, 0, state) 3406 screen = wantscreen(vt, { b = true }) 3407 resize(20, 80, vt) 3408 expect( 3409 'sb_pushline 80 = 54 6f 70\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =' 3410 ) 3411 -- TODO(dundargoc): fix or remove 3412 -- screen_row( 0 , "",screen) 3413 screen_row(19, 'Line 25', screen) 3414 cursor(9, 0, state) 3415 3416 -- Resize shorter does not lose line with cursor 3417 -- See also https://github.com/neovim/libvterm/commit/1b745d29d45623aa8d22a7b9288c7b0e331c7088 3418 reset(state, screen) 3419 wantscreen(vt) 3420 resize(25, 80, vt) 3421 screen = wantscreen(vt, { b = true }) 3422 push('\x1b[24HLine 24\r\nLine 25\r\n', vt) 3423 expect('sb_pushline 80 =') 3424 screen_row(23, 'Line 25', screen) 3425 cursor(24, 0, state) 3426 resize(24, 80, vt) 3427 expect('sb_pushline 80 =') 3428 screen_row(22, 'Line 25', screen) 3429 cursor(23, 0, state) 3430 3431 -- Resize shorter does not send the cursor to a negative row 3432 -- See also https://github.com/vim/vim/pull/6141 3433 reset(state, screen) 3434 wantscreen(vt) 3435 resize(25, 80, vt) 3436 screen = wantscreen(vt, { b = true }) 3437 push('\x1b[24HLine 24\r\nLine 25\x1b[H', vt) 3438 cursor(0, 0, state) 3439 resize(20, 80, vt) 3440 expect( 3441 'sb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =\nsb_pushline 80 =' 3442 ) 3443 cursor(0, 0, state) 3444 3445 -- Resize taller attempts to pop scrollback 3446 reset(state, screen) 3447 screen = wantscreen(vt) 3448 resize(25, 80, vt) 3449 push('Line 1\x1b[25HBottom\x1b[15H', vt) 3450 screen_row(0, 'Line 1', screen) 3451 screen_row(24, 'Bottom', screen) 3452 cursor(14, 0, state) 3453 screen = wantscreen(vt, { b = true }) 3454 resize(30, 80, vt) 3455 expect('sb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80\nsb_popline 80') 3456 screen_row(0, 'ABCDE', screen) 3457 screen_row(5, 'Line 1', screen) 3458 screen_row(29, 'Bottom', screen) 3459 cursor(19, 0, state) 3460 screen = wantscreen(vt) 3461 3462 -- Resize can operate on altscreen 3463 reset(state, screen) 3464 screen = wantscreen(vt, { a = true }) 3465 resize(25, 80, vt) 3466 push('Main screen\x1b[?1049h\x1b[HAlt screen', vt) 3467 resize(30, 80, vt) 3468 screen_row(0, 'Alt screen', screen) 3469 push('\x1b[?1049l', vt) 3470 screen_row(0, 'Main screen', screen) 3471 end) 3472 3473 itp('64screen_pen', function() 3474 local vt = init() 3475 local screen = wantscreen(vt) 3476 3477 reset(nil, screen) 3478 3479 -- Plain 3480 push('A', vt) 3481 screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3482 3483 -- Bold 3484 push('\x1b[1mB', vt) 3485 screen_cell(0, 1, '{42} width=1 attrs={B} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3486 3487 -- Italic 3488 push('\x1b[3mC', vt) 3489 screen_cell(0, 2, '{43} width=1 attrs={BI} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3490 3491 -- Underline 3492 push('\x1b[4mD', vt) 3493 screen_cell(0, 3, '{44} width=1 attrs={BU1I} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3494 3495 -- Reset 3496 push('\x1b[mE', vt) 3497 screen_cell(0, 4, '{45} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3498 3499 -- Font 3500 push('\x1b[11mF\x1b[m', vt) 3501 screen_cell(0, 5, '{46} width=1 attrs={F1} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3502 3503 -- Foreground 3504 push('\x1b[31mG\x1b[m', vt) 3505 screen_cell(0, 6, '{47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen) 3506 3507 -- Background 3508 push('\x1b[42mH\x1b[m', vt) 3509 screen_cell(0, 7, '{48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0)', screen) 3510 3511 -- Super/subscript 3512 push('x\x1b[74m0\x1b[73m2\x1b[m', vt) 3513 screen_cell(0, 8, '{78} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3514 screen_cell(0, 9, '{30} width=1 attrs={S_} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3515 screen_cell(0, 10, '{32} width=1 attrs={S^} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3516 3517 -- Dim 3518 push('\x1b[2mI\x1b[m', vt) 3519 screen_cell(0, 11, '{49} width=1 attrs={D} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3520 3521 -- Overline 3522 push('\x1b[53mJ\x1b[m', vt) 3523 screen_cell(0, 12, '{4a} width=1 attrs={O} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3524 3525 -- EL sets only colours to end of line, not other attrs 3526 push('\x1b[H\x1b[7;33;44m\x1b[K', vt) 3527 screen_cell(0, 0, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) 3528 screen_cell(0, 79, '{} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) 3529 3530 -- DECSCNM xors reverse for entire screen 3531 push('R\x1b[?5h', vt) 3532 screen_cell(0, 0, '{52} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) 3533 screen_cell(1, 0, '{} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3534 push('\x1b[?5$p', vt) 3535 expect_output('\x1b[?5;1$y') 3536 push('\x1b[?5l', vt) 3537 screen_cell(0, 0, '{52} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224)', screen) 3538 screen_cell(1, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3539 -- TODO(dundargoc): fix 3540 -- push('\x1b[?5$p') 3541 -- expect_output('\x1b[?5;2$y') 3542 3543 -- Set default colours 3544 reset(nil, screen) 3545 push('ABC\x1b[31mDEF\x1b[m', vt) 3546 screen_cell(0, 0, '{41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3547 screen_cell(0, 3, '{44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0)', screen) 3548 -- TODO(dundargoc): fix 3549 -- SETDEFAULTCOL rgb(252,253,254) 3550 -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(252,253,254) bg=rgb(0,0,0) 3551 -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0) 3552 -- SETDEFAULTCOL rgb(250,250,250) rgb(10,20,30) 3553 -- ?screen_cell 0,0 = {41} width=1 attrs={} fg=rgb(250,250,250) bg=rgb(10,20,30) 3554 -- ?screen_cell 0,3 = {44} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(10,20,30) 3555 end) 3556 3557 itp('65screen_protect', function() 3558 local vt = init() 3559 local screen = wantscreen(vt) 3560 3561 -- Selective erase 3562 reset(nil, screen) 3563 push('A\x1b[1"qB\x1b["qC', vt) 3564 screen_row(0, 'ABC', screen) 3565 push('\x1b[G\x1b[?J', vt) 3566 screen_row(0, ' B', screen) 3567 3568 -- Non-selective erase 3569 reset(nil, screen) 3570 push('A\x1b[1"qB\x1b["qC', vt) 3571 screen_row(0, 'ABC', screen) 3572 -- TODO(dundargoc): fix 3573 -- push('\x1b[G\x1b[J', vt) 3574 -- screen_row(0, '', screen) 3575 end) 3576 3577 itp('66screen_extent', function() 3578 local vt = init() 3579 local screen = wantscreen(vt) 3580 3581 -- Bold extent 3582 reset(nil, screen) 3583 push('AB\x1b[1mCD\x1b[mE', vt) 3584 screen_attrs_extent(0, 0, '0,0-1,1', screen) 3585 screen_attrs_extent(0, 1, '0,0-1,1', screen) 3586 screen_attrs_extent(0, 2, '0,2-1,3', screen) 3587 screen_attrs_extent(0, 3, '0,2-1,3', screen) 3588 screen_attrs_extent(0, 4, '0,4-1,79', screen) 3589 end) 3590 3591 itp('67screen_dbl_wh', function() 3592 local vt = init() 3593 local screen = wantscreen(vt) 3594 3595 reset(nil, screen) 3596 3597 -- Single Width, Single Height 3598 reset(nil, screen) 3599 push('\x1b#5', vt) 3600 push('abcde', vt) 3601 screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3602 3603 -- Double Width, Single Height 3604 reset(nil, screen) 3605 push('\x1b#6', vt) 3606 push('abcde', vt) 3607 screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3608 3609 -- Double Height 3610 reset(nil, screen) 3611 push('\x1b#3', vt) 3612 push('abcde', vt) 3613 push('\r\n\x1b#4', vt) 3614 push('abcde', vt) 3615 screen_cell(0, 0, '{61} width=1 attrs={} dwl dhl-top fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3616 screen_cell( 3617 1, 3618 0, 3619 '{61} width=1 attrs={} dwl dhl-bottom fg=rgb(240,240,240) bg=rgb(0,0,0)', 3620 screen 3621 ) 3622 3623 -- Late change 3624 reset(nil, screen) 3625 push('abcde', vt) 3626 screen_cell(0, 0, '{61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3627 push('\x1b#6', vt) 3628 screen_cell(0, 0, '{61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3629 3630 -- DWL doesn't spill over on scroll 3631 reset(nil, screen) 3632 push('\x1b[25H\x1b#6Final\r\n', vt) 3633 screen_cell(23, 0, '{46} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3634 screen_cell(24, 0, '{} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0)', screen) 3635 end) 3636 3637 itp('68screen_termprops', function() 3638 local vt = init() 3639 local screen = wantscreen(vt, { p = true }) 3640 3641 reset(nil, screen) 3642 expect('settermprop 1 true\nsettermprop 2 true\nsettermprop 7 1') 3643 3644 -- Cursor visibility 3645 push('\x1b[?25h', vt) 3646 expect('settermprop 1 true') 3647 push('\x1b[?25l', vt) 3648 expect('settermprop 1 false') 3649 3650 -- Title 3651 push('\x1b]2;Here is my title\a', vt) 3652 expect('settermprop 4 ["Here is my title"]') 3653 end) 3654 3655 itp('69screen_pushline', function() 3656 local vt = init() 3657 -- Run these tests on a much smaller default screen, so debug output is nowhere near as noisy 3658 resize(5, 10, vt) 3659 local state = wantstate(vt) 3660 local screen = wantscreen(vt, { r = true }) 3661 reset(state, screen) 3662 3663 -- Resize wider reflows wide lines 3664 reset(state, screen) 3665 push(string.rep('A', 12), vt) 3666 screen_row(0, 'AAAAAAAAAA', screen, vt.cols) 3667 screen_row(1, 'AA', screen, vt.cols) 3668 lineinfo(1, { cont = true }, state) 3669 cursor(1, 2, state) 3670 resize(5, 15, vt) 3671 screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols) 3672 -- TODO(dundargoc): fix 3673 -- screen_row(1, '', screen, vt.cols) 3674 lineinfo(1, {}, state) 3675 cursor(0, 12, state) 3676 resize(5, 20, vt) 3677 screen_row(0, 'AAAAAAAAAAAA', screen, vt.cols) 3678 -- TODO(dundargoc): fix 3679 -- screen_row( 1 ,'',screen, vt.cols) 3680 lineinfo(1, {}, state) 3681 cursor(0, 12, state) 3682 3683 -- Resize narrower can create continuation lines 3684 reset(state, screen) 3685 resize(5, 10, vt) 3686 push('ABCDEFGHI', vt) 3687 screen_row(0, 'ABCDEFGHI', screen, vt.cols) 3688 -- TODO(dundargoc): fix 3689 -- screen_row( 1 , "",screen, vt.cols) 3690 lineinfo(1, {}, state) 3691 cursor(0, 9, state) 3692 resize(5, 8, vt) 3693 -- TODO(dundargoc): fix 3694 -- screen_row( 0 , "ABCDEFGH",screen,vt.cols) 3695 screen_row(1, 'I', screen, vt.cols) 3696 lineinfo(1, { cont = true }, state) 3697 cursor(1, 1, state) 3698 resize(5, 6, vt) 3699 screen_row(0, 'ABCDEF', screen, vt.cols) 3700 screen_row(1, 'GHI', screen, vt.cols) 3701 lineinfo(1, { cont = true }, state) 3702 cursor(1, 3, state) 3703 3704 -- Shell wrapped prompt behaviour 3705 reset(state, screen) 3706 resize(5, 10, vt) 3707 push('PROMPT GOES HERE\r\n> \r\n\r\nPROMPT GOES HERE\r\n> ', vt) 3708 screen_row(0, '> ', screen, vt.cols) 3709 -- TODO(dundargoc): fix 3710 -- screen_row( 1 , "",screen,vt.cols) 3711 screen_row(2, 'PROMPT GOE', screen, vt.cols) 3712 screen_row(3, 'S HERE', screen, vt.cols) 3713 lineinfo(3, { cont = true }, state) 3714 screen_row(4, '> ', screen, vt.cols) 3715 cursor(4, 2, state) 3716 resize(5, 11, vt) 3717 screen_row(0, '> ', screen, vt.cols) 3718 -- TODO(dundargoc): fix 3719 -- screen_row( 1 , "",screen,vt.cols) 3720 screen_row(2, 'PROMPT GOES', screen, vt.cols) 3721 screen_row(3, ' HERE', screen, vt.cols) 3722 lineinfo(3, { cont = true }, state) 3723 screen_row(4, '> ', screen, vt.cols) 3724 cursor(4, 2, state) 3725 resize(5, 12, vt) 3726 screen_row(0, '> ', screen, vt.cols) 3727 -- TODO(dundargoc): fix 3728 -- screen_row( 1 , "",screen,vt.cols) 3729 screen_row(2, 'PROMPT GOES ', screen, vt.cols) 3730 screen_row(3, 'HERE', screen, vt.cols) 3731 lineinfo(3, { cont = true }, state) 3732 screen_row(4, '> ', screen, vt.cols) 3733 cursor(4, 2, state) 3734 resize(5, 16, vt) 3735 screen_row(0, '> ', screen, vt.cols) 3736 -- TODO(dundargoc): fix 3737 -- screen_row( 1 , "",screen,vt.cols) 3738 -- screen_row( 2 , "PROMPT GOES HERE",screen,vt.cols) 3739 lineinfo(3, {}, state) 3740 screen_row(3, '> ', screen, vt.cols) 3741 cursor(3, 2, state) 3742 3743 -- Cursor goes missing 3744 -- For more context: https://github.com/neovim/neovim/pull/21124 3745 reset(state, screen) 3746 resize(5, 5, vt) 3747 resize(3, 1, vt) 3748 push('\x1b[2;1Habc\r\n\x1b[H', vt) 3749 resize(1, 1, vt) 3750 cursor(0, 0, state) 3751 end) 3752 3753 pending('90vttest_01-movement-1', function() end) 3754 pending('90vttest_01-movement-2', function() end) 3755 3756 itp('90vttest_01-movement-3', function() 3757 -- Test of cursor-control characters inside ESC sequences 3758 local vt = init() 3759 local state = wantstate(vt) 3760 local screen = wantscreen(vt) 3761 3762 reset(state, screen) 3763 3764 push('A B C D E F G H I', vt) 3765 push('\x0d\x0a', vt) 3766 push('A\x1b[2\bCB\x1b[2\bCC\x1b[2\bCD\x1b[2\bCE\x1b[2\bCF\x1b[2\bCG\x1b[2\bCH\x1b[2\bCI', vt) 3767 push('\x0d\x0a', vt) 3768 push( 3769 'A \x1b[\x0d2CB\x1b[\x0d4CC\x1b[\x0d6CD\x1b[\x0d8CE\x1b[\x0d10CF\x1b[\x0d12CG\x1b[\x0d14CH\x1b[\x0d16CI', 3770 vt 3771 ) 3772 push('\x0d\x0a', vt) 3773 push( 3774 'A \x1b[1\x0bAB \x1b[1\x0bAC \x1b[1\x0bAD \x1b[1\x0bAE \x1b[1\x0bAF \x1b[1\x0bAG \x1b[1\x0bAH \x1b[1\x0bAI \x1b[1\x0bA', 3775 vt 3776 ) 3777 3778 -- Output 3779 3780 for i = 0, 2 do 3781 screen_row(i, 'A B C D E F G H I', screen) 3782 end 3783 screen_row(3, 'A B C D E F G H I ', screen) 3784 3785 cursor(3, 18, state) 3786 end) 3787 3788 itp('90vttest_01-movement-4', function() 3789 -- Test of leading zeroes in ESC sequences 3790 local vt = init() 3791 local screen = wantscreen(vt) 3792 3793 reset(nil, screen) 3794 3795 push('\x1b[00000000004;000000001HT', vt) 3796 push('\x1b[00000000004;000000002Hh', vt) 3797 push('\x1b[00000000004;000000003Hi', vt) 3798 push('\x1b[00000000004;000000004Hs', vt) 3799 push('\x1b[00000000004;000000005H ', vt) 3800 push('\x1b[00000000004;000000006Hi', vt) 3801 push('\x1b[00000000004;000000007Hs', vt) 3802 push('\x1b[00000000004;000000008H ', vt) 3803 push('\x1b[00000000004;000000009Ha', vt) 3804 push('\x1b[00000000004;0000000010H ', vt) 3805 push('\x1b[00000000004;0000000011Hc', vt) 3806 push('\x1b[00000000004;0000000012Ho', vt) 3807 push('\x1b[00000000004;0000000013Hr', vt) 3808 push('\x1b[00000000004;0000000014Hr', vt) 3809 push('\x1b[00000000004;0000000015He', vt) 3810 push('\x1b[00000000004;0000000016Hc', vt) 3811 push('\x1b[00000000004;0000000017Ht', vt) 3812 push('\x1b[00000000004;0000000018H ', vt) 3813 push('\x1b[00000000004;0000000019Hs', vt) 3814 push('\x1b[00000000004;0000000020He', vt) 3815 push('\x1b[00000000004;0000000021Hn', vt) 3816 push('\x1b[00000000004;0000000022Ht', vt) 3817 push('\x1b[00000000004;0000000023He', vt) 3818 push('\x1b[00000000004;0000000024Hn', vt) 3819 push('\x1b[00000000004;0000000025Hc', vt) 3820 push('\x1b[00000000004;0000000026He', vt) 3821 3822 -- Output 3823 3824 screen_row(3, 'This is a correct sentence', screen) 3825 end) 3826 3827 pending('90vttest_02-screen-1', function() end) 3828 pending('90vttest_02-screen-2', function() end) 3829 3830 itp('90vttest_02-screen-3', function() 3831 -- Origin mode 3832 local vt = init() 3833 local screen = wantscreen(vt) 3834 3835 reset(nil, screen) 3836 3837 push('\x1b[?6h', vt) 3838 push('\x1b[23;24r', vt) 3839 push('\n', vt) 3840 push('Bottom', vt) 3841 push('\x1b[1;1H', vt) 3842 push('Above', vt) 3843 3844 -- Output 3845 screen_row(22, 'Above', screen) 3846 screen_row(23, 'Bottom', screen) 3847 end) 3848 3849 itp('90vttest_02-screen-4', function() 3850 -- Origin mode (2) 3851 local vt = init() 3852 local screen = wantscreen(vt) 3853 3854 reset(nil, screen) 3855 3856 push('\x1b[?6l', vt) 3857 push('\x1b[23;24r', vt) 3858 push('\x1b[24;1H', vt) 3859 push('Bottom', vt) 3860 push('\x1b[1;1H', vt) 3861 push('Top', vt) 3862 3863 -- Output 3864 screen_row(23, 'Bottom', screen) 3865 screen_row(0, 'Top', screen) 3866 end) 3867 3868 itp('Mouse reporting should not break by idempotent DECSM 1002', function() 3869 -- Regression test for https://bugs.launchpad.net/libvterm/+bug/1640917 3870 -- Related: https://github.com/neovim/neovim/issues/5583 3871 local vt = init() 3872 wantstate(vt, {}) 3873 3874 push('\x1b[?1002h', vt) 3875 mousemove(0, 0, vt) 3876 mousebtn('d', 1, vt) 3877 expect_output('\x1b[M\x20\x21\x21') 3878 mousemove(1, 0, vt) 3879 expect_output('\x1b[M\x40\x21\x22') 3880 push('\x1b[?1002h', vt) 3881 mousemove(2, 0, vt) 3882 expect_output('\x1b[M\x40\x21\x23') 3883 end) 3884 end)