mirror of
https://github.com/lihop/godot-xterm.git
synced 2024-11-22 09:40:25 +01:00
feat(term): implement clear() method
Clears all but the bottommost row of the terminal (including scrollback buffer) and moves the bottommost row to the top.
This commit is contained in:
parent
fc03595e29
commit
d00a31fb45
4 changed files with 82 additions and 12 deletions
|
@ -75,8 +75,8 @@ void Terminal::_bind_methods()
|
||||||
ClassDB::bind_method(D_METHOD("get_copy_on_selection"), &Terminal::get_copy_on_selection);
|
ClassDB::bind_method(D_METHOD("get_copy_on_selection"), &Terminal::get_copy_on_selection);
|
||||||
ClassDB::add_property("Terminal", PropertyInfo(Variant::BOOL, "copy_on_selection"), "set_copy_on_selection", "get_copy_on_selection");
|
ClassDB::add_property("Terminal", PropertyInfo(Variant::BOOL, "copy_on_selection"), "set_copy_on_selection", "get_copy_on_selection");
|
||||||
|
|
||||||
// Methods.
|
// Other methods.
|
||||||
|
ClassDB::bind_method(D_METHOD("clear"), &Terminal::clear);
|
||||||
ClassDB::bind_method(D_METHOD("write", "data"), &Terminal::write);
|
ClassDB::bind_method(D_METHOD("write", "data"), &Terminal::write);
|
||||||
ClassDB::bind_method(D_METHOD("get_cursor_pos"), &Terminal::get_cursor_pos);
|
ClassDB::bind_method(D_METHOD("get_cursor_pos"), &Terminal::get_cursor_pos);
|
||||||
ClassDB::bind_method(D_METHOD("get_cell_size"), &Terminal::get_cell_size);
|
ClassDB::bind_method(D_METHOD("get_cell_size"), &Terminal::get_cell_size);
|
||||||
|
@ -642,6 +642,19 @@ double Terminal::get_blink_off_time() const
|
||||||
return blink_off_time;
|
return blink_off_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Terminal::clear() {
|
||||||
|
// Resize the terminal to a single row, forcing content above in to the scrollback buffer.
|
||||||
|
tsm_screen_resize(screen, cols, 1);
|
||||||
|
|
||||||
|
// Clear the scrollback buffer (hence clearing the content that was above).
|
||||||
|
tsm_screen_clear_sb(screen);
|
||||||
|
|
||||||
|
// Resize the screen to its original size.
|
||||||
|
tsm_screen_resize(screen, cols, rows);
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
String Terminal::_copy_screen(ScreenCopyFunction func) {
|
String Terminal::_copy_screen(ScreenCopyFunction func) {
|
||||||
char *out;
|
char *out;
|
||||||
PackedByteArray data;
|
PackedByteArray data;
|
||||||
|
|
|
@ -72,6 +72,8 @@ namespace godot
|
||||||
void set_blink_off_time(const double p_blink_off_time);
|
void set_blink_off_time(const double p_blink_off_time);
|
||||||
double get_blink_off_time() const;
|
double get_blink_off_time() const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
String copy_all();
|
String copy_all();
|
||||||
String copy_selection();
|
String copy_selection();
|
||||||
void set_copy_on_selection(const bool p_enable);
|
void set_copy_on_selection(const bool p_enable);
|
||||||
|
|
|
@ -12,7 +12,7 @@ func get_described_class():
|
||||||
func pick_cell_color(cell := Vector2i(0, 0)) -> Color:
|
func pick_cell_color(cell := Vector2i(0, 0)) -> Color:
|
||||||
var cell_size = subject.get_cell_size()
|
var cell_size = subject.get_cell_size()
|
||||||
var pixelv = Vector2(cell) * cell_size + (cell_size / 2)
|
var pixelv = Vector2(cell) * cell_size + (cell_size / 2)
|
||||||
return get_viewport().get_texture().get_image().get_pixelv(cell_size / 2)
|
return get_viewport().get_texture().get_image().get_pixelv(pixelv)
|
||||||
|
|
||||||
|
|
||||||
func before_each():
|
func before_each():
|
||||||
|
@ -27,9 +27,20 @@ func before_each():
|
||||||
class TestRendering:
|
class TestRendering:
|
||||||
extends RenderingTest
|
extends RenderingTest
|
||||||
|
|
||||||
|
# Fill the terminal with colored blocks.
|
||||||
|
func fill_color(color = Color.BLACK, rows: int = subject.get_rows()):
|
||||||
|
subject.write("\u001b[38;2;%d;%d;%dm" % [color.r8, color.g8, color.b8])
|
||||||
|
subject.write("█".repeat(subject.get_cols() * rows))
|
||||||
|
|
||||||
|
func test_render():
|
||||||
|
fill_color(Color.BLUE)
|
||||||
|
await wait_for_signal(subject.draw, 3)
|
||||||
|
await wait_frames(15)
|
||||||
|
var cell_color = pick_cell_color()
|
||||||
|
assert_eq(cell_color, Color.BLUE)
|
||||||
|
|
||||||
func test_update():
|
func test_update():
|
||||||
subject.write("\u001b[38;2;255;0;0m")
|
fill_color(Color.RED)
|
||||||
subject.write("█".repeat(subject.get_cols() * subject.get_rows()))
|
|
||||||
await get_tree().physics_frame
|
await get_tree().physics_frame
|
||||||
subject.queue_redraw()
|
subject.queue_redraw()
|
||||||
await wait_for_signal(subject.draw, 3)
|
await wait_for_signal(subject.draw, 3)
|
||||||
|
@ -37,6 +48,30 @@ class TestRendering:
|
||||||
var cell_color = pick_cell_color(Vector2i(0, 0))
|
var cell_color = pick_cell_color(Vector2i(0, 0))
|
||||||
assert_eq(cell_color, Color.RED)
|
assert_eq(cell_color, Color.RED)
|
||||||
|
|
||||||
|
func test_clear_clears_all_but_the_first_row():
|
||||||
|
await wait_frames(15)
|
||||||
|
var cell = Vector2i(0, 1) # Pick a cell not on the first row.
|
||||||
|
var original_color = pick_cell_color(cell)
|
||||||
|
call_deferred("fill_color", Color.CYAN)
|
||||||
|
await wait_for_signal(subject.draw, 3)
|
||||||
|
await wait_frames(15)
|
||||||
|
subject.clear()
|
||||||
|
await wait_for_signal(subject.draw, 3)
|
||||||
|
await wait_frames(15)
|
||||||
|
var cell_color = pick_cell_color(cell)
|
||||||
|
assert_eq(cell_color, original_color)
|
||||||
|
|
||||||
|
func test_clear_keeps_the_last_row():
|
||||||
|
fill_color(Color.GREEN)
|
||||||
|
fill_color(Color.ORANGE, 1)
|
||||||
|
await wait_for_signal(subject.draw, 3)
|
||||||
|
await wait_frames(15)
|
||||||
|
subject.clear()
|
||||||
|
await wait_for_signal(subject.draw, 3)
|
||||||
|
await wait_frames(15)
|
||||||
|
var cell_color = pick_cell_color(Vector2i(0, 0))
|
||||||
|
assert_eq(cell_color, Color.ORANGE)
|
||||||
|
|
||||||
|
|
||||||
class TestKeyPressed:
|
class TestKeyPressed:
|
||||||
extends RenderingTest
|
extends RenderingTest
|
||||||
|
|
|
@ -13,6 +13,13 @@ func before_each():
|
||||||
subject.size = Vector2(400, 200)
|
subject.size = Vector2(400, 200)
|
||||||
|
|
||||||
|
|
||||||
|
# Helper function to fill the screen with the given character.
|
||||||
|
func fill_screen(char: String = "A") -> String:
|
||||||
|
var result = char.repeat(subject.get_cols() * subject.get_rows())
|
||||||
|
subject.write(result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
class TestInterface:
|
class TestInterface:
|
||||||
extends TerminalTest
|
extends TerminalTest
|
||||||
|
|
||||||
|
@ -44,8 +51,7 @@ class TestInterface:
|
||||||
|
|
||||||
# Methods.
|
# Methods.
|
||||||
|
|
||||||
# TODO: Implement clear() method.
|
func test_has_method_clear():
|
||||||
func xtest_has_method_clear():
|
|
||||||
assert_has_method_with_return_type("clear", TYPE_NIL)
|
assert_has_method_with_return_type("clear", TYPE_NIL)
|
||||||
|
|
||||||
func test_has_method_copy_all():
|
func test_has_method_copy_all():
|
||||||
|
@ -196,11 +202,6 @@ class TestWrite:
|
||||||
class TestCopy:
|
class TestCopy:
|
||||||
extends TerminalTest
|
extends TerminalTest
|
||||||
|
|
||||||
func fill_screen(char: String = "A") -> String:
|
|
||||||
var result = char.repeat(subject.get_cols() * subject.get_rows())
|
|
||||||
subject.write(result)
|
|
||||||
return result
|
|
||||||
|
|
||||||
func test_copy_all_copies_the_entire_screen():
|
func test_copy_all_copies_the_entire_screen():
|
||||||
var text = fill_screen()
|
var text = fill_screen()
|
||||||
# The text will be wrapped over multiple lines and copy_all() preserves
|
# The text will be wrapped over multiple lines and copy_all() preserves
|
||||||
|
@ -220,3 +221,22 @@ class TestCopy:
|
||||||
var text = "アイウエオカキクケコサシスセソ"
|
var text = "アイウエオカキクケコサシスセソ"
|
||||||
subject.write(text)
|
subject.write(text)
|
||||||
assert_string_contains(subject.copy_all(), text)
|
assert_string_contains(subject.copy_all(), text)
|
||||||
|
|
||||||
|
|
||||||
|
class TestClear:
|
||||||
|
extends TerminalTest
|
||||||
|
|
||||||
|
func test_clear_an_empty_screen_changes_nothing():
|
||||||
|
var empty_screen = subject.copy_all()
|
||||||
|
subject.clear()
|
||||||
|
var screen_after = subject.copy_all()
|
||||||
|
assert_eq(screen_after, empty_screen)
|
||||||
|
|
||||||
|
func test_clear_when_screen_is_full_clears_all_but_the_bottommost_row():
|
||||||
|
fill_screen()
|
||||||
|
var final_line = "THIS SHOULDN'T BE CLEARED"
|
||||||
|
subject.write(final_line)
|
||||||
|
subject.clear()
|
||||||
|
var screen_after = subject.copy_all()
|
||||||
|
var expected = final_line + "\n".repeat(subject.get_rows())
|
||||||
|
assert_eq(screen_after, expected)
|
||||||
|
|
Loading…
Reference in a new issue