LibLine: Don't overwrite stuff when moving origin around

This fixes an issue (mainly) with multiline prompts, where a multiline
prompt would overwrite the lines before it when libline tries to display
it.
To reproduce, set `PROMPT="a\nb\nc> "` in the shell, then press return
a few times.
This commit is contained in:
AnotherTest 2021-01-04 11:38:56 +03:30 committed by Andreas Kling
parent 1f03b6ad57
commit 1c4a425bff
Notes: sideshowbarker 2024-07-19 00:07:27 +09:00
3 changed files with 56 additions and 18 deletions

View file

@ -545,9 +545,16 @@ auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error>
set_prompt(prompt);
reset();
set_origin();
strip_styles(true);
auto prompt_lines = max(current_prompt_metrics().line_lengths.size(), 1ul) - 1;
for (size_t i = 0; i < prompt_lines; ++i)
putc('\n', stderr);
VT::move_relative(-prompt_lines, 0);
set_origin();
m_history_cursor = m_history.size();
refresh_display();
@ -856,8 +863,18 @@ void Editor::handle_read_event()
}
reverse_tab = false;
auto completion_mode = m_times_tab_pressed == 1 ? SuggestionManager::CompletePrefix : m_times_tab_pressed == 2 ? SuggestionManager::ShowSuggestions
: SuggestionManager::CycleSuggestions;
SuggestionManager::CompletionMode completion_mode;
switch (m_times_tab_pressed) {
case 1:
completion_mode = SuggestionManager::CompletePrefix;
break;
case 2:
completion_mode = SuggestionManager::ShowSuggestions;
break;
default:
completion_mode = SuggestionManager::CycleSuggestions;
break;
}
auto completion_result = m_suggestion_manager.attempt_completion(completion_mode, token_start);
@ -1016,13 +1033,9 @@ void Editor::cleanup()
if (new_lines < shown_lines)
m_extra_forward_lines = max(shown_lines - new_lines, m_extra_forward_lines);
VT::move_relative(-m_extra_forward_lines, m_pending_chars.size() - m_chars_inserted_in_the_middle);
auto current_line = cursor_line();
// There's a newline at the top, don't clear that line.
if (current_prompt_metrics().line_lengths.first() == 0)
--current_line;
VT::clear_lines(current_line - 1, num_lines() - current_line + m_extra_forward_lines);
reposition_cursor(true);
auto current_line = num_lines() - 1;
VT::clear_lines(current_line, m_extra_forward_lines);
m_extra_forward_lines = 0;
reposition_cursor();
};
@ -1047,13 +1060,21 @@ void Editor::refresh_display()
}
// We might be at the last line, and have more than one line;
// Refreshing the display will cause the terminal to scroll,
// so note that fact and bring origin up.
// so note that fact and bring origin up, making sure to
// reserve the space for however many lines we move it up.
auto current_num_lines = num_lines();
if (m_origin_row + current_num_lines > m_num_lines + 1) {
if (current_num_lines > m_num_lines)
if (m_origin_row + current_num_lines > m_num_lines) {
if (current_num_lines > m_num_lines) {
for (size_t i = 0; i < m_num_lines; ++i)
putc('\n', stderr);
m_origin_row = 0;
else
} else {
auto old_origin_row = m_origin_row;
m_origin_row = m_num_lines - current_num_lines + 1;
for (size_t i = 0; i < old_origin_row - m_origin_row; ++i)
putc('\n', stderr);
}
fflush(stderr);
}
// Do not call hook on pure cursor movement.
if (m_cached_prompt_valid && !m_refresh_needed && m_pending_chars.size() == 0) {
@ -1172,8 +1193,16 @@ void Editor::reposition_cursor(bool to_end)
auto line = cursor_line() - 1;
auto column = offset_in_line();
ASSERT(column + m_origin_column <= m_num_columns);
VT::move_absolute(line + m_origin_row, column + m_origin_column);
if (line + m_origin_row > m_num_lines) {
for (size_t i = m_num_lines; i < line + m_origin_row; ++i)
fputc('\n', stderr);
m_origin_row -= line + m_origin_row - m_num_lines;
VT::move_relative(0, column + m_origin_column);
}
m_cursor = saved_cursor;
}
@ -1622,4 +1651,15 @@ size_t StringMetrics::lines_with_addition(const StringMetrics& offset, size_t co
return lines;
}
size_t StringMetrics::offset_with_addition(const StringMetrics& offset, size_t column_width) const
{
if (offset.line_lengths.size() > 1)
return offset.line_lengths.first() % column_width;
auto last = line_lengths.last();
last += offset.line_lengths.first();
return last % column_width;
}
}

View file

@ -349,10 +349,7 @@ private:
if (cursor > m_cursor)
cursor = m_cursor;
auto buffer_metrics = actual_rendered_string_metrics(buffer_view().substring_view(0, cursor));
if (buffer_metrics.line_lengths.size() > 1)
return buffer_metrics.line_lengths.last() % m_num_columns;
return (buffer_metrics.line_lengths.last() + current_prompt_metrics().line_lengths.last()) % m_num_columns;
return current_prompt_metrics().offset_with_addition(buffer_metrics, m_num_columns);
}
void set_origin()

View file

@ -37,6 +37,7 @@ struct StringMetrics {
size_t max_line_length { 0 };
size_t lines_with_addition(const StringMetrics& offset, size_t column_width) const;
size_t offset_with_addition(const StringMetrics& offset, size_t column_width) const;
void reset()
{
line_lengths.clear();