mirror of
https://github.com/lihop/godot-xterm.git
synced 2025-05-03 20:14:22 +02:00
Add more features, bug fixes and bugs ;-)
Most notably: - Reflow is now working. Terminal size will fill the window and cols/rows will be resized/calculated based on window and font size. - Added support for different fonts (i.e. bold, italic, bolditalic). - Enabled blinking characters. - Adde more tests and caught a few subtle bugs. - Removed renderer code (which was part of xterm.js) and just doing naive rendering in terminal.gd, but it seems to perform a lot faster. Still not working completely: - vim (some weirdness going on). - vttest (more weirdness). Todo: - Fix the above. - Draw the cursor! - Improve performance. Performance is still not great. The terminal becomes unusable when running `yes` or `cmatrix -r`.
This commit is contained in:
parent
0769592a1b
commit
0d4e10f5ab
30 changed files with 2640 additions and 1157 deletions
|
@ -122,7 +122,241 @@ class TestGetWrappedRangeForLine:
|
|||
buffer.lines.get_el(buffer.lines.length - 1).is_wrapped = true
|
||||
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 2).first, INIT_ROWS - 2)
|
||||
assert_eq(buffer.get_wrapped_range_for_line(buffer.lines.length - 2).last, INIT_ROWS - 1)
|
||||
|
||||
|
||||
class TestResize:
|
||||
extends BaseBufferTest
|
||||
|
||||
|
||||
func before_each():
|
||||
.before_each()
|
||||
buffer.fill_viewport_rows()
|
||||
|
||||
|
||||
func test_column_size_reduction_trims_data_in_the_buffer():
|
||||
buffer.resize(INIT_COLS / 2, INIT_ROWS)
|
||||
assert_eq(buffer.lines.length, INIT_ROWS)
|
||||
for i in range(INIT_ROWS):
|
||||
assert_eq(buffer.lines.get_line(i).length, INIT_COLS / 2)
|
||||
|
||||
|
||||
func test_column_size_increase_adds_pad_columns():
|
||||
buffer.resize(INIT_COLS + 10, INIT_ROWS)
|
||||
assert_eq(buffer.lines.length, INIT_ROWS)
|
||||
for i in range(INIT_ROWS):
|
||||
assert_eq(buffer.lines.get_line(i).length, INIT_COLS + 10)
|
||||
|
||||
|
||||
func test_row_size_reduction_trims_blank_lines_from_the_end():
|
||||
buffer.resize(INIT_COLS, INIT_ROWS - 10)
|
||||
assert_eq(buffer.lines.length, INIT_ROWS - 10)
|
||||
|
||||
|
||||
func test_row_size_reduction_moves_viewport_down_when_it_is_at_the_end():
|
||||
# Set cursor y to have 5 blank lines below it
|
||||
buffer.y = INIT_ROWS - 5 - 1
|
||||
buffer.resize(INIT_COLS, INIT_ROWS - 10)
|
||||
# Trim 5 rows
|
||||
assert_eq(buffer.lines.length, INIT_ROWS - 5)
|
||||
# Shift the viewport down 5 rows
|
||||
assert_eq(buffer.ydisp, 5)
|
||||
assert_eq(buffer.ybase, 5)
|
||||
|
||||
|
||||
func test_no_scrollback_trims_from_the_top_of_the_buffer_when_the_cursor_reaches_the_bottom():
|
||||
buffer = Buffer.new(true, TestUtils.MockOptionsService.new({"scrollback": 0}), buffer_service)
|
||||
assert_eq(buffer.lines.max_length, INIT_ROWS)
|
||||
buffer.y = INIT_ROWS - 1
|
||||
buffer.fill_viewport_rows()
|
||||
var ch_data = buffer.lines.get_line(5).load_cell(0, CellData.new()).get_as_char_data()
|
||||
ch_data[1] = "a"
|
||||
buffer.lines.get_line(5).set_cell(0, CellData.from_char_data(ch_data))
|
||||
ch_data = buffer.lines.get_line(INIT_ROWS - 1).load_cell(0, CellData.new()).get_as_char_data()
|
||||
ch_data[1] = "b"
|
||||
buffer.lines.get_line(INIT_ROWS - 1).set_cell(0, CellData.from_char_data(ch_data))
|
||||
buffer.resize(INIT_COLS, INIT_ROWS - 5)
|
||||
assert_eq(buffer.lines.get_line(0).load_cell(0, CellData.new()).get_as_char_data()[1], "a")
|
||||
assert_eq(buffer.lines.get_line(INIT_ROWS - 1 - 5).load_cell(0, CellData.new()).get_as_char_data()[1], "b")
|
||||
|
||||
|
||||
func test_row_size_increase_adds_blank_lines_to_empty_buffer():
|
||||
assert_eq(buffer.ydisp, 0)
|
||||
buffer.resize(INIT_COLS, INIT_ROWS + 10)
|
||||
assert_eq(buffer.ydisp, 0)
|
||||
assert_eq(buffer.lines.length, INIT_ROWS + 10)
|
||||
|
||||
func test_row_size_increase_shows_more_of_the_buffer_above():
|
||||
# Create 10 extra blank lines
|
||||
for i in range(10):
|
||||
buffer.lines.push(buffer.get_blank_line(AttributeData.new()))
|
||||
# Set cursor to the bottom of the buffer
|
||||
buffer.y = INIT_ROWS - 1
|
||||
# Scroll down 10 lines
|
||||
buffer.ybase = 10
|
||||
buffer.ydisp = 10
|
||||
assert_eq(buffer.lines.length, INIT_ROWS + 10)
|
||||
buffer.resize(INIT_COLS, INIT_ROWS + 5)
|
||||
# Should be 5 more lines
|
||||
assert_eq(buffer.ydisp, 5)
|
||||
assert_eq(buffer.ybase, 5)
|
||||
# Should not trim the buffer
|
||||
assert_eq(buffer.lines.length, INIT_ROWS + 10)
|
||||
|
||||
|
||||
func test_row_size_increase_shows_more_of_the_buffer_below_when_the_viewort_is_at_the_top_of_the_buffer():
|
||||
# Create 10 extra blank lines
|
||||
for i in range(10):
|
||||
buffer.lines.push(buffer.get_blank_line(AttributeData.new()))
|
||||
# Set cursor to the bottom of the buffer
|
||||
buffer.y = INIT_ROWS - 1
|
||||
# Scroll down 10 lines
|
||||
buffer.ybase = 10
|
||||
buffer.ydisp = 0
|
||||
assert_eq(buffer.lines.length, INIT_ROWS + 10)
|
||||
buffer.resize(INIT_COLS, INIT_ROWS + 5)
|
||||
# The viewport should remain at the top
|
||||
assert_eq(buffer.ydisp, 0)
|
||||
# The buffer ybase should move up 5 lines
|
||||
assert_eq(buffer.ybase, 5)
|
||||
# Should not trim the buffer
|
||||
assert_eq(buffer.lines.length, INIT_ROWS + 10)
|
||||
|
||||
|
||||
func test_row_and_column_increase_resizes_properly():
|
||||
buffer.resize(INIT_COLS + 5, INIT_ROWS + 5)
|
||||
assert_eq(buffer.lines.length, INIT_ROWS + 5)
|
||||
buffer.resize(INIT_COLS - 5, INIT_ROWS)
|
||||
assert_eq(buffer.lines.length, INIT_ROWS)
|
||||
|
||||
|
||||
func test_reflow_does_not_wrap_empty_lines():
|
||||
assert_eq(buffer.lines.length, INIT_ROWS)
|
||||
buffer.resize(INIT_COLS - 5, INIT_ROWS)
|
||||
assert_eq(buffer.lines.length, INIT_ROWS)
|
||||
|
||||
|
||||
func test_reflow_shrinks_row_length():
|
||||
buffer.resize(5, 10)
|
||||
assert_eq(buffer.lines.length, 10)
|
||||
for i in range(10):
|
||||
assert_eq(buffer.lines.get_line(i).length, 5)
|
||||
|
||||
|
||||
func test_reflow_wraps_and_unwraps_lines():
|
||||
buffer.resize(5, 10)
|
||||
var first_line = buffer.lines.get_line(0)
|
||||
for i in range(5):
|
||||
var code = "a".ord_at(0) + i
|
||||
var ch = char(code)
|
||||
first_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
|
||||
buffer.y = 1
|
||||
assert_eq(buffer.lines.get_line(0).length, 5)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcde")
|
||||
buffer.resize(1, 10)
|
||||
assert_eq(buffer.lines.length, 10)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "a")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), "b")
|
||||
assert_eq(buffer.lines.get_line(2).translate_to_string(), "c")
|
||||
assert_eq(buffer.lines.get_line(3).translate_to_string(), "d")
|
||||
assert_eq(buffer.lines.get_line(4).translate_to_string(), "e")
|
||||
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(6).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(7).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(8).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(9).translate_to_string(), " ")
|
||||
buffer.resize(5, 10)
|
||||
assert_eq(buffer.lines.length, 10)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcde")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(2).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(3).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(4).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(6).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(7).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(8).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(9).translate_to_string(), " ")
|
||||
|
||||
|
||||
func test_discards_parts_of_wrapped_lines_that_go_out_of_the_scrollback():
|
||||
options_service.options.scrollback = 1
|
||||
buffer.resize(10, 5)
|
||||
var last_line = buffer.lines.get_line(3)
|
||||
for i in range(10):
|
||||
var code = "a".ord_at(0) + i
|
||||
var ch = char(code)
|
||||
last_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
|
||||
assert_eq(buffer.lines.length, 5)
|
||||
buffer.y = 4
|
||||
buffer.resize(2, 5)
|
||||
assert_eq(buffer.y, 4)
|
||||
assert_eq(buffer.ybase, 1)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "ab")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), "cd")
|
||||
assert_eq(buffer.lines.get_line(2).translate_to_string(), "ef")
|
||||
assert_eq(buffer.lines.get_line(3).translate_to_string(), "gh")
|
||||
assert_eq(buffer.lines.get_line(4).translate_to_string(), "ij")
|
||||
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
|
||||
buffer.resize(1, 5)
|
||||
assert_eq(buffer.y, 4)
|
||||
assert_eq(buffer.ybase, 1)
|
||||
assert_eq(buffer.lines.length, 6)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "f")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), "g")
|
||||
assert_eq(buffer.lines.get_line(2).translate_to_string(), "h")
|
||||
assert_eq(buffer.lines.get_line(3).translate_to_string(), "i")
|
||||
assert_eq(buffer.lines.get_line(4).translate_to_string(), "j")
|
||||
assert_eq(buffer.lines.get_line(5).translate_to_string(), " ")
|
||||
buffer.resize(10, 5)
|
||||
assert_eq(buffer.y, 1)
|
||||
assert_eq(buffer.ybase, 0)
|
||||
assert_eq(buffer.lines.length, 5)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "fghij ")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(2).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(3).translate_to_string(), " ")
|
||||
assert_eq(buffer.lines.get_line(4).translate_to_string(), " ")
|
||||
|
||||
|
||||
func test_removes_the_correct_amount_of_rows_when_reflowing_larger():
|
||||
# This is a regression test to ensure that successive wrapped lines that are getting
|
||||
# 3+ lines removed on a reflow actually remove the right lines
|
||||
buffer.resize(10, 10)
|
||||
buffer.y = 2
|
||||
var first_line = buffer.lines.get_line(0)
|
||||
var second_line = buffer.lines.get_line(1)
|
||||
for i in range(10):
|
||||
var code = "a".ord_at(0) + i
|
||||
var ch = char(code)
|
||||
first_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
|
||||
for i in range(10):
|
||||
var code = "0".ord_at(0) + i
|
||||
var ch = char(code)
|
||||
second_line.set_cell(i, CellData.from_char_data([0, ch, 1, code]))
|
||||
assert_eq(buffer.lines.length, 10)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcdefghij")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), "0123456789")
|
||||
for i in range(2, 10):
|
||||
assert_eq(buffer.lines.get_line(i).translate_to_string(), " ")
|
||||
buffer.resize(2, 10)
|
||||
assert_eq(buffer.ybase, 1)
|
||||
assert_eq(buffer.lines.length, 11)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "ab")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), "cd")
|
||||
assert_eq(buffer.lines.get_line(2).translate_to_string(), "ef")
|
||||
assert_eq(buffer.lines.get_line(3).translate_to_string(), "gh")
|
||||
assert_eq(buffer.lines.get_line(4).translate_to_string(), "ij")
|
||||
assert_eq(buffer.lines.get_line(5).translate_to_string(), "01")
|
||||
assert_eq(buffer.lines.get_line(6).translate_to_string(), "23")
|
||||
assert_eq(buffer.lines.get_line(7).translate_to_string(), "45")
|
||||
assert_eq(buffer.lines.get_line(8).translate_to_string(), "67")
|
||||
assert_eq(buffer.lines.get_line(9).translate_to_string(), "89")
|
||||
assert_eq(buffer.lines.get_line(10).translate_to_string(), " ")
|
||||
buffer.resize(10, 10)
|
||||
assert_eq(buffer.ybase, 0)
|
||||
assert_eq(buffer.lines.length, 10)
|
||||
assert_eq(buffer.lines.get_line(0).translate_to_string(), "abcdefghij")
|
||||
assert_eq(buffer.lines.get_line(1).translate_to_string(), "0123456789")
|
||||
for i in range(2, 10):
|
||||
assert_eq(buffer.lines.get_line(i).translate_to_string(), " ",
|
||||
"line %d is incorrect" % i)
|
||||
|
|
|
@ -144,7 +144,6 @@ class TestCellData:
|
|||
|
||||
func before_each():
|
||||
cell = CellData.new()
|
||||
|
||||
|
||||
|
||||
func test_char_data_cell_data_equality():
|
||||
|
@ -242,8 +241,97 @@ class TestBufferLine:
|
|||
[6, 'f', 0, 'f'.ord_at(0)],
|
||||
[5, 'e', 0, 'e'.ord_at(0)],
|
||||
])
|
||||
|
||||
|
||||
func test_copy_from():
|
||||
var line = BufferLineTest.new(5)
|
||||
line.set_cell(0, CellData.from_char_data([1, 'a', 0, 'a'.ord_at(0)]))
|
||||
line.set_cell(0, CellData.from_char_data([2, 'b', 0, 'b'.ord_at(0)]))
|
||||
line.set_cell(0, CellData.from_char_data([3, 'c', 0, 'c'.ord_at(0)]))
|
||||
line.set_cell(0, CellData.from_char_data([4, 'd', 0, 'd'.ord_at(0)]))
|
||||
line.set_cell(0, CellData.from_char_data([5, 'e', 0, 'e'.ord_at(0)]))
|
||||
var line2 = BufferLineTest.new(5, CellData.from_char_data([1, 'a', 0, 'a'.ord_at(0)]), true)
|
||||
line2.copy_from(line)
|
||||
assert_eq(line2.to_array(), line.to_array())
|
||||
assert_eq(line2.length, line.length)
|
||||
assert_eq(line2.is_wrapped, line.is_wrapped)
|
||||
|
||||
|
||||
class TestResize:
|
||||
extends "res://addons/gut/test.gd"
|
||||
|
||||
|
||||
var CHAR_DATA = [1, 'a', 0, 'a'.ord_at(0)]
|
||||
var line
|
||||
|
||||
func repeat(el, times: int) -> Array:
|
||||
var result = []
|
||||
result.resize(times)
|
||||
for i in range(times):
|
||||
result[i] = el
|
||||
return result
|
||||
|
||||
|
||||
func test_enlarge():
|
||||
line = BufferLineTest.new(5, CellData.from_char_data(CHAR_DATA), false)
|
||||
line.resize(10, CellData.from_char_data(CHAR_DATA))
|
||||
assert_eq(line.to_array(), repeat(CHAR_DATA, 10))
|
||||
|
||||
|
||||
func test_shrink():
|
||||
line = BufferLineTest.new(10, CellData.from_char_data(CHAR_DATA), false)
|
||||
line.resize(5, CellData.from_char_data(CHAR_DATA))
|
||||
assert_eq(line.to_array(), repeat(CHAR_DATA, 5))
|
||||
|
||||
|
||||
func test_shrink_to_0_length():
|
||||
line = BufferLineTest.new(10, CellData.from_char_data(CHAR_DATA), false)
|
||||
line.resize(0, CellData.from_char_data(CHAR_DATA))
|
||||
assert_eq(line.to_array(), repeat(CHAR_DATA, 0))
|
||||
|
||||
func shrink_then_enlarge():
|
||||
line = BufferLineTest.new(10, CellData.from_char_data(CHAR_DATA), false);
|
||||
line.set_cell(2, CellData.from_char_data([0, '😁', 1, '😁'.ord_at(0)]))
|
||||
line.set_cell(9, CellData.from_char_data([0, '😁', 1, '😁'.ord_at(0)]))
|
||||
assert_eq(line.translate_to_string(), 'aa😁aaaaaa😁')
|
||||
line.resize(5, CellData.from_char_data(CHAR_DATA))
|
||||
assert_eq(line.translate_to_string(), 'aa😁aa')
|
||||
line.resize(10, CellData.from_char_data(CHAR_DATA))
|
||||
assert_eq(line.translate_to_string(), 'aa😁aaaaaaa')
|
||||
|
||||
|
||||
class TestTrimLength:
|
||||
extends "res://addons/gut/test.gd"
|
||||
|
||||
|
||||
var line
|
||||
|
||||
|
||||
func before_each():
|
||||
line = BufferLineTest.new(3, CellData.from_char_data([Constants.DEFAULT_ATTR,
|
||||
Constants.NULL_CELL_CHAR, Constants.NULL_CELL_WIDTH, Constants.NULL_CELL_CODE]))
|
||||
|
||||
|
||||
func test_empty_line():
|
||||
assert_eq(line.get_trimmed_length(), 0)
|
||||
|
||||
|
||||
func test_ascii():
|
||||
line.set_cell(0, CellData.from_char_data([1, "a", 1, "a".ord_at(0)]))
|
||||
line.set_cell(2, CellData.from_char_data([1, "a", 1, "a".ord_at(0)]))
|
||||
assert_eq(line.get_trimmed_length(), 3)
|
||||
|
||||
|
||||
func test_unicode():
|
||||
line.set_cell(0, CellData.from_char_data([1, "\u1f914", 1, "\u1f914".ord_at(0)]))
|
||||
line.set_cell(2, CellData.from_char_data([1, "\u1f914", 1, "\u1f914".ord_at(0)]))
|
||||
assert_eq(line.get_trimmed_length(), 3)
|
||||
|
||||
|
||||
func test_one_cell():
|
||||
line.set_cell(0, CellData.from_char_data([1, "a", 1, "a".ord_at(0)]))
|
||||
assert_eq(line.get_trimmed_length(), 1)
|
||||
|
||||
# Skipped a bunch of tests here...
|
||||
|
||||
class TestAddCharToCell:
|
||||
extends "res://addons/gut/test.gd"
|
||||
|
@ -293,7 +381,7 @@ class TestAddCharToCell:
|
|||
assert_eq(cell.is_combined(), Content.IS_COMBINED_MASK)
|
||||
|
||||
|
||||
class Testtranslate_to_string:
|
||||
class TestTranslateToString:
|
||||
extends "res://addons/gut/test.gd"
|
||||
|
||||
|
||||
|
|
201
test/unit/test_circular_list.gd
Normal file
201
test/unit/test_circular_list.gd
Normal file
|
@ -0,0 +1,201 @@
|
|||
# Copyright (c) 2016 The xterm.js authors. All rights reserved.
|
||||
# Ported to GDScript by the GodotXterm authors.
|
||||
# License MIT
|
||||
extends "res://addons/gut/test.gd"
|
||||
|
||||
|
||||
const CIRCULAR_LIST_PATH = "res://addons/godot_xterm/circular_list.gd"
|
||||
const CircularList = preload(CIRCULAR_LIST_PATH)
|
||||
|
||||
var list
|
||||
|
||||
|
||||
func before_each():
|
||||
list = CircularList.new(5)
|
||||
|
||||
|
||||
func test_push():
|
||||
list.push("1")
|
||||
list.push("2")
|
||||
list.push("3")
|
||||
list.push("4")
|
||||
list.push("5")
|
||||
assert_eq(list.get_line(0), "1")
|
||||
assert_eq(list.get_line(1), "2")
|
||||
assert_eq(list.get_line(2), "3")
|
||||
assert_eq(list.get_line(3), "4")
|
||||
assert_eq(list.get_line(4), "5")
|
||||
|
||||
|
||||
func test_splice_deletes_items():
|
||||
list = CircularList.new(2)
|
||||
list.push("1")
|
||||
list.push("2")
|
||||
list.splice(0, 1)
|
||||
assert_eq(list.length, 1)
|
||||
assert_eq(list.get_el(0), "2")
|
||||
list.push("3")
|
||||
list.splice(1, 1)
|
||||
assert_eq(list.length, 1)
|
||||
assert_eq(list.get_el(0), "2")
|
||||
|
||||
|
||||
func test_splice_inserts_items():
|
||||
list = CircularList.new(2)
|
||||
list.push("1")
|
||||
list.splice(0, 0, ["2"])
|
||||
assert_eq(list.length, 2)
|
||||
assert_eq(list.get_el(0), "2")
|
||||
assert_eq(list.get_el(1), "1")
|
||||
list.splice(1, 0, ["3"])
|
||||
assert_eq(list.length, 2)
|
||||
assert_eq(list.get_el(0), "3")
|
||||
assert_eq(list.get_el(1), "1")
|
||||
|
||||
|
||||
func test_splice_deletes_items_then_inserts_items():
|
||||
list = CircularList.new(3)
|
||||
list.push("1")
|
||||
list.push("2")
|
||||
list.splice(0, 1, ["3", "4"])
|
||||
assert_eq(list.length, 3)
|
||||
assert_eq(list.get_el(0), "3")
|
||||
assert_eq(list.get_el(1), "4")
|
||||
assert_eq(list.get_el(2), "2")
|
||||
|
||||
|
||||
func test_splice_wraps_the_array_correctly_when_more_items_are_inserted_than_deleted():
|
||||
list = CircularList.new(3)
|
||||
list.push("1")
|
||||
list.push("2")
|
||||
list.splice(1, 0, ["3", "4"])
|
||||
assert_eq(list.length, 3)
|
||||
assert_eq(list.get_el(0), "3")
|
||||
assert_eq(list.get_el(1), "4")
|
||||
assert_eq(list.get_el(2), "2")
|
||||
|
||||
|
||||
class TestShiftElements:
|
||||
extends "res://addons/gut/test.gd"
|
||||
|
||||
|
||||
var list
|
||||
|
||||
|
||||
func before_each():
|
||||
list = CircularList.new(5)
|
||||
|
||||
|
||||
func test_does_not_mutate_the_list_when_count_is_0():
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.shift_elements(0, 0, 1)
|
||||
assert_eq(list.length, 2)
|
||||
assert_eq(list.get_el(0), 1)
|
||||
assert_eq(list.get_el(1), 2)
|
||||
|
||||
|
||||
func test_pushes_errors_for_invalid_args():
|
||||
list = partial_double(CIRCULAR_LIST_PATH).new()
|
||||
list.max_length = 5
|
||||
list.push(1)
|
||||
list.shift_elements(-1, 1, 1)
|
||||
assert_called(list, "push_error", ["start argument out of range"])
|
||||
list.shift_elements(1, 1, 1)
|
||||
assert_called(list, "push_error", ["start argument out of range"])
|
||||
list.shift_elements(0, 1, -1)
|
||||
assert_called(list, "push_error", ["cannot shift elements in list beyond index 0"])
|
||||
|
||||
|
||||
func test_trim_start_removes_items_from_the_beginning_of_the_list():
|
||||
list.push("1")
|
||||
list.push("2")
|
||||
list.push("3")
|
||||
list.push("4")
|
||||
list.push("5")
|
||||
list.trim_start(1)
|
||||
assert_eq(list.length, 4)
|
||||
assert_eq(list.get_el(0), "2")
|
||||
assert_eq(list.get_el(1), "3")
|
||||
assert_eq(list.get_el(2), "4")
|
||||
assert_eq(list.get_el(3), "5")
|
||||
list.trim_start(2)
|
||||
assert_eq(list.length, 2)
|
||||
assert_eq(list.get_el(0), "4")
|
||||
assert_eq(list.get_el(1), "5")
|
||||
|
||||
|
||||
func test_trim_start_removes_all_items_if_the_requested_trim_amount_is_larger_than_the_lists_length():
|
||||
list.push("1")
|
||||
list.trim_start(2)
|
||||
assert_eq(list.length, 0)
|
||||
|
||||
|
||||
func test_shifts_an_element_forward():
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.shift_elements(0, 1, 1)
|
||||
assert_eq(list.length, 2)
|
||||
assert_eq(list.get_el(0), 1)
|
||||
assert_eq(list.get_el(1), 1)
|
||||
|
||||
|
||||
func test_shifts_elements_forward():
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.push(3)
|
||||
list.push(4)
|
||||
list.shift_elements(0, 2, 2)
|
||||
assert_eq(list.length, 4)
|
||||
assert_eq(list.get_el(0), 1)
|
||||
assert_eq(list.get_el(1), 2)
|
||||
assert_eq(list.get_el(2), 1)
|
||||
assert_eq(list.get_el(3), 2)
|
||||
|
||||
|
||||
func test_shifts_elements_forward_expanding_the_list_if_needed():
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.shift_elements(0, 2, 2)
|
||||
assert_eq(list.length, 4)
|
||||
assert_eq(list.get_el(0), 1)
|
||||
assert_eq(list.get_el(1), 2)
|
||||
assert_eq(list.get_el(2), 1)
|
||||
assert_eq(list.get_el(3), 2)
|
||||
|
||||
|
||||
func test_shifts_elements_forward_wrapping_the_list_if_needed():
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.push(3)
|
||||
list.push(4)
|
||||
list.push(5)
|
||||
list.shift_elements(2, 2, 3)
|
||||
assert_eq(list.length, 5)
|
||||
assert_eq(list.get_el(0), 3)
|
||||
assert_eq(list.get_el(1), 4)
|
||||
assert_eq(list.get_el(2), 5)
|
||||
assert_eq(list.get_el(3), 3)
|
||||
assert_eq(list.get_el(4), 4)
|
||||
|
||||
|
||||
func test_shifts_an_element_backwards():
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.shift_elements(1, 1, -1)
|
||||
assert_eq(list.length, 2)
|
||||
assert_eq(list.get_el(0), 2)
|
||||
assert_eq(list.get_el(1), 2)
|
||||
|
||||
|
||||
func test_shiftS_elements_backwards():
|
||||
list.push(1)
|
||||
list.push(2)
|
||||
list.push(3)
|
||||
list.push(4)
|
||||
list.shift_elements(2, 2, -2)
|
||||
assert_eq(list.length, 4)
|
||||
assert_eq(list.get_el(0), 3)
|
||||
assert_eq(list.get_el(1), 4)
|
||||
assert_eq(list.get_el(2), 3)
|
||||
assert_eq(list.get_el(3), 4)
|
|
@ -9,6 +9,10 @@ const InputHandler = preload("res://addons/godot_xterm/input_handler.gd")
|
|||
const CharsetService = preload("res://addons/godot_xterm/services/charset_service.gd")
|
||||
const Params = preload("res://addons/godot_xterm/parser/params.gd")
|
||||
const CoreService = preload("res://addons/godot_xterm/services/core_service.gd")
|
||||
const Constants = preload("res://addons/godot_xterm/buffer/constants.gd")
|
||||
const OptionsService = preload("res://addons/godot_xterm/services/options_service.gd")
|
||||
|
||||
const CursorStyle = Constants.CursorStyle
|
||||
|
||||
var options_service
|
||||
var buffer_service
|
||||
|
@ -49,12 +53,76 @@ func before_each():
|
|||
charset_service = CharsetService.new()
|
||||
core_service = CoreService.new()
|
||||
input_handler = InputHandler.new(buffer_service, core_service, charset_service, options_service)
|
||||
|
||||
|
||||
func test_save_and_restore_cursor():
|
||||
buffer_service.buffer.x = 1
|
||||
buffer_service.buffer.y = 2
|
||||
buffer_service.buffer.ybase = 0
|
||||
input_handler._cur_attr_data.fg = 3
|
||||
# Save cursor position
|
||||
input_handler.save_cursor()
|
||||
assert_eq(buffer_service.buffer.x, 1)
|
||||
assert_eq(buffer_service.buffer.y, 2)
|
||||
assert_eq(input_handler._cur_attr_data.fg, 3)
|
||||
# Change the cursor position
|
||||
buffer_service.buffer.x = 10
|
||||
buffer_service.buffer.y = 20
|
||||
input_handler._cur_attr_data.fg = 30
|
||||
# Restore cursor position
|
||||
input_handler.restore_cursor()
|
||||
assert_eq(buffer_service.buffer.x, 1)
|
||||
assert_eq(buffer_service.buffer.y, 2)
|
||||
assert_eq(input_handler._cur_attr_data.fg, 3)
|
||||
|
||||
# Skipping lots of tests here...
|
||||
|
||||
func test_set_cursor_style():
|
||||
input_handler.set_cursor_style(Params.from_array([0]))
|
||||
assert_eq(options_service.options.cursor_style, CursorStyle.BLOCK)
|
||||
assert_eq(options_service.options.cursor_blink, true)
|
||||
|
||||
options_service.options = OptionsService.TerminalOptions.new()
|
||||
input_handler.set_cursor_style(Params.from_array([1]))
|
||||
assert_eq(options_service.options.cursor_style, CursorStyle.BLOCK)
|
||||
assert_eq(options_service.options.cursor_blink, true)
|
||||
|
||||
options_service.options = OptionsService.TerminalOptions.new()
|
||||
input_handler.set_cursor_style(Params.from_array([2]))
|
||||
assert_eq(options_service.options.cursor_style, CursorStyle.BLOCK)
|
||||
assert_eq(options_service.options.cursor_blink, false)
|
||||
|
||||
options_service.options = OptionsService.TerminalOptions.new()
|
||||
input_handler.set_cursor_style(Params.from_array([3]))
|
||||
assert_eq(options_service.options.cursor_style, CursorStyle.UNDERLINE)
|
||||
assert_eq(options_service.options.cursor_blink, true)
|
||||
|
||||
options_service.options = OptionsService.TerminalOptions.new()
|
||||
input_handler.set_cursor_style(Params.from_array([4]))
|
||||
assert_eq(options_service.options.cursor_style, CursorStyle.UNDERLINE)
|
||||
assert_eq(options_service.options.cursor_blink, false)
|
||||
|
||||
options_service.options = OptionsService.TerminalOptions.new()
|
||||
input_handler.set_cursor_style(Params.from_array([5]))
|
||||
assert_eq(options_service.options.cursor_style, CursorStyle.BAR)
|
||||
assert_eq(options_service.options.cursor_blink, true)
|
||||
|
||||
options_service.options = OptionsService.TerminalOptions.new()
|
||||
input_handler.set_cursor_style(Params.from_array([6]))
|
||||
assert_eq(options_service.options.cursor_style, CursorStyle.BAR)
|
||||
assert_eq(options_service.options.cursor_blink, false)
|
||||
|
||||
|
||||
func test_set_mode_toggles_bracketed_paste_mode():
|
||||
# Set bracketed paste mode
|
||||
input_handler.set_mode_private(Params.from_array([2004]))
|
||||
assert_true(core_service.dec_private_modes.bracketed_paste_mode)
|
||||
# Reset bracketed paste mode
|
||||
input_handler.reset_mode_private(Params.from_array([2004]))
|
||||
assert_false(core_service.dec_private_modes.bracketed_paste_mode)
|
||||
|
||||
|
||||
func test_erase_in_line():
|
||||
buffer_service = TestUtils.MockBufferService.new(10, 3, options_service)
|
||||
buffer_service = TestUtils.MockBufferService.new(80, 30, options_service)
|
||||
input_handler = InputHandler.new(buffer_service, core_service, charset_service, options_service)
|
||||
|
||||
# fill 6 lines to test 3 different states
|
||||
|
@ -65,27 +133,27 @@ func test_erase_in_line():
|
|||
|
||||
# params[0] - right erase
|
||||
buffer_service.buffer.y = 0
|
||||
buffer_service.buffer.x = 7
|
||||
buffer_service.buffer.x = 70
|
||||
input_handler.erase_in_line(Params.from_array([0]))
|
||||
assert_eq(buffer_service.buffer.lines.get_el(0).translate_to_string(false),
|
||||
repeat("a", 7) + " ")
|
||||
assert_eq(buffer_service.buffer.lines.get_line(0).translate_to_string(false),
|
||||
repeat("a", 70) + " ")
|
||||
|
||||
# # params[1] - left erase
|
||||
# buffer_service.buffer.y = 1
|
||||
# buffer_service.buffer.x = 70
|
||||
# input_handler.erase_in_line(Params.from_array([1]))
|
||||
# assert_eq(buffer_service.buffer.lines.get_el(1).translate_to_string(false),
|
||||
# repeat(" ", 70) + " aaaaaaaaa")
|
||||
#
|
||||
# # params[1] - left erase
|
||||
# buffer_service.buffer.y = 2
|
||||
# buffer_service.buffer.x = 70
|
||||
# input_handler.erase_in_line(Params.from_array([2]))
|
||||
# assert_eq(buffer_service.buffer.lines.get_el(2).translate_to_string(false),
|
||||
# repeat(" ", buffer_service.cols))
|
||||
# params[1] - left erase
|
||||
buffer_service.buffer.y = 1
|
||||
buffer_service.buffer.x = 70
|
||||
input_handler.erase_in_line(Params.from_array([1]))
|
||||
assert_eq(buffer_service.buffer.lines.get_line(1).translate_to_string(false),
|
||||
repeat(" ", 70) + " aaaaaaaaa")
|
||||
|
||||
# params[1] - left erase
|
||||
buffer_service.buffer.y = 2
|
||||
buffer_service.buffer.x = 70
|
||||
input_handler.erase_in_line(Params.from_array([2]))
|
||||
assert_eq(buffer_service.buffer.lines.get_line(2).translate_to_string(false),
|
||||
repeat(" ", buffer_service.cols))
|
||||
|
||||
|
||||
func skip_test_erase_in_display():
|
||||
func test_erase_in_display():
|
||||
buffer_service = TestUtils.MockBufferService.new(80, 7, options_service)
|
||||
input_handler = InputHandler.new(buffer_service, core_service, charset_service, options_service)
|
||||
|
||||
|
@ -119,7 +187,7 @@ func skip_test_erase_in_display():
|
|||
# reset
|
||||
for _i in range(buffer_service.rows):
|
||||
input_handler.parse(repeat("a", buffer_service.cols))
|
||||
|
||||
|
||||
# params [1] - left and above
|
||||
buffer_service.buffer.y = 5;
|
||||
buffer_service.buffer.x = 40;
|
||||
|
@ -169,36 +237,38 @@ func skip_test_erase_in_display():
|
|||
"",
|
||||
"",
|
||||
]))
|
||||
#
|
||||
# # reset and add a wrapped line
|
||||
# buffer_service.buffer.y = 0;
|
||||
# buffer_service.buffer.x = 0;
|
||||
# input_handler.parse(Array(buffer_service.cols + 1).join('a')); # line 0
|
||||
# input_handler.parse(Array(buffer_service.cols + 10).join('a')); # line 1 and 2
|
||||
# for (let i = 3; i < buffer_service.rows; ++i) input_handler.parse(Array(buffer_service.cols + 1).join('a'));
|
||||
#
|
||||
# # params[1] left and above with wrap
|
||||
# # confirm precondition that line 2 is wrapped
|
||||
# expect(buffer_service.buffer.lines.get(2)!.isWrapped).true;
|
||||
# buffer_service.buffer.y = 2;
|
||||
# buffer_service.buffer.x = 40;
|
||||
# input_handler.erase_in_display(Params.from_array([1]));
|
||||
# expect(buffer_service.buffer.lines.get(2)!.isWrapped).false;
|
||||
#
|
||||
# # reset and add a wrapped line
|
||||
# buffer_service.buffer.y = 0;
|
||||
# buffer_service.buffer.x = 0;
|
||||
# input_handler.parse(Array(buffer_service.cols + 1).join('a')); # line 0
|
||||
# input_handler.parse(Array(buffer_service.cols + 10).join('a')); # line 1 and 2
|
||||
# for (let i = 3; i < buffer_service.rows; ++i) input_handler.parse(Array(buffer_service.cols + 1).join('a'));
|
||||
#
|
||||
# # params[1] left and above with wrap
|
||||
# # confirm precondition that line 2 is wrapped
|
||||
# expect(buffer_service.buffer.lines.get(2)!.isWrapped).true;
|
||||
# buffer_service.buffer.y = 1;
|
||||
# buffer_service.buffer.x = 90; # Cursor is beyond last column
|
||||
# input_handler.erase_in_display(Params.from_array([1]));
|
||||
# expect(buffer_service.buffer.lines.get(2)!.isWrapped).false;
|
||||
|
||||
# reset and add a wrapped line
|
||||
buffer_service.buffer.y = 0;
|
||||
buffer_service.buffer.x = 0;
|
||||
input_handler.parse(repeat("a", buffer_service.cols)) # line 0
|
||||
input_handler.parse(repeat("a", buffer_service.cols + 9)) # line 1 and 2
|
||||
for i in range(3, buffer_service.rows):
|
||||
input_handler.parse(repeat("a", buffer_service.cols))
|
||||
|
||||
# params[1] left and above with wrap
|
||||
# confirm precondition that line 2 is wrapped
|
||||
assert_true(buffer_service.buffer.lines.get_line(2).is_wrapped)
|
||||
buffer_service.buffer.y = 2
|
||||
buffer_service.buffer.x = 40
|
||||
input_handler.erase_in_display(Params.from_array([1]))
|
||||
assert_false(buffer_service.buffer.lines.get_line(2).is_wrapped)
|
||||
|
||||
# reset and add a wrapped line
|
||||
buffer_service.buffer.y = 0
|
||||
buffer_service.buffer.x = 0
|
||||
input_handler.parse(repeat("a", buffer_service.cols)) # line 0
|
||||
input_handler.parse(repeat("a", buffer_service.cols + 9)) # line 1 and 2
|
||||
for i in range(3, buffer_service.rows):
|
||||
input_handler.parse(repeat("a", buffer_service.cols))
|
||||
|
||||
# params[1] left and above with wrap
|
||||
# confirm precondition that line 2 is wrapped
|
||||
assert_true(buffer_service.buffer.lines.get_line(2).is_wrapped)
|
||||
buffer_service.buffer.y = 1
|
||||
buffer_service.buffer.x = 90 # Cursor is beyond last column
|
||||
input_handler.erase_in_display(Params.from_array([1]));
|
||||
assert_false(buffer_service.buffer.lines.get_line(2).is_wrapped)
|
||||
|
||||
|
||||
func test_print_does_not_cause_an_infinite_loop():
|
||||
|
|
|
@ -3,22 +3,27 @@
|
|||
# License MIT
|
||||
extends 'res://addons/gut/test.gd'
|
||||
|
||||
|
||||
const Params = preload("res://addons/godot_xterm/parser/params.gd")
|
||||
|
||||
|
||||
class TestParams:
|
||||
extends 'res://addons/gut/test.gd'
|
||||
|
||||
var params
|
||||
|
||||
|
||||
func before_each():
|
||||
params = Params.new()
|
||||
|
||||
|
||||
func test_respects_ctor_args():
|
||||
params = Params.new(12, 23)
|
||||
assert_eq(params.params.size(), 12)
|
||||
assert_eq(params.sub_params.size(), 23)
|
||||
assert_eq(params.to_array(), [])
|
||||
|
||||
|
||||
func test_add_param():
|
||||
params.add_param(1)
|
||||
assert_eq(params.length, 1)
|
||||
|
@ -30,6 +35,7 @@ class TestParams:
|
|||
assert_eq(params.to_array(), [1, 23])
|
||||
assert_eq(params.sub_params_length, 0)
|
||||
|
||||
|
||||
func test_add_sub_param():
|
||||
params.add_param(1)
|
||||
params.add_sub_param(2)
|
||||
|
@ -43,6 +49,7 @@ class TestParams:
|
|||
assert_eq(params.sub_params_length, 3)
|
||||
assert_eq(params.to_array(), [1, [2,3], 12345, [-1]])
|
||||
|
||||
|
||||
func test_should_not_add_sub_params_without_previous_param():
|
||||
params.add_sub_param(2)
|
||||
params.add_sub_param(3)
|
||||
|
@ -56,6 +63,7 @@ class TestParams:
|
|||
assert_eq(params.sub_params_length, 2)
|
||||
assert_eq(params.to_array(), [1, [2, 3]])
|
||||
|
||||
|
||||
func test_reset():
|
||||
params.add_param(1)
|
||||
params.add_sub_param(2)
|
||||
|
@ -92,13 +100,25 @@ class TestParams:
|
|||
# ignore leading sub params
|
||||
data = [[1,2], 12345, [-1]]
|
||||
assert_eq(Params.from_array(data).to_array(), [12345, [-1]])
|
||||
|
||||
|
||||
func test_has_sub_params_get_sub_params():
|
||||
params = Params.from_array([38, [2, 50, 100, 150], 5, [], 6])
|
||||
assert_eq(params.has_sub_params(0), true)
|
||||
assert_eq(params.get_sub_params(0), [2, 50, 100, 150])
|
||||
assert_eq(params.has_sub_params(1), false)
|
||||
assert_eq(params.get_sub_params(1), null)
|
||||
assert_eq(params.has_sub_params(2), false)
|
||||
assert_eq(params.get_sub_params(2), null)
|
||||
|
||||
|
||||
class TestParse:
|
||||
extends 'res://addons/gut/test.gd'
|
||||
|
||||
|
||||
var params
|
||||
|
||||
|
||||
func parse(params, s):
|
||||
params.reset()
|
||||
params.add_param(0)
|
||||
|
@ -124,18 +144,22 @@ class TestParse:
|
|||
i-=1
|
||||
# End for
|
||||
i+=1
|
||||
|
||||
|
||||
|
||||
func before_each():
|
||||
params = Params.new()
|
||||
|
||||
|
||||
|
||||
func test_param_defaults_to_0(): # ZDM (Zero Default Mode)
|
||||
parse(params, '')
|
||||
assert_eq(params.to_array(), [0])
|
||||
|
||||
|
||||
|
||||
func test_sub_param_defaults_to_neg_1():
|
||||
parse(params, ':')
|
||||
assert_eq(params.to_array(), [0, [-1]])
|
||||
|
||||
|
||||
|
||||
func test_reset_on_new_sequence():
|
||||
parse(params, '1;2;3')
|
||||
assert_eq(params.to_array(), [1, 2, 3])
|
||||
|
@ -145,7 +169,8 @@ class TestParse:
|
|||
assert_eq(params.to_array(), [4, [-1, 123, 5], 6, 7])
|
||||
parse(params, '')
|
||||
assert_eq(params.to_array(), [0])
|
||||
|
||||
|
||||
|
||||
func test_should_handle_length_restrictions_correctly():
|
||||
params = Params.new(3, 3)
|
||||
parse(params, '1;2;3')
|
||||
|
@ -162,7 +187,8 @@ class TestParse:
|
|||
# overlong sub params
|
||||
parse(params, '4;38:2::50:100:150;48:5:22')
|
||||
assert_eq(params.to_array(), [4, 38, [2, -1, 50], 48])
|
||||
|
||||
|
||||
|
||||
func test_typical_sequences():
|
||||
# SGR with semicolon syntax
|
||||
parse(params, '0;4;38;2;50;100;150;48;5;22')
|
||||
|
@ -173,15 +199,18 @@ class TestParse:
|
|||
# SGR colon style
|
||||
parse(params, '0;4;38:2::50:100:150;48:5:22')
|
||||
assert_eq(params.to_array(), [0, 4, 38, [2, -1, 50, 100, 150], 48, [5, 22]])
|
||||
|
||||
|
||||
|
||||
func test_clamp_parsed_params():
|
||||
parse(params, '2147483648')
|
||||
assert_eq(params.to_array(), [0x7FFFFFFF])
|
||||
|
||||
|
||||
|
||||
func test_clamp_parsed_sub_params():
|
||||
parse(params, ':2147483648')
|
||||
assert_eq(params.to_array(), [0, [0x7FFFFFFF]])
|
||||
|
||||
|
||||
|
||||
func test_should_cancel_subdigits_if_beyond_params_limit():
|
||||
parse(params, ';;;;;;;;;10;;;;;;;;;;20;;;;;;;;;;30;31;32;33;34;35::::::::')
|
||||
assert_eq(params.to_array(), [
|
||||
|
@ -190,13 +219,4 @@ class TestParse:
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 32
|
||||
])
|
||||
|
||||
# func test_should_carry_forward_is_sub_state():
|
||||
# parse(params, ['1:22:33', '44'])
|
||||
# assert_eq(params.to_array(), [1, [22, 3344]])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue