Quellcode durchsuchen

LibVT: Only resize the line after all rewrapping is done

Otherwise we would end up inserting empty cells into the wrapped lines.
Fixes #8227.
Ali Mohammad Pur vor 4 Jahren
Ursprung
Commit
7c88caf99f

+ 24 - 13
Userland/Libraries/LibVT/Line.cpp

@@ -10,43 +10,52 @@ namespace VT {
 
 Line::Line(size_t length)
 {
-    set_length(length, nullptr, nullptr);
+    set_length(length);
 }
 
 Line::~Line()
 {
 }
 
-void Line::set_length(size_t new_length, Line* next_line, CursorPosition* cursor, bool cursor_is_on_next_line)
+void Line::rewrap(size_t new_length, Line* next_line, CursorPosition* cursor, bool cursor_is_on_next_line)
 {
     size_t old_length = length();
     if (old_length == new_length)
         return;
 
     // Drop the empty cells
-    if (m_terminated_at.has_value())
+    if (m_terminated_at.has_value() && m_cells.size() > m_terminated_at.value())
         m_cells.remove(m_terminated_at.value(), m_cells.size() - m_terminated_at.value());
 
     if (!next_line)
         return m_cells.resize(new_length);
 
     if (old_length < new_length)
-        take_cells_from_next_line(old_length, new_length, next_line, cursor_is_on_next_line, cursor);
+        take_cells_from_next_line(new_length, next_line, cursor_is_on_next_line, cursor);
     else
-        push_cells_into_next_line(old_length, new_length, next_line, cursor_is_on_next_line, cursor);
+        push_cells_into_next_line(new_length, next_line, cursor_is_on_next_line, cursor);
+}
 
-    m_cells.resize(max(new_length, static_cast<size_t>(m_terminated_at.value_or(new_length))));
+void Line::set_length(size_t new_length)
+{
+    m_cells.resize(new_length);
 }
 
-void Line::push_cells_into_next_line(size_t old_length, size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor)
+void Line::push_cells_into_next_line(size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor)
 {
+    if (is_empty())
+        return;
+
+    if (length() <= new_length)
+        return;
+
     // Push as many cells as _wouldn't_ fit into the next line.
     auto cells_to_preserve = !next_line->m_terminated_at.has_value() && next_line->is_empty() ? 0 : m_terminated_at.value_or(0);
-    auto cells_to_push_into_next_line = min(old_length - new_length, length() - cells_to_preserve);
+    auto preserved_cells = max(new_length, cells_to_preserve);
+    auto cells_to_push_into_next_line = length() - preserved_cells;
     if (!cells_to_push_into_next_line)
         return;
 
-    auto preserved_cells = length() - cells_to_push_into_next_line;
     if (next_line->m_terminated_at.has_value())
         next_line->m_terminated_at = next_line->m_terminated_at.value() + cells_to_push_into_next_line;
 
@@ -71,18 +80,20 @@ void Line::push_cells_into_next_line(size_t old_length, size_t new_length, Line*
         m_terminated_at = m_terminated_at.value() - cells_to_push_into_next_line;
 }
 
-void Line::take_cells_from_next_line(size_t old_length, size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor)
+void Line::take_cells_from_next_line(size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor)
 {
     // Take as many cells as would fit from the next line
     if (m_terminated_at.has_value())
         return;
 
-    auto cells_to_grab_from_next_line = min(new_length - old_length, next_line->length());
+    if (length() >= new_length)
+        return;
+
+    auto cells_to_grab_from_next_line = min(new_length - length(), next_line->length());
     auto clear_next_line = false;
     if (next_line->m_terminated_at.has_value()) {
-        cells_to_grab_from_next_line = min(cells_to_grab_from_next_line, static_cast<size_t>(next_line->m_terminated_at.value()));
         if (cells_to_grab_from_next_line == *next_line->m_terminated_at) {
-            m_terminated_at = old_length + *next_line->m_terminated_at;
+            m_terminated_at = length() + *next_line->m_terminated_at;
             next_line->m_terminated_at.clear();
             clear_next_line = true;
         } else {

+ 4 - 3
Userland/Libraries/LibVT/Line.h

@@ -53,7 +53,8 @@ public:
     {
         return m_cells.size();
     }
-    void set_length(size_t, Line* next_line, CursorPosition* cursor, bool cursor_is_on_next_line = true);
+    void set_length(size_t);
+    void rewrap(size_t new_length, Line* next_line, CursorPosition* cursor, bool cursor_is_on_next_line = true);
 
     u32 code_point(size_t index) const
     {
@@ -78,8 +79,8 @@ public:
     void set_terminated(u16 column) { m_terminated_at = column; }
 
 private:
-    void take_cells_from_next_line(size_t old_length, size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor);
-    void push_cells_into_next_line(size_t old_length, size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor);
+    void take_cells_from_next_line(size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor);
+    void push_cells_into_next_line(size_t new_length, Line* next_line, bool cursor_is_on_next_line, CursorPosition* cursor);
 
     Vector<Cell> m_cells;
     bool m_dirty { false };

+ 7 - 4
Userland/Libraries/LibVT/Terminal.cpp

@@ -1455,14 +1455,14 @@ void Terminal::set_size(u16 columns, u16 rows)
                     auto next_line = is_at_seam ? nullptr : &buffer[buffer.size() - i + 1];
                     auto& line = buffer[buffer.size() - i];
                     auto next_cursor = cursor_on_line(buffer.size() - i + 1);
-                    line.set_length(columns, next_line, next_cursor ?: cursor_on_line(buffer.size() - i), !!next_cursor);
+                    line.rewrap(columns, next_line, next_cursor ?: cursor_on_line(buffer.size() - i), !!next_cursor);
                 }
             } else {
                 for (size_t i = 0; i < buffer.size(); ++i) {
                     auto is_at_seam = i + 1 == buffer.size();
                     auto next_line = is_at_seam ? nullptr : &buffer[i + 1];
                     auto next_cursor = cursor_on_line(i + 1);
-                    buffer[i].set_length(columns, next_line, next_cursor ?: cursor_on_line(i), !!next_cursor);
+                    buffer[i].rewrap(columns, next_line, next_cursor ?: cursor_on_line(i), !!next_cursor);
                 }
             }
 
@@ -1478,7 +1478,7 @@ void Terminal::set_size(u16 columns, u16 rows)
                 auto next_line = is_at_seam ? nullptr : &buffer[index + 1];
                 auto& line = buffer[index];
                 auto next_cursor = cursor_on_line(index + 1);
-                line.set_length(columns, next_line, next_cursor ?: cursor_on_line(index), !!next_cursor);
+                line.rewrap(columns, next_line, next_cursor ?: cursor_on_line(index), !!next_cursor);
                 if (line.length() > columns) {
                     auto current_cursor = cursor_on_line(index);
                     // Split the line into two (or more)
@@ -1486,7 +1486,7 @@ void Terminal::set_size(u16 columns, u16 rows)
                     ++rows_inserted;
                     buffer.insert(index, make<Line>(0));
                     VERIFY(buffer[index].length() == 0);
-                    line.set_length(columns, &buffer[index], current_cursor, false);
+                    line.rewrap(columns, &buffer[index], current_cursor, false);
                     // If we inserted a line and the old cursor was after that line, increment its row
                     if (!current_cursor && old_cursor.row >= index)
                         ++old_cursor.row;
@@ -1499,6 +1499,9 @@ void Terminal::set_size(u16 columns, u16 rows)
             }
         }
 
+        for (auto& line : buffer)
+            line.set_length(columns);
+
         return old_cursor;
     };