From d5baf1c1fa6a16144e3d6af5ac9f9b82c255fd64 Mon Sep 17 00:00:00 2001 From: thislooksfun Date: Thu, 28 Oct 2021 20:31:54 -0500 Subject: [PATCH] LibGUI: Allow autocomplete to stay open after applying Previously the autocomplete box would always close after applying a suggestion. This is the desired behavior in almost all cases, but there are some situations (like autocompleting paths) where it would be nicer to keep the autocomplete box open after applying the suggestion. --- .../HackStudio/AutoCompleteResponse.h | 6 +++++- .../Libraries/LibGUI/AutocompleteProvider.cpp | 20 +++++++++++++++---- .../Libraries/LibGUI/AutocompleteProvider.h | 8 +++++++- Userland/Libraries/LibGUI/TextEditor.cpp | 7 +++++-- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Userland/DevTools/HackStudio/AutoCompleteResponse.h b/Userland/DevTools/HackStudio/AutoCompleteResponse.h index f394fa8ff1..b42aa7b386 100644 --- a/Userland/DevTools/HackStudio/AutoCompleteResponse.h +++ b/Userland/DevTools/HackStudio/AutoCompleteResponse.h @@ -22,6 +22,7 @@ inline bool encode(IPC::Encoder& encoder, const GUI::AutocompleteProvider::Entry encoder << (u64)response.partial_input_length; encoder << (u32)response.language; encoder << response.display_text; + encoder << (u32)response.hide_autocomplete_after_applying; return true; } @@ -30,14 +31,17 @@ inline bool decode(IPC::Decoder& decoder, GUI::AutocompleteProvider::Entry& resp { u32 language = 0; u64 partial_input_length = 0; + u32 hide_autocomplete_after_applying = 0; bool ok = decoder.decode(response.completion) && decoder.decode(partial_input_length) && decoder.decode(language) - && decoder.decode(response.display_text); + && decoder.decode(response.display_text) + && decoder.decode(hide_autocomplete_after_applying); if (ok) { response.language = static_cast(language); response.partial_input_length = partial_input_length; + response.hide_autocomplete_after_applying = static_cast(hide_autocomplete_after_applying); } return ok; diff --git a/Userland/Libraries/LibGUI/AutocompleteProvider.cpp b/Userland/Libraries/LibGUI/AutocompleteProvider.cpp index 58ffcea628..58b66cf6c8 100644 --- a/Userland/Libraries/LibGUI/AutocompleteProvider.cpp +++ b/Userland/Libraries/LibGUI/AutocompleteProvider.cpp @@ -34,6 +34,7 @@ public: __ModelRoleCustom = (int)GUI::ModelRole::Custom, PartialInputLength, Completion, + HideAutocompleteAfterApplying, }; virtual int row_count(const GUI::ModelIndex& = GUI::ModelIndex()) const override { return m_suggestions.size(); } @@ -71,6 +72,9 @@ public: if ((int)role == InternalRole::Completion) return suggestion.completion; + if ((int)role == InternalRole::HideAutocompleteAfterApplying) + return suggestion.hide_autocomplete_after_applying == AutocompleteProvider::Entry::HideAutocompleteAfterApplying::Yes; + return {}; } @@ -173,21 +177,27 @@ void AutocompleteBox::previous_suggestion() } } -void AutocompleteBox::apply_suggestion() +AutocompleteProvider::Entry::HideAutocompleteAfterApplying AutocompleteBox::apply_suggestion() { + auto hide_when_done = AutocompleteProvider::Entry::HideAutocompleteAfterApplying::Yes; + if (m_editor.is_null()) - return; + return hide_when_done; if (!m_editor->is_editable()) - return; + return hide_when_done; auto selected_index = m_suggestion_view->selection().first(); if (!selected_index.is_valid() || !m_suggestion_view->model()->is_within_range(selected_index)) - return; + return hide_when_done; auto suggestion_index = m_suggestion_view->model()->index(selected_index.row()); auto completion = suggestion_index.data((GUI::ModelRole)AutocompleteSuggestionModel::InternalRole::Completion).to_string(); size_t partial_length = suggestion_index.data((GUI::ModelRole)AutocompleteSuggestionModel::InternalRole::PartialInputLength).to_i64(); + auto hide_after_applying = suggestion_index.data((GUI::ModelRole)AutocompleteSuggestionModel::InternalRole::HideAutocompleteAfterApplying).to_bool(); + + if (!hide_after_applying) + hide_when_done = AutocompleteProvider::Entry::HideAutocompleteAfterApplying::No; VERIFY(completion.length() >= partial_length); if (!m_editor->has_selection()) { @@ -200,6 +210,8 @@ void AutocompleteBox::apply_suggestion() } m_editor->insert_at_cursor_or_replace_selection(completion); + + return hide_when_done; } bool AutocompleteProvider::Declaration::operator==(const AutocompleteProvider::Declaration& other) const diff --git a/Userland/Libraries/LibGUI/AutocompleteProvider.h b/Userland/Libraries/LibGUI/AutocompleteProvider.h index cec55fae32..7d045bc067 100644 --- a/Userland/Libraries/LibGUI/AutocompleteProvider.h +++ b/Userland/Libraries/LibGUI/AutocompleteProvider.h @@ -32,6 +32,12 @@ public: size_t partial_input_length { 0 }; Language language { Language::Unspecified }; String display_text {}; + + enum class HideAutocompleteAfterApplying { + No, + Yes, + }; + HideAutocompleteAfterApplying hide_autocomplete_after_applying { HideAutocompleteAfterApplying::Yes }; }; struct ProjectLocation { @@ -89,7 +95,7 @@ public: bool has_suggestions() { return m_suggestion_view->model()->row_count() > 0; } void next_suggestion(); void previous_suggestion(); - void apply_suggestion(); + AutocompleteProvider::Entry::HideAutocompleteAfterApplying apply_suggestion(); private: WeakPtr m_editor; diff --git a/Userland/Libraries/LibGUI/TextEditor.cpp b/Userland/Libraries/LibGUI/TextEditor.cpp index 50ed109186..0d8fb9e17b 100644 --- a/Userland/Libraries/LibGUI/TextEditor.cpp +++ b/Userland/Libraries/LibGUI/TextEditor.cpp @@ -739,8 +739,11 @@ void TextEditor::select_all() void TextEditor::keydown_event(KeyEvent& event) { if (m_autocomplete_box && m_autocomplete_box->is_visible() && (event.key() == KeyCode::Key_Return || event.key() == KeyCode::Key_Tab)) { - m_autocomplete_box->apply_suggestion(); - hide_autocomplete(); + TemporaryChange change { m_should_keep_autocomplete_box, true }; + if (m_autocomplete_box->apply_suggestion() == AutocompleteProvider::Entry::HideAutocompleteAfterApplying::Yes) + hide_autocomplete(); + else + try_update_autocomplete(); return; }