diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-06-29 20:08:02 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-06-30 18:21:44 +0200 |
commit | f20becf71b89e1caac65a06d69c57362847c1c94 (patch) | |
tree | 4ecb16224f436b7c2da0380c903cd715d500360e /Libraries | |
parent | 0fc8931d5f5105f17eabc462e68783689d6649a1 (diff) | |
download | serenity-f20becf71b89e1caac65a06d69c57362847c1c94.zip |
LibLine: Correctly display suggestions on multiline prompts
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibLine/Editor.cpp | 27 | ||||
-rw-r--r-- | Libraries/LibLine/Editor.h | 17 | ||||
-rw-r--r-- | Libraries/LibLine/StringMetrics.h | 49 | ||||
-rw-r--r-- | Libraries/LibLine/SuggestionDisplay.h | 6 | ||||
-rw-r--r-- | Libraries/LibLine/XtermSuggestionDisplay.cpp | 14 |
5 files changed, 86 insertions, 27 deletions
diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index 892d9a6880..48226094af 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -56,7 +56,7 @@ Editor::Editor(Configuration configuration) m_num_columns = ws.ws_col; m_num_lines = ws.ws_row; } - m_suggestion_display = make<XtermSuggestionDisplay>(m_num_lines, m_num_columns); + m_suggestion_display = make<XtermSuggestionDisplay>(m_num_lines, m_num_columns, m_cached_prompt_metrics); } Editor::~Editor() @@ -304,6 +304,7 @@ auto Editor::get_line(const String& prompt) -> Result<String, Editor::Error> if (m_finish) { m_finish = false; + reposition_cursor(true); printf("\n"); fflush(stdout); auto string = line(); @@ -950,6 +951,12 @@ void Editor::recalculate_origin() } void Editor::cleanup() { + auto current_buffer_metrics = actual_rendered_string_metrics(buffer_view()); + auto new_lines = current_prompt_metrics().lines_with_addition(current_buffer_metrics, m_num_columns); + auto shown_lines = num_lines(); + 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(); @@ -1105,14 +1112,22 @@ void Editor::strip_styles(bool strip_anchored) m_refresh_needed = true; } -void Editor::reposition_cursor() +void Editor::reposition_cursor(bool to_end) { - m_drawn_cursor = m_cursor; + auto cursor = m_cursor; + auto saved_cursor = m_cursor; + if (to_end) + cursor = m_buffer.size(); + + m_cursor = cursor; + m_drawn_cursor = cursor; auto line = cursor_line() - 1; auto column = offset_in_line(); VT::move_absolute(line + m_origin_row, column + m_origin_column); + + m_cursor = saved_cursor; } void VT::move_absolute(u32 row, u32 col) @@ -1307,7 +1322,7 @@ void VT::clear_to_end_of_line() fflush(stdout); } -Editor::StringMetrics Editor::actual_rendered_string_metrics(const StringView& string) const +StringMetrics Editor::actual_rendered_string_metrics(const StringView& string) const { size_t length { 0 }; StringMetrics metrics; @@ -1331,7 +1346,7 @@ Editor::StringMetrics Editor::actual_rendered_string_metrics(const StringView& s return metrics; } -Editor::StringMetrics Editor::actual_rendered_string_metrics(const Utf32View& view) const +StringMetrics Editor::actual_rendered_string_metrics(const Utf32View& view) const { size_t length { 0 }; StringMetrics metrics; @@ -1557,7 +1572,7 @@ void Editor::readjust_anchored_styles(size_t hint_index, ModificationKind modifi } } -size_t Editor::StringMetrics::lines_with_addition(const StringMetrics& offset, size_t column_width) const +size_t StringMetrics::lines_with_addition(const StringMetrics& offset, size_t column_width) const { size_t lines = 0; diff --git a/Libraries/LibLine/Editor.h b/Libraries/LibLine/Editor.h index 50c73e1482..2f9fb4693e 100644 --- a/Libraries/LibLine/Editor.h +++ b/Libraries/LibLine/Editor.h @@ -41,6 +41,7 @@ #include <LibCore/Notifier.h> #include <LibCore/Object.h> #include <LibLine/Span.h> +#include <LibLine/StringMetrics.h> #include <LibLine/Style.h> #include <LibLine/SuggestionDisplay.h> #include <LibLine/SuggestionManager.h> @@ -104,20 +105,6 @@ public: const Vector<String>& history() const { return m_history; } void register_character_input_callback(char ch, Function<bool(Editor&)> callback); - struct StringMetrics { - Vector<size_t> line_lengths; - size_t total_length { 0 }; - size_t max_line_length { 0 }; - - size_t lines_with_addition(const StringMetrics& offset, size_t column_width) const; - void reset() - { - line_lengths.clear(); - total_length = 0; - max_line_length = 0; - line_lengths.append(0); - } - }; StringMetrics actual_rendered_string_metrics(const StringView&) const; StringMetrics actual_rendered_string_metrics(const Utf32View&) const; @@ -313,7 +300,7 @@ private: bool should_break_token(Vector<u32, 1024>& buffer, size_t index); void recalculate_origin(); - void reposition_cursor(); + void reposition_cursor(bool to_end = false); struct CodepointRange { size_t start { 0 }; diff --git a/Libraries/LibLine/StringMetrics.h b/Libraries/LibLine/StringMetrics.h new file mode 100644 index 0000000000..9fdd8ee719 --- /dev/null +++ b/Libraries/LibLine/StringMetrics.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, The SerenityOS developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <AK/Types.h> +#include <AK/Vector.h> + +namespace Line { + +struct StringMetrics { + Vector<size_t> line_lengths; + size_t total_length { 0 }; + size_t max_line_length { 0 }; + + size_t lines_with_addition(const StringMetrics& offset, size_t column_width) const; + void reset() + { + line_lengths.clear(); + total_length = 0; + max_line_length = 0; + line_lengths.append(0); + } +}; + +} diff --git a/Libraries/LibLine/SuggestionDisplay.h b/Libraries/LibLine/SuggestionDisplay.h index 346ee4bc59..80606bc5fc 100644 --- a/Libraries/LibLine/SuggestionDisplay.h +++ b/Libraries/LibLine/SuggestionDisplay.h @@ -28,6 +28,7 @@ #include <AK/Forward.h> #include <AK/String.h> +#include <LibLine/StringMetrics.h> #include <LibLine/SuggestionManager.h> #include <stdlib.h> @@ -61,9 +62,10 @@ protected: class XtermSuggestionDisplay : public SuggestionDisplay { public: - XtermSuggestionDisplay(size_t lines, size_t columns) + XtermSuggestionDisplay(size_t lines, size_t columns, const StringMetrics& prompt_metrics) : m_num_lines(lines) , m_num_columns(columns) + , m_prompt_metrics(prompt_metrics) { } virtual ~XtermSuggestionDisplay() override { } @@ -92,7 +94,7 @@ private: size_t m_num_lines { 0 }; size_t m_num_columns { 0 }; size_t m_prompt_lines_at_suggestion_initiation { 0 }; - size_t m_prompt_length { 0 }; + const StringMetrics& m_prompt_metrics; struct PageRange { size_t start; diff --git a/Libraries/LibLine/XtermSuggestionDisplay.cpp b/Libraries/LibLine/XtermSuggestionDisplay.cpp index 7cfff9999b..b908056b13 100644 --- a/Libraries/LibLine/XtermSuggestionDisplay.cpp +++ b/Libraries/LibLine/XtermSuggestionDisplay.cpp @@ -52,7 +52,11 @@ void XtermSuggestionDisplay::display(const SuggestionManager& manager) VT::restore_cursor(); auto spans_entire_line { false }; - auto max_line_count = (m_prompt_length + longest_suggestion_length + m_num_columns - 1) / m_num_columns; + Vector<size_t> lines; + for (size_t i = 0; i < m_prompt_lines_at_suggestion_initiation - 1; ++i) + lines.append(0); + lines.append(longest_suggestion_length); + auto max_line_count = StringMetrics { move(lines) }.lines_with_addition({ { 0 } }, m_num_columns); if (longest_suggestion_length >= m_num_columns - 2) { spans_entire_line = true; // We should make enough space for the biggest entry in @@ -126,9 +130,9 @@ void XtermSuggestionDisplay::display(const SuggestionManager& manager) if (spans_entire_line) { num_printed += m_num_columns; - fprintf(stderr, "%s", suggestion.text_string.characters()); + fprintf(stdout, "%s", suggestion.text_string.characters()); } else { - fprintf(stderr, "%-*s", static_cast<int>(longest_suggestion_byte_length) + 2, suggestion.text_string.characters()); + fprintf(stdout, "%-*s", static_cast<int>(longest_suggestion_byte_length) + 2, suggestion.text_string.characters()); num_printed += longest_suggestion_length + 2; } @@ -153,6 +157,7 @@ void XtermSuggestionDisplay::display(const SuggestionManager& manager) if (string.length() > m_num_columns - 1) { // This would overflow into the next line, so just don't print an indicator. + fflush(stdout); return; } @@ -160,8 +165,9 @@ void XtermSuggestionDisplay::display(const SuggestionManager& manager) VT::apply_style({ Style::Background(Style::XtermColor::Green) }); fputs(string.characters(), stdout); VT::apply_style(Style::reset_style()); - fflush(stdout); } + + fflush(stdout); } bool XtermSuggestionDisplay::cleanup() |