Ver Fonte

LibVT: Move out the Line class from Terminal to its own class

Andreas Kling há 5 anos atrás
pai
commit
16965db86b

+ 1 - 0
Libraries/LibVT/CMakeLists.txt

@@ -1,4 +1,5 @@
 set(SOURCES
+    Line.cpp
     Terminal.cpp
     TerminalWidget.cpp
 )

+ 95 - 0
Libraries/LibVT/Line.cpp

@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibVT/Line.h>
+#include <string.h>
+
+namespace VT {
+
+Line::Line(u16 length)
+{
+    set_length(length);
+}
+
+Line::~Line()
+{
+    delete[] m_characters;
+    delete[] m_attributes;
+}
+
+void Line::set_length(u16 new_length)
+{
+    if (m_length == new_length)
+        return;
+    auto* new_characters = new u8[new_length];
+    auto* new_attributes = new Attribute[new_length];
+    memset(new_characters, ' ', new_length);
+    if (m_characters && m_attributes) {
+        memcpy(new_characters, m_characters, min(m_length, new_length));
+        for (size_t i = 0; i < min(m_length, new_length); ++i)
+            new_attributes[i] = m_attributes[i];
+    }
+    delete[] m_characters;
+    delete[] m_attributes;
+    m_characters = new_characters;
+    m_attributes = new_attributes;
+    m_length = new_length;
+}
+
+void Line::clear(Attribute attribute)
+{
+    if (m_dirty) {
+        memset(m_characters, ' ', m_length);
+        for (u16 i = 0; i < m_length; ++i)
+            m_attributes[i] = attribute;
+        return;
+    }
+    for (unsigned i = 0; i < m_length; ++i) {
+        if (m_characters[i] != ' ')
+            m_dirty = true;
+        m_characters[i] = ' ';
+    }
+    for (unsigned i = 0; i < m_length; ++i) {
+        if (m_attributes[i] != attribute)
+            m_dirty = true;
+        m_attributes[i] = attribute;
+    }
+}
+
+bool Line::has_only_one_background_color() const
+{
+    if (!m_length)
+        return true;
+    // FIXME: Cache this result?
+    auto color = m_attributes[0].background_color;
+    for (size_t i = 1; i < m_length; ++i) {
+        if (m_attributes[i].background_color != color)
+            return false;
+    }
+    return true;
+}
+
+}

+ 111 - 0
Libraries/LibVT/Line.h

@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <AK/Noncopyable.h>
+#include <AK/String.h>
+#include <LibVT/XtermColors.h>
+
+namespace VT {
+
+struct Attribute {
+    Attribute() { reset(); }
+
+    static const u32 default_foreground_color = xterm_colors[7];
+    static const u32 default_background_color = xterm_colors[0];
+
+    void reset()
+    {
+        foreground_color = default_foreground_color;
+        background_color = default_background_color;
+        flags = Flags::NoAttributes;
+    }
+    u32 foreground_color;
+    u32 background_color;
+
+    String href;
+    String href_id;
+
+    enum Flags : u8 {
+        NoAttributes = 0x00,
+        Bold = 0x01,
+        Italic = 0x02,
+        Underline = 0x04,
+        Negative = 0x08,
+        Blink = 0x10,
+        Touched = 0x20,
+    };
+
+    bool is_untouched() const { return !(flags & Touched); }
+
+    // TODO: it would be really nice if we had a helper for enums that
+    // exposed bit ops for class enums...
+    u8 flags = Flags::NoAttributes;
+
+    bool operator==(const Attribute& other) const
+    {
+        return foreground_color == other.foreground_color && background_color == other.background_color && flags == other.flags;
+    }
+    bool operator!=(const Attribute& other) const
+    {
+        return !(*this == other);
+    }
+};
+
+class Line {
+    AK_MAKE_NONCOPYABLE(Line);
+    AK_MAKE_NONMOVABLE(Line);
+
+public:
+    explicit Line(u16 columns);
+    ~Line();
+
+    void clear(Attribute);
+    bool has_only_one_background_color() const;
+    void set_length(u16);
+
+    StringView text() const { return { m_characters, m_length }; }
+
+    u16 length() const { return m_length; }
+
+    const u8* characters() const { return m_characters; }
+    u8* characters() { return m_characters; }
+
+    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; }
+
+private:
+    u8* m_characters { nullptr };
+    Attribute* m_attributes { nullptr };
+    bool m_dirty { false };
+    u16 m_length { 0 };
+};
+
+}

+ 12 - 74
Libraries/LibVT/Terminal.cpp

@@ -41,68 +41,6 @@ Terminal::~Terminal()
 {
 }
 
-Terminal::Line::Line(u16 length)
-{
-    set_length(length);
-}
-
-Terminal::Line::~Line()
-{
-    delete[] characters;
-    delete[] attributes;
-}
-
-void Terminal::Line::set_length(u16 new_length)
-{
-    if (m_length == new_length)
-        return;
-    auto* new_characters = new u8[new_length];
-    auto* new_attributes = new Attribute[new_length];
-    memset(new_characters, ' ', new_length);
-    if (characters && attributes) {
-        memcpy(new_characters, characters, min(m_length, new_length));
-        for (size_t i = 0; i < min(m_length, new_length); ++i)
-            new_attributes[i] = attributes[i];
-    }
-    delete[] characters;
-    delete[] attributes;
-    characters = new_characters;
-    attributes = new_attributes;
-    m_length = new_length;
-}
-
-void Terminal::Line::clear(Attribute attribute)
-{
-    if (dirty) {
-        memset(characters, ' ', m_length);
-        for (u16 i = 0; i < m_length; ++i)
-            attributes[i] = attribute;
-        return;
-    }
-    for (unsigned i = 0; i < m_length; ++i) {
-        if (characters[i] != ' ')
-            dirty = true;
-        characters[i] = ' ';
-    }
-    for (unsigned i = 0; i < m_length; ++i) {
-        if (attributes[i] != attribute)
-            dirty = true;
-        attributes[i] = attribute;
-    }
-}
-
-bool Terminal::Line::has_only_one_background_color() const
-{
-    if (!m_length)
-        return true;
-    // FIXME: Cache this result?
-    auto color = attributes[0].background_color;
-    for (size_t i = 1; i < m_length; ++i) {
-        if (attributes[i].background_color != color)
-            return false;
-    }
-    return true;
-}
 
 void Terminal::clear()
 {
@@ -590,14 +528,14 @@ void Terminal::escape$P(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.m_length - num; i++)
-        line.characters[i] = line.characters[i + num];
+    for (int i = m_cursor_column; i < line.length() - num; i++)
+        line.characters()[i] = line.characters()[i + num];
 
     // Fill remainder of line with blanks
-    for (int i = line.m_length - num; i < line.m_length; i++)
-        line.characters[i] = ' ';
+    for (int i = line.length() - num; i < line.length(); i++)
+        line.characters()[i] = ' ';
 
-    line.dirty = true;
+    line.set_dirty(true);
 }
 
 void Terminal::execute_xterm_command()
@@ -828,10 +766,10 @@ void Terminal::put_character_at(unsigned row, unsigned column, u8 ch)
     ASSERT(row < rows());
     ASSERT(column < columns());
     auto& line = m_lines[row];
-    line.characters[column] = ch;
-    line.attributes[column] = m_current_attribute;
-    line.attributes[column].flags |= Attribute::Touched;
-    line.dirty = true;
+    line.characters()[column] = ch;
+    line.attributes()[column] = m_current_attribute;
+    line.attributes()[column].flags |= Attribute::Touched;
+    line.set_dirty(true);
 
     m_last_char = ch;
 }
@@ -1087,7 +1025,7 @@ void Terminal::set_size(u16 columns, u16 rows)
 
 void Terminal::invalidate_cursor()
 {
-    m_lines[m_cursor_row].dirty = true;
+    m_lines[m_cursor_row].set_dirty(true);
 }
 
 void Terminal::execute_hashtag(u8 hashtag)
@@ -1113,9 +1051,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.m_length)
+    if (position.column() >= line.length())
         return {};
-    return line.attributes[position.column()];
+    return line.attributes()[position.column()];
 }
 
 }

+ 2 - 64
Libraries/LibVT/Terminal.h

@@ -30,14 +30,14 @@
 #include <AK/NonnullOwnPtrVector.h>
 #include <AK/String.h>
 #include <AK/Vector.h>
+#include <LibVT/Line.h>
 #include <LibVT/Position.h>
