diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-05-22 14:02:17 +0430 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-05-23 01:31:41 +0200 |
commit | 3c3edf583116037f43e1e031f6f7ade6d7c55709 (patch) | |
tree | dece737c58588b0837185ddd73cbcb6084852604 /Libraries | |
parent | 0446b7e347f20062f8a560c51bee7cf8182a6a7c (diff) | |
download | serenity-3c3edf583116037f43e1e031f6f7ade6d7c55709.zip |
LibLine: Properly paginate suggestions in XtermSuggestionDisplay
This commit adds back suggestion pagination, and makes it 10x better.
Also adds a "< page m of n >" indicator at the bottom if there are more
suggestions than would fit in a page.
It properly handles cycling forwards and backwards :^)
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibLine/Editor.cpp | 2 | ||||
-rw-r--r-- | Libraries/LibLine/SuggestionDisplay.h | 13 | ||||
-rw-r--r-- | Libraries/LibLine/SuggestionManager.h | 7 | ||||
-rw-r--r-- | Libraries/LibLine/XtermSuggestionDisplay.cpp | 77 |
4 files changed, 95 insertions, 4 deletions
diff --git a/Libraries/LibLine/Editor.cpp b/Libraries/LibLine/Editor.cpp index db63696561..18d691eb44 100644 --- a/Libraries/LibLine/Editor.cpp +++ b/Libraries/LibLine/Editor.cpp @@ -566,6 +566,7 @@ String Editor::get_line(const String& prompt) suggest(0, 0, Span::CodepointOriented); m_times_tab_pressed = 0; m_suggestion_manager.reset(); + m_suggestion_display->finish(); } continue; } @@ -582,6 +583,7 @@ String Editor::get_line(const String& prompt) } m_suggestion_manager.reset(); suggest(0, 0, Span::CodepointOriented); + m_suggestion_display->finish(); } m_times_tab_pressed = 0; // Safe to say if we get here, the user didn't press TAB diff --git a/Libraries/LibLine/SuggestionDisplay.h b/Libraries/LibLine/SuggestionDisplay.h index 77393c0641..a6c56a6a76 100644 --- a/Libraries/LibLine/SuggestionDisplay.h +++ b/Libraries/LibLine/SuggestionDisplay.h @@ -39,6 +39,7 @@ public: virtual ~SuggestionDisplay() { } virtual void display(const SuggestionManager&) = 0; virtual bool cleanup() = 0; + virtual void finish() = 0; virtual void set_initial_prompt_lines(size_t) = 0; virtual void set_vt_size(size_t lines, size_t columns) = 0; @@ -67,6 +68,10 @@ public: virtual ~XtermSuggestionDisplay() override { } virtual void display(const SuggestionManager&) override; virtual bool cleanup() override; + virtual void finish() override + { + m_pages.clear(); + } virtual void set_initial_prompt_lines(size_t lines) override { @@ -77,14 +82,22 @@ public: { m_num_lines = lines; m_num_columns = columns; + m_pages.clear(); } private: + size_t fit_to_page_boundary(size_t selection_index); size_t m_lines_used_for_last_suggestions { 0 }; 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 }; + + struct PageRange { + size_t start; + size_t end; + }; + Vector<PageRange> m_pages; }; } diff --git a/Libraries/LibLine/SuggestionManager.h b/Libraries/LibLine/SuggestionManager.h index 47821b6bb0..cdc201d90b 100644 --- a/Libraries/LibLine/SuggestionManager.h +++ b/Libraries/LibLine/SuggestionManager.h @@ -83,12 +83,13 @@ class SuggestionManager { public: void set_suggestions(Vector<CompletionSuggestion>&& suggestions); - void set_current_suggestion_initiation_index(size_t index); + void set_current_suggestion_initiation_index(size_t start_index); size_t count() const { return m_suggestions.size(); } size_t display_length() const { return m_last_shown_suggestion_display_length; } - size_t index() const { return m_last_displayed_suggestion_index; } + size_t start_index() const { return m_last_displayed_suggestion_index; } size_t next_index() const { return m_next_suggestion_index; } + void set_start_index(size_t index) const { m_last_displayed_suggestion_index = index; } size_t for_each_suggestion(Function<IterationDecision(const CompletionSuggestion&, size_t)>) const; @@ -151,7 +152,7 @@ private: mutable size_t m_next_suggestion_invariant_offset { 0 }; mutable size_t m_next_suggestion_static_offset { 0 }; size_t m_largest_common_suggestion_prefix_length { 0 }; - size_t m_last_displayed_suggestion_index { 0 }; + mutable size_t m_last_displayed_suggestion_index { 0 }; size_t m_selected_suggestion_index { 0 }; }; diff --git a/Libraries/LibLine/XtermSuggestionDisplay.cpp b/Libraries/LibLine/XtermSuggestionDisplay.cpp index 3cd02f6c85..b4e8527b09 100644 --- a/Libraries/LibLine/XtermSuggestionDisplay.cpp +++ b/Libraries/LibLine/XtermSuggestionDisplay.cpp @@ -24,7 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <AK/BinarySearch.h> #include <AK/Function.h> +#include <AK/StringBuilder.h> #include <LibLine/SuggestionDisplay.h> #include <LibLine/VT.h> #include <stdio.h> @@ -43,7 +45,7 @@ void XtermSuggestionDisplay::display(const SuggestionManager& manager) }); size_t num_printed = 0; - size_t lines_used { 1 }; + size_t lines_used = 1; VT::save_cursor(); VT::clear_lines(0, m_lines_used_for_last_suggestions); @@ -62,8 +64,45 @@ void XtermSuggestionDisplay::display(const SuggestionManager& manager) lines_used += max_line_count; longest_suggestion_length = 0; } + VT::move_absolute(max_line_count + m_origin_x, 1); + if (m_pages.is_empty()) { + size_t num_printed = 0; + size_t lines_used = 1; + // cache the pages + manager.set_start_index(0); + size_t page_start = 0; + manager.for_each_suggestion([&](auto& suggestion, auto index) { + size_t next_column = num_printed + suggestion.text_view.length() + longest_suggestion_length + 2; + if (next_column > m_num_columns) { + auto lines = (suggestion.text_view.length() + m_num_columns - 1) / m_num_columns; + lines_used += lines; + num_printed = 0; + } + + if (lines_used + m_prompt_lines_at_suggestion_initiation >= m_num_lines) { + m_pages.append({ page_start, index }); + page_start = index; + lines_used = 1; + num_printed = 0; + } + + if (spans_entire_line) + num_printed += m_num_columns; + else + num_printed += longest_suggestion_length + 2; + + return IterationDecision::Continue; + }); + // last page + m_pages.append({ page_start, manager.count() }); + } + + auto page_index = fit_to_page_boundary(manager.next_index()); + + manager.set_start_index(m_pages[page_index].start); + manager.for_each_suggestion([&](auto& suggestion, auto index) { size_t next_column = num_printed + suggestion.text_view.length() + longest_suggestion_length + 2; @@ -106,6 +145,23 @@ void XtermSuggestionDisplay::display(const SuggestionManager& manager) if (m_origin_x + lines_used >= m_num_lines) { m_origin_x = m_num_lines - lines_used; } + + if (m_pages.size() > 1) { + auto left_arrow = page_index > 0 ? '<' : ' '; + auto right_arrow = page_index < m_pages.size() - 1 ? '>' : ' '; + auto string = String::format("%c page %d of %d %c", left_arrow, page_index + 1, m_pages.size(), right_arrow); + + if (string.length() > m_num_columns - 1) { + // this would overflow into the next line, so just don't print an indicator + return; + } + + VT::move_absolute(m_origin_x + lines_used, m_num_columns - string.length() - 1); + VT::apply_style({ Style::Background(Style::XtermColor::Green) }); + fputs(string.characters(), stdout); + VT::apply_style(Style::reset_style()); + fflush(stdout); + } } bool XtermSuggestionDisplay::cleanup() @@ -119,4 +175,23 @@ bool XtermSuggestionDisplay::cleanup() return false; } +size_t XtermSuggestionDisplay::fit_to_page_boundary(size_t selection_index) +{ + ASSERT(m_pages.size() > 0); + int index = 0; + + auto* match = binary_search( + m_pages.data(), m_pages.size(), { selection_index, selection_index }, [](auto& a, auto& b) -> int { + if (a.start >= b.start && a.start < b.end) + return 0; + return a.start - b.start; + }, + &index); + + if (!match) + return m_pages.size() - 1; + + return index; +} + } |