diff options
author | Andreas Kling <kling@serenityos.org> | 2021-02-26 20:28:22 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-02-27 09:23:06 +0100 |
commit | b7c66233f6650e69c705ea07830e9136b760727a (patch) | |
tree | 8bd55100b044203247899ae496dcda66fd4d5a08 /Userland/Libraries | |
parent | c58570ebafa7bb5b5e53152067297c8b12a317a7 (diff) | |
download | serenity-b7c66233f6650e69c705ea07830e9136b760727a.zip |
LibVT: Make VT::Line use a Vector for storage
This is preparation for non-destructive terminal resizing which will
require more dynamic storage for lines.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibVT/Line.cpp | 83 | ||||
-rw-r--r-- | Userland/Libraries/LibVT/Line.h | 51 | ||||
-rw-r--r-- | Userland/Libraries/LibVT/Terminal.cpp | 13 | ||||
-rw-r--r-- | Userland/Libraries/LibVT/TerminalWidget.cpp | 32 |
4 files changed, 58 insertions, 121 deletions
diff --git a/Userland/Libraries/LibVT/Line.cpp b/Userland/Libraries/LibVT/Line.cpp index 6818220e62..cb0d14981d 100644 --- a/Userland/Libraries/LibVT/Line.cpp +++ b/Userland/Libraries/LibVT/Line.cpp @@ -25,103 +25,52 @@ */ #include <LibVT/Line.h> -#include <string.h> namespace VT { -Line::Line(u16 length) +Line::Line(size_t length) { set_length(length); } Line::~Line() { - if (m_utf32) - delete[] m_code_points.as_u32; - else - delete[] m_code_points.as_u8; - delete[] m_attributes; } -template<typename CodepointType> -static CodepointType* create_new_code_point_array(size_t new_length, const CodepointType* old_code_points, size_t old_length) +void Line::set_length(size_t new_length) { - auto* new_code_points = new CodepointType[new_length]; - for (size_t i = 0; i < new_length; ++i) - new_code_points[i] = ' '; - if (old_code_points) { - for (size_t i = 0; i < min(old_length, new_length); ++i) { - new_code_points[i] = old_code_points[i]; - } - } - delete[] old_code_points; - return new_code_points; -} - -void Line::set_length(u16 new_length) -{ - if (m_length == new_length) + size_t old_length = length(); + if (old_length == new_length) return; - - if (m_utf32) - m_code_points.as_u32 = create_new_code_point_array<u32>(new_length, m_code_points.as_u32, m_length); - else - m_code_points.as_u8 = create_new_code_point_array<u8>(new_length, m_code_points.as_u8, m_length); - - auto* new_attributes = new Attribute[new_length]; - if (m_attributes) { - for (size_t i = 0; i < min(m_length, new_length); ++i) - new_attributes[i] = m_attributes[i]; - } - delete[] m_attributes; - m_attributes = new_attributes; - m_length = new_length; + m_cells.resize(new_length); } -void Line::clear(Attribute attribute) +void Line::clear(const Attribute& attribute) { if (m_dirty) { - for (u16 i = 0; i < m_length; ++i) { - set_code_point(i, ' '); - m_attributes[i] = attribute; + for (auto& cell : m_cells) { + cell = Cell { .code_point = ' ', .attribute = attribute }; } return; } - for (unsigned i = 0; i < m_length; ++i) { - if (code_point(i) != ' ') - m_dirty = true; - set_code_point(i, ' '); - } - for (unsigned i = 0; i < m_length; ++i) { - if (m_attributes[i] != attribute) - m_dirty = true; - m_attributes[i] = attribute; + for (auto& cell : m_cells) { + if (!m_dirty) + m_dirty = cell.code_point != ' ' || cell.attribute != attribute; + cell = Cell { .code_point = ' ', .attribute = attribute }; } } bool Line::has_only_one_background_color() const { - if (!m_length) + if (!length()) return true; // FIXME: Cache this result? - auto color = m_attributes[0].effective_background_color(); - for (size_t i = 1; i < m_length; ++i) { - if (m_attributes[i].effective_background_color() != color) + auto color = attribute_at(0).effective_background_color(); + for (size_t i = 1; i < length(); ++i) { + if (attribute_at(i).effective_background_color() != color) return false; } return true; } -void Line::convert_to_utf32() -{ - VERIFY(!m_utf32); - auto* new_code_points = new u32[m_length]; - for (size_t i = 0; i < m_length; ++i) { - new_code_points[i] = m_code_points.as_u8[i]; - } - delete m_code_points.as_u8; - m_code_points.as_u32 = new_code_points; - m_utf32 = true; -} - } diff --git a/Userland/Libraries/LibVT/Line.h b/Userland/Libraries/LibVT/Line.h index 5b3bcbd5c7..72e692a3da 100644 --- a/Userland/Libraries/LibVT/Line.h +++ b/Userland/Libraries/LibVT/Line.h @@ -28,6 +28,7 @@ #include <AK/Noncopyable.h> #include <AK/String.h> +#include <AK/Vector.h> #include <LibVT/XtermColors.h> namespace VT { @@ -44,8 +45,8 @@ struct Attribute { background_color = default_background_color; flags = Flags::NoAttributes; } - u32 foreground_color; - u32 background_color; + u32 foreground_color {}; + u32 background_color {}; u32 effective_background_color() const { return flags & Negative ? foreground_color : background_color; } u32 effective_foreground_color() const { return flags & Negative ? background_color : foreground_color; } @@ -84,52 +85,42 @@ class Line { AK_MAKE_NONMOVABLE(Line); public: - explicit Line(u16 columns); + explicit Line(size_t length); ~Line(); - void clear(Attribute); + struct Cell { + u32 code_point {}; + Attribute attribute; + }; + + const Attribute& attribute_at(size_t index) const { return m_cells[index].attribute; } + Attribute& attribute_at(size_t index) { return m_cells[index].attribute; } + + Cell& cell_at(size_t index) { return m_cells[index]; } + const Cell& cell_at(size_t index) const { return m_cells[index]; } + + void clear(const Attribute&); bool has_only_one_background_color() const; - void set_length(u16); - u16 length() const { return m_length; } + size_t length() const { return m_cells.size(); } + void set_length(size_t); u32 code_point(size_t index) const { - if (m_utf32) - return m_code_points.as_u32[index]; - return m_code_points.as_u8[index]; + return m_cells[index].code_point; } void set_code_point(size_t index, u32 code_point) { - if (!m_utf32 && code_point & 0xffffff80u) - convert_to_utf32(); - - if (m_utf32) - m_code_points.as_u32[index] = code_point; - else - m_code_points.as_u8[index] = code_point; + m_cells[index].code_point = code_point; } bool is_dirty() const { return m_dirty; } void set_dirty(bool b) { m_dirty = b; } - const Attribute* attributes() const { return m_attributes; } - Attribute* attributes() { return m_attributes; } - - void convert_to_utf32(); - - bool is_utf32() const { return m_utf32; } - private: - union { - u8* as_u8; - u32* as_u32; - } m_code_points { nullptr }; - Attribute* m_attributes { nullptr }; + Vector<Cell> m_cells; bool m_dirty { false }; - bool m_utf32 { false }; - u16 m_length { 0 }; }; } diff --git a/Userland/Libraries/LibVT/Terminal.cpp b/Userland/Libraries/LibVT/Terminal.cpp index 6d61c1853f..54d2eb8bd6 100644 --- a/Userland/Libraries/LibVT/Terminal.cpp +++ b/Userland/Libraries/LibVT/Terminal.cpp @@ -28,7 +28,6 @@ #include <AK/StringBuilder.h> #include <AK/StringView.h> #include <LibVT/Terminal.h> -#include <string.h> namespace VT { @@ -535,11 +534,11 @@ void Terminal::DCH(const ParamVector& params) auto& line = m_lines[m_cursor_row]; // Move n characters of line to the left - for (int i = m_cursor_column; i < line.length() - num; i++) + for (size_t i = m_cursor_column; i < line.length() - num; i++) line.set_code_point(i, line.code_point(i + num)); // Fill remainder of line with blanks - for (int i = line.length() - num; i < line.length(); i++) + for (size_t i = line.length() - num; i < line.length(); i++) line.set_code_point(i, ' '); line.set_dirty(true); @@ -759,8 +758,8 @@ void Terminal::put_character_at(unsigned row, unsigned column, u32 code_point) VERIFY(column < columns()); auto& line = m_lines[row]; line.set_code_point(column, code_point); - line.attributes()[column] = m_current_attribute; - line.attributes()[column].flags |= Attribute::Touched; + line.attribute_at(column) = m_current_attribute; + line.attribute_at(column).flags |= Attribute::Touched; line.set_dirty(true); m_last_code_point = code_point; @@ -1191,9 +1190,9 @@ Attribute Terminal::attribute_at(const Position& position) const if (position.row() >= static_cast<int>(line_count())) return {}; auto& line = this->line(position.row()); - if (position.column() >= line.length()) + if (static_cast<size_t>(position.column()) >= line.length()) return {}; - return line.attributes()[position.column()]; + return line.attribute_at(position.column()); } } diff --git a/Userland/Libraries/LibVT/TerminalWidget.cpp b/Userland/Libraries/LibVT/TerminalWidget.cpp index ba17011f98..1509511e5e 100644 --- a/Userland/Libraries/LibVT/TerminalWidget.cpp +++ b/Userland/Libraries/LibVT/TerminalWidget.cpp @@ -313,7 +313,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) for (u16 visual_row = 0; visual_row < m_terminal.rows(); ++visual_row) { auto& line = m_terminal.line(first_row_from_history + visual_row); for (size_t column = 0; column < line.length(); ++column) { - if (m_hovered_href_id == line.attributes()[column].href_id) { + if (m_hovered_href_id == line.attribute_at(column).href_id) { bool merged_with_existing_rect = false; auto glyph_rect = this->glyph_rect(visual_row, column); for (auto& rect : hovered_href_rects) { @@ -340,7 +340,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) if (visual_beep_active) painter.clear_rect(row_rect, Color::Red); else if (has_only_one_background_color) - painter.clear_rect(row_rect, color_from_rgb(line.attributes()[0].effective_background_color()).with_alpha(m_opacity)); + painter.clear_rect(row_rect, color_from_rgb(line.attribute_at(0).effective_background_color()).with_alpha(m_opacity)); for (size_t column = 0; column < line.length(); ++column) { bool should_reverse_fill_for_cursor_or_selection = m_cursor_blink_state @@ -348,7 +348,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) && visual_row == row_with_cursor && column == m_terminal.cursor_column(); should_reverse_fill_for_cursor_or_selection |= selection_contains({ first_row_from_history + visual_row, (int)column }); - auto attribute = line.attributes()[column]; + auto attribute = line.attribute_at(column); auto character_rect = glyph_rect(visual_row, column); auto cell_rect = character_rect.inflated(0, m_line_spacing); auto text_color = color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.effective_background_color() : attribute.effective_foreground_color()); @@ -405,7 +405,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) continue; auto& line = m_terminal.line(first_row_from_history + visual_row); for (size_t column = 0; column < line.length(); ++column) { - auto attribute = line.attributes()[column]; + auto attribute = line.attribute_at(column); bool should_reverse_fill_for_cursor_or_selection = m_cursor_blink_state && m_has_logical_focus && visual_row == row_with_cursor @@ -436,7 +436,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event) auto& cursor_line = m_terminal.line(first_row_from_history + row_with_cursor); if (m_terminal.cursor_row() < (m_terminal.rows() - rows_from_history)) { auto cell_rect = glyph_rect(row_with_cursor, m_terminal.cursor_column()).inflated(0, m_line_spacing); - painter.draw_rect(cell_rect, color_from_rgb(cursor_line.attributes()[m_terminal.cursor_column()].effective_foreground_color())); + painter.draw_rect(cell_rect, color_from_rgb(cursor_line.attribute_at(m_terminal.cursor_column()).effective_foreground_color())); } } } @@ -590,18 +590,20 @@ VT::Position TerminalWidget::buffer_position_at(const Gfx::IntPoint& position) c u32 TerminalWidget::code_point_at(const VT::Position& position) const { + VERIFY(position.is_valid()); VERIFY(position.row() >= 0 && static_cast<size_t>(position.row()) < m_terminal.line_count()); auto& line = m_terminal.line(position.row()); - if (position.column() == line.length()) + if (static_cast<size_t>(position.column()) == line.length()) return '\n'; return line.code_point(position.column()); } VT::Position TerminalWidget::next_position_after(const VT::Position& position, bool should_wrap) const { + VERIFY(position.is_valid()); VERIFY(position.row() >= 0 && static_cast<size_t>(position.row()) < m_terminal.line_count()); auto& line = m_terminal.line(position.row()); - if (position.column() == line.length()) { + if (static_cast<size_t>(position.column()) == line.length()) { if (static_cast<size_t>(position.row()) == m_terminal.line_count() - 1) { if (should_wrap) return { 0, 0 }; @@ -619,12 +621,12 @@ VT::Position TerminalWidget::previous_position_before(const VT::Position& positi if (position.row() == 0) { if (should_wrap) { auto& last_line = m_terminal.line(m_terminal.line_count() - 1); - return { static_cast<int>(m_terminal.line_count() - 1), last_line.length() }; + return { static_cast<int>(m_terminal.line_count() - 1), static_cast<int>(last_line.length()) }; } return {}; } auto& prev_line = m_terminal.line(position.row() - 1); - return { position.row() - 1, prev_line.length() }; + return { position.row() - 1, static_cast<int>(prev_line.length()) }; } return { position.row(), position.column() - 1 }; } @@ -909,18 +911,14 @@ String TerminalWidget::selected_text() const int last_column = last_selection_column_on_row(row); for (int column = first_column; column <= last_column; ++column) { auto& line = m_terminal.line(row); - if (line.attributes()[column].is_untouched()) { + if (line.attribute_at(column).is_untouched()) { builder.append('\n'); break; } // FIXME: This is a bit hackish. - if (line.is_utf32()) { - u32 code_point = line.code_point(column); - builder.append(Utf32View(&code_point, 1)); - } else { - builder.append(line.code_point(column)); - } - if (column == line.length() - 1 || (m_rectangle_selection && column == last_column)) { + u32 code_point = line.code_point(column); + builder.append(Utf32View(&code_point, 1)); + if (column == static_cast<int>(line.length()) - 1 || (m_rectangle_selection && column == last_column)) { builder.append('\n'); } } |