-#include <LibVT/XtermColors.h>
 
 namespace VT {
 
 class TerminalClient {
 public:
-    virtual ~TerminalClient() {}
+    virtual ~TerminalClient() { }
 
     virtual void beep() = 0;
     virtual void set_window_title(const StringView&) = 0;
@@ -46,50 +46,6 @@ public:
     virtual void emit(const u8*, size_t) = 0;
 };
 
-struct Attribute {
-    Attribute() { reset(); }
-
-    static const u32 default_foreground_color = xterm_colors[7];
-    static const u32 default_background_color = xterm_colors[0];
-
-    void reset()
-    {
-        foreground_color = default_foreground_color;
-        background_color = default_background_color;
-        flags = Flags::NoAttributes;
-    }
-    u32 foreground_color;
-    u32 background_color;
-
-    String href;
-    String href_id;
-
-    enum Flags : u8 {
-        NoAttributes = 0x00,
-        Bold = 0x01,
-        Italic = 0x02,
-        Underline = 0x04,
-        Negative = 0x08,
-        Blink = 0x10,
-        Touched = 0x20,
-    };
-
-    bool is_untouched() const { return !(flags & Touched); }
-
-    // TODO: it would be really nice if we had a helper for enums that
-    // exposed bit ops for class enums...
-    u8 flags = Flags::NoAttributes;
-
-    bool operator==(const Attribute& other) const
-    {
-        return foreground_color == other.foreground_color && background_color == other.background_color && flags == other.flags;
-    }
-    bool operator!=(const Attribute& other) const
-    {
-        return !(*this == other);
-    }
-};
-
 class Terminal {
 public:
     explicit Terminal(TerminalClient&);
@@ -108,24 +64,6 @@ public:
     u16 cursor_column() const { return m_cursor_column; }
     u16 cursor_row() const { return m_cursor_row; }
 
-    struct Line {
-        AK_MAKE_NONCOPYABLE(Line);
-        AK_MAKE_NONMOVABLE(Line);
-
-    public:
-        explicit Line(u16 columns);
-        ~Line();
-        void clear(Attribute);
-        bool has_only_one_background_color() const;
-        void set_length(u16);
-        StringView text() const { return { characters, m_length }; }
-
-        u8* characters { nullptr };
-        Attribute* attributes { nullptr };
-        bool dirty { false };
-        u16 m_length { 0 };
-    };
-
     size_t line_count() const
     {
         return m_history.size() + m_lines.size();

+ 11 - 11
Libraries/LibVT/TerminalWidget.cpp

@@ -336,7 +336,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
         if (m_visual_beep_timer->is_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].background_color).with_alpha(m_opacity));
+            painter.clear_rect(row_rect, color_from_rgb(line.attributes()[0].background_color).with_alpha(m_opacity));
 
         // The terminal insists on thinking characters and
         // bytes are the same thing. We want to still draw
@@ -369,7 +369,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, column });
-                attribute = line.attributes[column];
+                attribute = line.attributes()[column];
                 text_color = color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.background_color : attribute.foreground_color);
                 auto character_rect = glyph_rect(visual_row, column);
                 auto cell_rect = character_rect.inflated(0, m_line_spacing);
@@ -430,7 +430,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()].foreground_color));
+            painter.draw_rect(cell_rect, color_from_rgb(cursor_line.attributes()[m_terminal.cursor_column()].foreground_color));
         }
     }
 }
@@ -456,9 +456,9 @@ void TerminalWidget::flush_dirty_lines()
     }
     Gfx::Rect rect;
     for (int i = 0; i < m_terminal.rows(); ++i) {
-        if (m_terminal.visible_line(i).dirty) {
+        if (m_terminal.visible_line(i).is_dirty()) {
             rect = rect.united(row_rect(i));
-            m_terminal.visible_line(i).dirty = false;
+            m_terminal.visible_line(i).set_dirty(false);
         }
     }
     update(rect);
@@ -583,16 +583,16 @@ void TerminalWidget::doubleclick_event(GUI::MouseEvent& event)
 
         auto position = buffer_position_at(event.position());
         auto& line = m_terminal.line(position.row());
-        bool want_whitespace = line.characters[position.column()] == ' ';
+        bool want_whitespace = line.characters()[position.column()] == ' ';
 
         int start_column = 0;
         int end_column = 0;
 
-        for (int column = position.column(); column >= 0 && (line.characters[column] == ' ') == want_whitespace; --column) {
+        for (int column = position.column(); column >= 0 && (line.characters()[column] == ' ') == want_whitespace; --column) {
             start_column = column;
         }
 
-        for (int column = position.column(); column < m_terminal.columns() && (line.characters[column] == ' ') == want_whitespace; ++column) {
+        for (int column = position.column(); column < m_terminal.columns() && (line.characters()[column] == ' ') == want_whitespace; ++column) {
             end_column = column;
         }
 
@@ -758,12 +758,12 @@ 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.attributes()[column].is_untouched()) {
                 builder.append('\n');
                 break;
             }
-            builder.append(line.characters[column]);
-            if (column == line.m_length - 1 || (m_rectangle_selection && column == last_column)) {
+            builder.append(line.characters()[column]);
+            if (column == line.length() - 1 || (m_rectangle_selection && column == last_column)) {
                 builder.append('\n');
             }
         }