diff --git a/Userland/DevTools/HackStudio/DeclarationsModel.cpp b/Userland/DevTools/HackStudio/DeclarationsModel.cpp index de162aa412..054ff70cf2 100644 --- a/Userland/DevTools/HackStudio/DeclarationsModel.cpp +++ b/Userland/DevTools/HackStudio/DeclarationsModel.cpp @@ -57,4 +57,35 @@ GUI::Variant DeclarationsModel::data(GUI::ModelIndex const& index, GUI::ModelRol return {}; } +GUI::Model::MatchResult DeclarationsModel::data_matches(GUI::ModelIndex const& index, GUI::Variant const& term) const +{ + if (index.row() < 0 || (size_t)index.row() >= m_declarations.size()) + return { TriState::False }; + + auto needle = term.as_string(); + if (needle.is_empty()) + return { TriState::True }; + + auto& declaration = m_declarations[index.row()]; + if (declaration.is_filename()) { + if (declaration.as_filename->contains(needle, CaseSensitivity::CaseInsensitive)) + return { TriState::True }; + return { TriState::False }; + } + if (declaration.is_symbol_declaration()) { + if (declaration.as_symbol_declaration->name.contains(needle, CaseSensitivity::CaseInsensitive) + || declaration.as_symbol_declaration->scope.contains(needle, CaseSensitivity::CaseInsensitive)) + return { TriState::True }; + return { TriState::False }; + } + + return { TriState::False }; +} + +void DeclarationsModel::set_declarations(Vector&& declarations) +{ + m_declarations = move(declarations); + did_update(); +} + } diff --git a/Userland/DevTools/HackStudio/DeclarationsModel.h b/Userland/DevTools/HackStudio/DeclarationsModel.h index c7bbf8b9cd..310c503ccf 100644 --- a/Userland/DevTools/HackStudio/DeclarationsModel.h +++ b/Userland/DevTools/HackStudio/DeclarationsModel.h @@ -48,8 +48,10 @@ public: virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Column_Count; } virtual GUI::Variant data(GUI::ModelIndex const& index, GUI::ModelRole role) const override; + virtual MatchResult data_matches(GUI::ModelIndex const&, GUI::Variant const&) const override; Vector const& declarations() const { return m_declarations; } + void set_declarations(Vector&&); private: Vector m_declarations; diff --git a/Userland/DevTools/HackStudio/Locator.cpp b/Userland/DevTools/HackStudio/Locator.cpp index 594d648346..921fedf516 100644 --- a/Userland/DevTools/HackStudio/Locator.cpp +++ b/Userland/DevTools/HackStudio/Locator.cpp @@ -77,12 +77,15 @@ Locator::Locator(Core::EventReceiver* parent) m_suggestion_view->on_activation = [this](auto& index) { open_suggestion(index); }; + + m_model = GUI::FilteringProxyModel::create(ProjectDeclarations::the().declarations_model()).release_value_but_fixme_should_propagate_errors(); + m_suggestion_view->set_model(m_model); } void Locator::open_suggestion(const GUI::ModelIndex& index) { - auto& model = reinterpret_cast(*m_suggestion_view->model()); - auto suggestion = model.declarations()[index.row()]; + auto original_index = m_model->map(index); + auto suggestion = ProjectDeclarations::the().declarations_model().declarations()[original_index.row()]; if (suggestion.is_filename()) { auto filename = suggestion.as_filename.value(); open_file(filename); @@ -111,23 +114,9 @@ void Locator::close() void Locator::update_suggestions() { - auto typed_text = m_textbox->text(); - Vector suggestions; - project().for_each_text_file([&](auto& file) { - if (file.name().contains(typed_text, CaseSensitivity::CaseInsensitive)) - suggestions.append(Declaration::create_filename(file.name())); - }); + m_model->set_filter_term(m_textbox->text()); - ProjectDeclarations::the().for_each_declared_symbol([&suggestions, &typed_text](auto& decl) { - if (decl.name.contains(typed_text, CaseSensitivity::CaseInsensitive) || decl.scope.contains(typed_text, CaseSensitivity::CaseInsensitive)) - suggestions.append((Declaration::create_symbol_declaration(decl))); - }); - - bool has_suggestions = !suggestions.is_empty(); - - m_suggestion_view->set_model(adopt_ref(*new DeclarationsModel(move(suggestions)))); - - if (!has_suggestions) + if (m_model->row_count() == 0) m_suggestion_view->selection().clear(); else m_suggestion_view->selection().set(m_suggestion_view->model()->index(0)); diff --git a/Userland/DevTools/HackStudio/Locator.h b/Userland/DevTools/HackStudio/Locator.h index b5525449e1..3ad48c2b0a 100644 --- a/Userland/DevTools/HackStudio/Locator.h +++ b/Userland/DevTools/HackStudio/Locator.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include namespace HackStudio { @@ -29,6 +30,7 @@ private: RefPtr m_textbox; RefPtr m_popup_window; RefPtr m_suggestion_view; + RefPtr m_model; }; } diff --git a/Userland/DevTools/HackStudio/ProjectDeclarations.cpp b/Userland/DevTools/HackStudio/ProjectDeclarations.cpp index b4adce4f7b..701c46e85d 100644 --- a/Userland/DevTools/HackStudio/ProjectDeclarations.cpp +++ b/Userland/DevTools/HackStudio/ProjectDeclarations.cpp @@ -1,24 +1,35 @@ /* * Copyright (c) 2021, Itamar S. + * Copyright (c) 2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #include "ProjectDeclarations.h" +#include "HackStudio.h" -HackStudio::ProjectDeclarations& HackStudio::ProjectDeclarations::the() +namespace HackStudio { + +ProjectDeclarations::ProjectDeclarations() + : m_declarations_model(adopt_ref(*new DeclarationsModel({}))) +{ +} + +ProjectDeclarations& ProjectDeclarations::the() { static ProjectDeclarations s_instance; return s_instance; } -void HackStudio::ProjectDeclarations::set_declared_symbols(ByteString const& filename, Vector const& declarations) +void ProjectDeclarations::set_declared_symbols(ByteString const& filename, Vector const& declarations) { m_document_to_declarations.set(filename, declarations); + // FIXME: Partially invalidate the model instead of fully rebuilding it. + update_declarations_model(); if (on_update) on_update(); } -Optional HackStudio::ProjectDeclarations::get_icon_for(CodeComprehension::DeclarationType type) +Optional ProjectDeclarations::get_icon_for(CodeComprehension::DeclarationType type) { static GUI::Icon struct_icon(Gfx::Bitmap::load_from_file("/res/icons/hackstudio/Struct.png"sv).release_value_but_fixme_should_propagate_errors()); static GUI::Icon class_icon(Gfx::Bitmap::load_from_file("/res/icons/hackstudio/Class.png"sv).release_value_but_fixme_should_propagate_errors()); @@ -46,3 +57,17 @@ Optional HackStudio::ProjectDeclarations::get_icon_for(CodeComprehens return {}; } } + +void ProjectDeclarations::update_declarations_model() +{ + Vector declarations; + project().for_each_text_file([&](auto& file) { + declarations.append(Declaration::create_filename(file.name())); + }); + for_each_declared_symbol([&declarations](auto& decl) { + declarations.append((Declaration::create_symbol_declaration(decl))); + }); + m_declarations_model->set_declarations(move(declarations)); +} + +} diff --git a/Userland/DevTools/HackStudio/ProjectDeclarations.h b/Userland/DevTools/HackStudio/ProjectDeclarations.h index d356cfd33e..da04516574 100644 --- a/Userland/DevTools/HackStudio/ProjectDeclarations.h +++ b/Userland/DevTools/HackStudio/ProjectDeclarations.h @@ -1,11 +1,13 @@ /* * Copyright (c) 2021, Itamar S. + * Copyright (c) 2024, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include "DeclarationsModel.h" #include #include #include @@ -25,13 +27,18 @@ public: void set_declared_symbols(ByteString const& filename, Vector const&); + DeclarationsModel& declarations_model() { return m_declarations_model; } + void update_declarations_model(); + static Optional get_icon_for(CodeComprehension::DeclarationType); Function on_update = nullptr; private: - ProjectDeclarations() = default; + ProjectDeclarations(); + HashMap> m_document_to_declarations; + NonnullRefPtr m_declarations_model; }; template