Sfoglia il codice sorgente

Kernel+LibVT: Fix selection with scrollback wrap-around

If lines are removed from the tail of the scrollback buffer, the
previous line indices will refer to different lines; therefore we need
to offset them.
Daniel Bertalan 4 anni fa
parent
commit
ce9460de59

+ 1 - 1
Kernel/TTY/VirtualConsole.cpp

@@ -353,7 +353,7 @@ void VirtualConsole::terminal_did_resize(u16 columns, u16 rows)
     dbgln("VC {}: Resized to {} x {}", index(), columns, rows);
 }
 
-void VirtualConsole::terminal_history_changed()
+void VirtualConsole::terminal_history_changed(int)
 {
     // Do nothing, I guess?
 }

+ 1 - 1
Kernel/TTY/VirtualConsole.h

@@ -100,7 +100,7 @@ private:
     virtual void set_window_title(const StringView&) override;
     virtual void set_window_progress(int, int) override;
     virtual void terminal_did_resize(u16 columns, u16 rows) override;
-    virtual void terminal_history_changed() override;
+    virtual void terminal_history_changed(int) override;
     virtual void emit(const u8*, size_t) override;
     virtual void set_cursor_style(VT::CursorStyle) override;
 

+ 6 - 0
Userland/Libraries/LibVT/Range.h

@@ -42,6 +42,12 @@ public:
         m_end = end;
     }
 
+    void offset_row(int delta)
+    {
+        m_start = Position(m_start.row() + delta, m_start.column());
+        m_end = Position(m_end.row() + delta, m_end.column());
+    }
+
     bool operator==(const Range& other) const
     {
         return m_start == other.m_start && m_end == other.m_end;

+ 6 - 3
Userland/Libraries/LibVT/Terminal.cpp

@@ -39,9 +39,10 @@ void Terminal::clear()
 void Terminal::clear_history()
 {
     dbgln_if(TERMINAL_DEBUG, "Clear history");
+    auto previous_history_size = m_history.size();
     m_history.clear();
     m_history_start = 0;
-    m_client.terminal_history_changed();
+    m_client.terminal_history_changed(-previous_history_size);
 }
 #endif
 
@@ -744,8 +745,11 @@ void Terminal::scroll_up(u16 region_top, u16 region_bottom, size_t count)
     // NOTE: We have to invalidate the cursor first.
     invalidate_cursor();
 
+    int history_delta = -count;
     bool should_move_to_scrollback = !m_use_alternate_screen_buffer && max_history_size() != 0;
     if (should_move_to_scrollback) {
+        auto remaining_lines = max_history_size() - history_size();
+        history_delta = (count > remaining_lines) ? remaining_lines - count : 0;
         for (size_t i = 0; i < count; ++i)
             add_line_to_history(move(active_buffer().ptr_at(region_top + i)));
     }
@@ -767,8 +771,7 @@ void Terminal::scroll_up(u16 region_top, u16 region_bottom, size_t count)
     // The other lines have implicitly been set dirty by being cleared.
     for (u16 row = region_top; row <= region_bottom - count; ++row)
         active_buffer()[row].set_dirty(true);
-    if (!m_use_alternate_screen_buffer && max_history_size() != 0)
-        m_client.terminal_history_changed();
+    m_client.terminal_history_changed(history_delta);
 }
 
 // Insert `count` blank lines at the top of the region. Text moves down. Does not affect the scrollback buffer.

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

@@ -45,7 +45,7 @@ public:
     virtual void set_window_title(const StringView&) = 0;
     virtual void set_window_progress(int value, int max) = 0;
     virtual void terminal_did_resize(u16 columns, u16 rows) = 0;
-    virtual void terminal_history_changed() = 0;
+    virtual void terminal_history_changed(int delta) = 0;
     virtual void emit(const u8*, size_t) = 0;
     virtual void set_cursor_style(CursorStyle) = 0;
 };
@@ -141,10 +141,11 @@ public:
     void set_max_history_size(size_t value)
     {
         if (value == 0) {
+            auto previous_size = m_history.size();
             m_max_history_lines = 0;
             m_history_start = 0;
             m_history.clear();
-            m_client.terminal_history_changed();
+            m_client.terminal_history_changed(-previous_size);
             return;
         }
 
@@ -158,7 +159,7 @@ public:
             }
             m_history = move(new_history);
             m_history_start = 0;
-            m_client.terminal_history_changed();
+            m_client.terminal_history_changed(value - existing_line_count);
         }
         m_max_history_lines = value;
     }

+ 4 - 1
Userland/Libraries/LibVT/TerminalWidget.cpp

@@ -947,13 +947,16 @@ int TerminalWidget::last_selection_column_on_row(int row) const
     return row == normalized_selection_end.row() || m_rectangle_selection ? normalized_selection_end.column() : m_terminal.columns() - 1;
 }
 
-void TerminalWidget::terminal_history_changed()
+void TerminalWidget::terminal_history_changed(int delta)
 {
     bool was_max = m_scrollbar->value() == m_scrollbar->max();
     m_scrollbar->set_max(m_terminal.history_size());
     if (was_max)
         m_scrollbar->set_value(m_scrollbar->max());
     m_scrollbar->update();
+    // If the history buffer wrapped around, the selection needs to be offset accordingly.
+    if (m_selection.is_valid() && delta < 0)
+        m_selection.offset_row(delta);
 }
 
 void TerminalWidget::terminal_did_resize(u16 columns, u16 rows)

+ 1 - 1
Userland/Libraries/LibVT/TerminalWidget.h

@@ -119,7 +119,7 @@ private:
     virtual void set_window_title(const StringView&) override;
     virtual void set_window_progress(int value, int max) override;
     virtual void terminal_did_resize(u16 columns, u16 rows) override;
-    virtual void terminal_history_changed() override;
+    virtual void terminal_history_changed(int delta) override;
     virtual void emit(const u8*, size_t) override;
     virtual void set_cursor_style(CursorStyle) override;