From 89843cd6928651171474b4ba486471f46a3bee1b Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Sat, 5 Jun 2021 15:11:45 +0200 Subject: Kernel+LibVT: Implement left-right scrolling This commit implements the left/right scrolling used in the `ICH`/`DCH` escape sequences for `VirtualConsole`. This brings us one step closer to VT420/xterm compatibility. We can now finally remove the last escape sequence related `ifdef`s. --- Kernel/TTY/VirtualConsole.cpp | 30 ++++++++++++++--- Kernel/TTY/VirtualConsole.h | 7 ++-- Userland/Libraries/LibVT/Terminal.cpp | 62 +++++++++++++++++++---------------- Userland/Libraries/LibVT/Terminal.h | 12 +++---- 4 files changed, 68 insertions(+), 43 deletions(-) diff --git a/Kernel/TTY/VirtualConsole.cpp b/Kernel/TTY/VirtualConsole.cpp index 8acc248f9f..e4c50127cb 100644 --- a/Kernel/TTY/VirtualConsole.cpp +++ b/Kernel/TTY/VirtualConsole.cpp @@ -86,14 +86,14 @@ void ConsoleImpl::clear_in_line(u16 row, u16 first_column, u16 last_column) m_client.clear_in_line(row, first_column, last_column); } -void ConsoleImpl::ICH(Parameters) +void ConsoleImpl::scroll_left(u16 row, u16 column, size_t count) { - // FIXME: Implement this + m_client.scroll_left(row, column, count); } -void ConsoleImpl::DCH(Parameters) +void ConsoleImpl::scroll_right(u16 row, u16 column, size_t count) { - // FIXME: Implement this + m_client.scroll_right(row, column, count); } void VirtualConsole::set_graphical(bool graphical) @@ -425,6 +425,28 @@ void VirtualConsole::scroll_down(u16 region_top, u16 region_bottom, size_t count m_lines[row].dirty = true; } +void VirtualConsole::scroll_left(u16 row, u16 column, size_t count) +{ + VERIFY(row < rows()); + VERIFY(column < columns()); + count = min(count, columns() - column); + memmove(&cell_at(column, row), &cell_at(column + count, row), sizeof(Cell) * (columns() - column - count)); + for (size_t i = column + count; i < columns(); ++i) + cell_at(i, row).clear(); + m_lines[row].dirty = true; +} + +void VirtualConsole::scroll_right(u16 row, u16 column, size_t count) +{ + VERIFY(row < rows()); + VERIFY(column < columns()); + count = min(count, columns() - column); + memmove(&cell_at(column + count, row), &cell_at(column, row), sizeof(Cell) * (columns() - column - count)); + for (size_t i = column; i < column + count; ++i) + cell_at(i, row).clear(); + m_lines[row].dirty = true; +} + void VirtualConsole::clear_in_line(u16 row, u16 first_column, u16 last_column) { VERIFY(row < rows()); diff --git a/Kernel/TTY/VirtualConsole.h b/Kernel/TTY/VirtualConsole.h index a25c5a3731..4acd096f05 100644 --- a/Kernel/TTY/VirtualConsole.h +++ b/Kernel/TTY/VirtualConsole.h @@ -39,11 +39,10 @@ private: virtual void scroll_up(u16 region_top, u16 region_bottom, size_t count) override; virtual void scroll_down(u16 region_top, u16 region_bottom, size_t count) override; + virtual void scroll_left(u16 row, u16 column, size_t count) override; + virtual void scroll_right(u16 row, u16 column, size_t count) override; virtual void put_character_at(unsigned row, unsigned column, u32 ch) override; virtual void clear_in_line(u16 row, u16 first_column, u16 last_column) override; - - virtual void ICH(Parameters) override; - virtual void DCH(Parameters) override; }; class VirtualConsole final : public TTY @@ -138,6 +137,8 @@ private: void scroll_down(u16 region_top, u16 region_bottom, size_t count); void scroll_up(u16 region_top, u16 region_bottom, size_t count); + void scroll_left(u16 row, u16 column, size_t count); + void scroll_right(u16 row, u16 column, size_t count); void clear_line(size_t index) { clear_in_line(index, 0, m_console_impl.columns() - 1); diff --git a/Userland/Libraries/LibVT/Terminal.cpp b/Userland/Libraries/LibVT/Terminal.cpp index 5641e44cfc..5e72d1dd8e 100644 --- a/Userland/Libraries/LibVT/Terminal.cpp +++ b/Userland/Libraries/LibVT/Terminal.cpp @@ -692,27 +692,15 @@ void Terminal::DL(Parameters params) scroll_up(cursor_row(), m_scroll_region_bottom, count); } -#ifndef KERNEL void Terminal::DCH(Parameters params) { int num = 1; if (params.size() >= 1 && params[0] != 0) num = params[0]; - auto& line = active_buffer()[cursor_row()]; - num = min(num, static_cast(line.length()) - cursor_column()); - - // Move n characters of line to the left - for (size_t i = cursor_column(); i < line.length() - num; i++) - line.cell_at(i) = line.cell_at(i + num); - - // Fill remainder of line with blanks - for (size_t i = line.length() - num; i < line.length(); i++) - line.set_code_point(i, ' '); - - line.set_dirty(true); + num = min(num, columns() - cursor_column()); + scroll_left(cursor_row(), cursor_column(), num); } -#endif void Terminal::linefeed() { @@ -807,6 +795,36 @@ void Terminal::scroll_down(u16 region_top, u16 region_bottom, size_t count) active_buffer()[row].set_dirty(true); } +// Insert `count` blank cells at the end of the line. Text moves left. +void Terminal::scroll_left(u16 row, u16 column, size_t count) +{ + VERIFY(row < rows()); + VERIFY(column < columns()); + count = min(count, columns() - column); + dbgln_if(TERMINAL_DEBUG, "Scroll left {} columns from line {} column {}", count, row, column); + + auto& line = active_buffer()[row]; + for (size_t i = column; i < columns() - count; ++i) + swap(line.cell_at(i), line.cell_at(i + count)); + clear_in_line(row, columns() - count, columns() - 1); + line.set_dirty(true); +} + +// Insert `count` blank cells after `row`. Text moves right. +void Terminal::scroll_right(u16 row, u16 column, size_t count) +{ + VERIFY(row < rows()); + VERIFY(column < columns()); + count = min(count, columns() - column); + dbgln_if(TERMINAL_DEBUG, "Scroll right {} columns from line {} column {}", count, row, column); + + auto& line = active_buffer()[row]; + for (int i = columns() - 1; i >= static_cast(column + count); --i) + swap(line.cell_at(i), line.cell_at(i - count)); + clear_in_line(row, column, column + count - 1); + line.set_dirty(true); +} + void Terminal::put_character_at(unsigned row, unsigned column, u32 code_point) { VERIFY(row < rows()); @@ -883,27 +901,15 @@ void Terminal::DSR(Parameters params) } } -#ifndef KERNEL void Terminal::ICH(Parameters params) { unsigned num = 1; if (params.size() >= 1 && params[0] != 0) num = params[0]; - auto& line = active_buffer()[cursor_row()]; - - auto max_insert = static_cast(line.length()) - cursor_column(); - num = min(num, max_insert); - // Move characters after cursor to the right - for (int i = line.length() - num - 1; i >= cursor_column(); --i) - line.cell_at(i + num) = line.cell_at(i); - // Fill n characters after cursor with blanks - for (unsigned i = 0; i < num; ++i) - line.set_code_point(cursor_column() + i, ' '); - - line.set_dirty(true); + num = min(num, columns() - cursor_column()); + scroll_right(cursor_row(), cursor_column(), num); } -#endif void Terminal::on_input(u8 byte) { diff --git a/Userland/Libraries/LibVT/Terminal.h b/Userland/Libraries/LibVT/Terminal.h index def255546e..ea719935ba 100644 --- a/Userland/Libraries/LibVT/Terminal.h +++ b/Userland/Libraries/LibVT/Terminal.h @@ -216,11 +216,15 @@ protected: #ifndef KERNEL void scroll_up(u16 region_top, u16 region_bottom, size_t count); void scroll_down(u16 region_top, u16 region_bottom, size_t count); + void scroll_left(u16 row, u16 column, size_t count); + void scroll_right(u16 row, u16 column, size_t count); void put_character_at(unsigned row, unsigned column, u32 ch); void clear_in_line(u16 row, u16 first_column, u16 last_column); #else virtual void scroll_up(u16 region_top, u16 region_bottom, size_t count) = 0; virtual void scroll_down(u16 region_top, u16 region_bottom, size_t count) = 0; + virtual void scroll_left(u16 row, u16 column, size_t count) = 0; + virtual void scroll_right(u16 row, u16 column, size_t count) = 0; virtual void put_character_at(unsigned row, unsigned column, u32 ch) = 0; virtual void clear_in_line(u16 row, u16 first_column, u16 last_column) = 0; #endif @@ -306,12 +310,8 @@ protected: // DECSCUSR - Set Cursor Style void DECSCUSR(Parameters); -#ifndef KERNEL // ICH - Insert Character void ICH(Parameters); -#else - virtual void ICH(Parameters) = 0; -#endif // SU - Scroll Up (called "Pan Down" in VT510) void SU(Parameters); @@ -322,12 +322,8 @@ protected: // IL - Insert Line void IL(Parameters); -#ifndef KERNEL // DCH - Delete Character void DCH(Parameters); -#else - virtual void DCH(Parameters) = 0; -#endif // DL - Delete Line void DL(Parameters); -- cgit v1.2.3