diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index bd0383ebe9..781fce17a0 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -545,9 +545,16 @@ auto Editor::get_line(const String& prompt) -> Result 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; +} + } diff --git a/Libraries/LibLine/Editor.h b/Libraries/LibLine/Editor.h index b6f2ba510e..3106debc83 100644 --- a/Libraries/LibLine/Editor.h +++ b/Libraries/LibLine/Editor.h @@ -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() diff --git a/Libraries/LibLine/StringMetrics.h b/Libraries/LibLine/StringMetrics.h index 9fdd8ee719..5976d25555 100644 --- a/Libraries/LibLine/StringMetrics.h +++ b/Libraries/LibLine/StringMetrics.h @@ -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();