mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 12:37:43 +00:00
LibVT: Make selection follow terminal history scrollback :^)
The buffer positions referred to by a VT::Position now include history scrollback, meaning that a VT::Position with row=0 is at the start of the history. The active terminal buffer keeps moving in VT::Position coordinates whenever we scroll. This allows selection to follow history. It also allows us to click hyperlinks in history. Fixes #957.
This commit is contained in:
parent
c50672a19d
commit
901d2e3236
3 changed files with 27 additions and 25 deletions
|
@ -107,7 +107,7 @@ bool Terminal::Line::has_only_one_background_color() const
|
||||||
void Terminal::clear()
|
void Terminal::clear()
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < rows(); ++i)
|
for (size_t i = 0; i < rows(); ++i)
|
||||||
line(i).clear(m_current_attribute);
|
m_lines[i].clear(m_current_attribute);
|
||||||
set_cursor(0, 0);
|
set_cursor(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,7 +587,7 @@ void Terminal::escape$P(const ParamVector& params)
|
||||||
if (num == 0)
|
if (num == 0)
|
||||||
num = 1;
|
num = 1;
|
||||||
|
|
||||||
auto& line = this->line(m_cursor_row);
|
auto& line = m_lines[m_cursor_row];
|
||||||
|
|
||||||
// Move n characters of line to the left
|
// Move n characters of line to the left
|
||||||
for (int i = m_cursor_column; i < line.m_length - num; i++)
|
for (int i = m_cursor_column; i < line.m_length - num; i++)
|
||||||
|
@ -827,7 +827,7 @@ void Terminal::put_character_at(unsigned row, unsigned column, u8 ch)
|
||||||
{
|
{
|
||||||
ASSERT(row < rows());
|
ASSERT(row < rows());
|
||||||
ASSERT(column < columns());
|
ASSERT(column < columns());
|
||||||
auto& line = this->line(row);
|
auto& line = m_lines[row];
|
||||||
line.characters[column] = ch;
|
line.characters[column] = ch;
|
||||||
line.attributes[column] = m_current_attribute;
|
line.attributes[column] = m_current_attribute;
|
||||||
line.attributes[column].flags |= Attribute::Touched;
|
line.attributes[column].flags |= Attribute::Touched;
|
||||||
|
@ -1087,7 +1087,7 @@ void Terminal::set_size(u16 columns, u16 rows)
|
||||||
|
|
||||||
void Terminal::invalidate_cursor()
|
void Terminal::invalidate_cursor()
|
||||||
{
|
{
|
||||||
line(m_cursor_row).dirty = true;
|
m_lines[m_cursor_row].dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::execute_hashtag(u8 hashtag)
|
void Terminal::execute_hashtag(u8 hashtag)
|
||||||
|
@ -1110,7 +1110,7 @@ Attribute Terminal::attribute_at(const Position& position) const
|
||||||
{
|
{
|
||||||
if (!position.is_valid())
|
if (!position.is_valid())
|
||||||
return {};
|
return {};
|
||||||
if (position.row() >= static_cast<int>(m_lines.size()))
|
if (position.row() >= static_cast<int>(line_count()))
|
||||||
return {};
|
return {};
|
||||||
auto& line = this->line(position.row());
|
auto& line = this->line(position.row());
|
||||||
if (position.column() >= line.m_length)
|
if (position.column() >= line.m_length)
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace VT {
|
||||||
|
|
||||||
class TerminalClient {
|
class TerminalClient {
|
||||||
public:
|
public:
|
||||||
virtual ~TerminalClient() { }
|
virtual ~TerminalClient() {}
|
||||||
|
|
||||||
virtual void beep() = 0;
|
virtual void beep() = 0;
|
||||||
virtual void set_window_title(const StringView&) = 0;
|
virtual void set_window_title(const StringView&) = 0;
|
||||||
|
@ -126,15 +126,22 @@ public:
|
||||||
u16 m_length { 0 };
|
u16 m_length { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t line_count() const
|
||||||
|
{
|
||||||
|
return m_history.size() + m_lines.size();
|
||||||
|
}
|
||||||
|
|
||||||
Line& line(size_t index)
|
Line& line(size_t index)
|
||||||
{
|
{
|
||||||
ASSERT(index < m_rows);
|
if (index < m_history.size())
|
||||||
return m_lines[index];
|
return m_history[index];
|
||||||
|
return m_lines[index - m_history.size()];
|
||||||
}
|
}
|
||||||
const Line& line(size_t index) const
|
const Line& line(size_t index) const
|
||||||
{
|
{
|
||||||
ASSERT(index < m_rows);
|
if (index < m_history.size())
|
||||||
return m_lines[index];
|
return m_history[index];
|
||||||
|
return m_lines[index - m_history.size()];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t max_history_size() const { return 500; }
|
size_t max_history_size() const { return 500; }
|
||||||
|
|
|
@ -327,7 +327,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
|
||||||
invalidate_cursor();
|
invalidate_cursor();
|
||||||
|
|
||||||
int rows_from_history = 0;
|
int rows_from_history = 0;
|
||||||
int first_row_from_history = 0;
|
int first_row_from_history = m_terminal.history().size();
|
||||||
int row_with_cursor = m_terminal.cursor_row();
|
int row_with_cursor = m_terminal.cursor_row();
|
||||||
if (m_scrollbar->value() != m_scrollbar->max()) {
|
if (m_scrollbar->value() != m_scrollbar->max()) {
|
||||||
rows_from_history = min((int)m_terminal.rows(), m_scrollbar->max() - m_scrollbar->value());
|
rows_from_history = min((int)m_terminal.rows(), m_scrollbar->max() - m_scrollbar->value());
|
||||||
|
@ -335,17 +335,11 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
|
||||||
row_with_cursor = m_terminal.cursor_row() + rows_from_history;
|
row_with_cursor = m_terminal.cursor_row() + rows_from_history;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto line_for_visual_row = [&](u16 row) -> const VT::Terminal::Line& {
|
for (u16 visual_row = 0; visual_row < m_terminal.rows(); ++visual_row) {
|
||||||
if (row < rows_from_history)
|
auto row_rect = this->row_rect(visual_row);
|
||||||
return m_terminal.history().at(first_row_from_history + row);
|
|
||||||
return m_terminal.line(row - rows_from_history);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (u16 row = 0; row < m_terminal.rows(); ++row) {
|
|
||||||
auto row_rect = this->row_rect(row);
|
|
||||||
if (!event.rect().contains(row_rect))
|
if (!event.rect().contains(row_rect))
|
||||||
continue;
|
continue;
|
||||||
auto& line = line_for_visual_row(row);
|
auto& line = m_terminal.line(first_row_from_history + visual_row);
|
||||||
bool has_only_one_background_color = line.has_only_one_background_color();
|
bool has_only_one_background_color = line.has_only_one_background_color();
|
||||||
if (m_visual_beep_timer->is_active())
|
if (m_visual_beep_timer->is_active())
|
||||||
painter.clear_rect(row_rect, Color::Red);
|
painter.clear_rect(row_rect, Color::Red);
|
||||||
|
@ -380,12 +374,12 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
|
||||||
for (u16 column = this_char_column; column < next_char_column; ++column) {
|
for (u16 column = this_char_column; column < next_char_column; ++column) {
|
||||||
should_reverse_fill_for_cursor_or_selection |= m_cursor_blink_state
|
should_reverse_fill_for_cursor_or_selection |= m_cursor_blink_state
|
||||||
&& m_has_logical_focus
|
&& m_has_logical_focus
|
||||||
&& row == row_with_cursor
|
&& visual_row == row_with_cursor
|
||||||
&& column == m_terminal.cursor_column();
|
&& column == m_terminal.cursor_column();
|
||||||
should_reverse_fill_for_cursor_or_selection |= selection_contains({ row, 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);
|
text_color = color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.background_color : attribute.foreground_color);
|
||||||
auto character_rect = glyph_rect(row, column);
|
auto character_rect = glyph_rect(visual_row, column);
|
||||||
auto cell_rect = character_rect.inflated(0, m_line_spacing);
|
auto cell_rect = character_rect.inflated(0, m_line_spacing);
|
||||||
if (!has_only_one_background_color || should_reverse_fill_for_cursor_or_selection) {
|
if (!has_only_one_background_color || should_reverse_fill_for_cursor_or_selection) {
|
||||||
painter.clear_rect(cell_rect, color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.foreground_color : attribute.background_color).with_alpha(m_opacity));
|
painter.clear_rect(cell_rect, color_from_rgb(should_reverse_fill_for_cursor_or_selection ? attribute.foreground_color : attribute.background_color).with_alpha(m_opacity));
|
||||||
|
@ -429,7 +423,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
|
||||||
if (codepoint == ' ')
|
if (codepoint == ' ')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto character_rect = glyph_rect(row, this_char_column);
|
auto character_rect = glyph_rect(visual_row, this_char_column);
|
||||||
auto num_columns = next_char_column - this_char_column;
|
auto num_columns = next_char_column - this_char_column;
|
||||||
character_rect.move_by((num_columns - 1) * font().glyph_width('x') / 2, 0);
|
character_rect.move_by((num_columns - 1) * font().glyph_width('x') / 2, 0);
|
||||||
painter.draw_glyph_or_emoji(
|
painter.draw_glyph_or_emoji(
|
||||||
|
@ -441,7 +435,7 @@ void TerminalWidget::paint_event(GUI::PaintEvent& event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_has_logical_focus && row_with_cursor < m_terminal.rows()) {
|
if (!m_has_logical_focus && row_with_cursor < m_terminal.rows()) {
|
||||||
auto& cursor_line = line_for_visual_row(row_with_cursor);
|
auto& cursor_line = m_terminal.line(first_row_from_history + row_with_cursor);
|
||||||
if (m_terminal.cursor_row() < (m_terminal.rows() - rows_from_history)) {
|
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);
|
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));
|
||||||
|
@ -586,6 +580,7 @@ VT::Position TerminalWidget::buffer_position_at(const Gfx::Point& position) cons
|
||||||
row = m_terminal.rows() - 1;
|
row = m_terminal.rows() - 1;
|
||||||
if (column >= m_terminal.columns())
|
if (column >= m_terminal.columns())
|
||||||
column = m_terminal.columns() - 1;
|
column = m_terminal.columns() - 1;
|
||||||
|
row += m_scrollbar->value();
|
||||||
return { row, column };
|
return { row, column };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue