mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 14:57:35 +00:00
LibVT+Everywhere: Introduce 'automarks' and 'clear previous command'
Automarks are similar to bookmarks placed by the terminal, allowing the user to selectively remove a single command and its output from the terminal scrollback. This commit implements a single way to add marks: automatically placing them when the shell becomes interactive. To make sure the shell behaves correctly after its expected prompt position changes, the terminal layer forces a resize event to be passed to the shell on such (possibly) partial clears; this also has the nice side effect of fixing the disappearing prompt on the preexisting "clear including history" action: Fixes #4192.
This commit is contained in:
parent
cde528fdd9
commit
54ab6fe5b9
12 changed files with 238 additions and 0 deletions
|
@ -35,6 +35,7 @@ void Terminal::clear()
|
|||
for (size_t i = 0; i < rows(); ++i)
|
||||
active_buffer()[i]->clear();
|
||||
set_cursor(0, 0);
|
||||
m_client.terminal_did_perform_possibly_partial_clear();
|
||||
}
|
||||
|
||||
void Terminal::clear_history()
|
||||
|
@ -45,6 +46,68 @@ void Terminal::clear_history()
|
|||
m_history_start = 0;
|
||||
m_client.terminal_history_changed(-previous_history_size);
|
||||
}
|
||||
|
||||
void Terminal::clear_to_mark(Mark mark)
|
||||
{
|
||||
auto cursor_row = this->cursor_row();
|
||||
ScopeGuard send_sigwinch = [&] {
|
||||
set_cursor(cursor_row, 1);
|
||||
mark_cursor();
|
||||
m_client.terminal_did_perform_possibly_partial_clear();
|
||||
};
|
||||
m_valid_marks.remove(mark);
|
||||
|
||||
{
|
||||
auto it = active_buffer().rbegin();
|
||||
size_t row = m_rows - 1;
|
||||
// Skip to the cursor line.
|
||||
for (size_t i = this->cursor_row() + 1; i < active_buffer().size(); ++i, row--)
|
||||
++it;
|
||||
for (; it != active_buffer().rend(); ++it, row--) {
|
||||
auto& line = *it;
|
||||
auto line_mark = line->mark();
|
||||
auto is_target_line = line_mark == mark;
|
||||
if (line_mark.has_value())
|
||||
m_valid_marks.remove(*line_mark);
|
||||
line->clear();
|
||||
if (is_target_line) {
|
||||
cursor_row = row;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the mark is not found, go through the history.
|
||||
auto it = AK::find_if(
|
||||
m_history.rbegin(),
|
||||
m_history.rend(),
|
||||
[mark](auto& line) {
|
||||
return line->mark() == mark;
|
||||
});
|
||||
auto index = it == m_history.rend() ? 0 : m_history.size() - it.index();
|
||||
m_client.terminal_history_changed(m_history.size() - index);
|
||||
auto count = m_history.size() - index;
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (auto mark = m_history[index + i]->mark(); mark.has_value())
|
||||
m_valid_marks.remove(*mark);
|
||||
}
|
||||
m_history.remove(index, count);
|
||||
cursor_row = 0;
|
||||
}
|
||||
|
||||
void Terminal::mark_cursor()
|
||||
{
|
||||
static u32 next_mark_id { 0 };
|
||||
|
||||
auto& line = active_buffer()[cursor_row()];
|
||||
if (line->mark().has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto mark = Mark(next_mark_id++);
|
||||
line->set_marked(mark);
|
||||
m_valid_marks.set(mark);
|
||||
}
|
||||
#endif
|
||||
|
||||
void Terminal::alter_ansi_mode(bool should_set, Parameters params)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue