mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:47:44 +00:00
HackStudio: Keep the DeclarationsModel around, and use a filtering proxy
Rather than construct a new DeclarationsModel each time the user types something in the Locator, keep a single one around permanently in the ProjectDeclarations, and then use a FilteringProxyModel over it for the suggestions.
This commit is contained in:
parent
e72b14ef1d
commit
85101c6626
6 changed files with 78 additions and 22 deletions
|
@ -57,4 +57,35 @@ GUI::Variant DeclarationsModel::data(GUI::ModelIndex const& index, GUI::ModelRol
|
||||||
return {};
|
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<HackStudio::Declaration>&& declarations)
|
||||||
|
{
|
||||||
|
m_declarations = move(declarations);
|
||||||
|
did_update();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,10 @@ public:
|
||||||
|
|
||||||
virtual int column_count(GUI::ModelIndex const& = GUI::ModelIndex()) const override { return Column::__Column_Count; }
|
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 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<Declaration> const& declarations() const { return m_declarations; }
|
Vector<Declaration> const& declarations() const { return m_declarations; }
|
||||||
|
void set_declarations(Vector<Declaration>&&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<Declaration> m_declarations;
|
Vector<Declaration> m_declarations;
|
||||||
|
|
|
@ -77,12 +77,15 @@ Locator::Locator(Core::EventReceiver* parent)
|
||||||
m_suggestion_view->on_activation = [this](auto& index) {
|
m_suggestion_view->on_activation = [this](auto& index) {
|
||||||
open_suggestion(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)
|
void Locator::open_suggestion(const GUI::ModelIndex& index)
|
||||||
{
|
{
|
||||||
auto& model = reinterpret_cast<DeclarationsModel&>(*m_suggestion_view->model());
|
auto original_index = m_model->map(index);
|
||||||
auto suggestion = model.declarations()[index.row()];
|
auto suggestion = ProjectDeclarations::the().declarations_model().declarations()[original_index.row()];
|
||||||
if (suggestion.is_filename()) {
|
if (suggestion.is_filename()) {
|
||||||
auto filename = suggestion.as_filename.value();
|
auto filename = suggestion.as_filename.value();
|
||||||
open_file(filename);
|
open_file(filename);
|
||||||
|
@ -111,23 +114,9 @@ void Locator::close()
|
||||||
|
|
||||||
void Locator::update_suggestions()
|
void Locator::update_suggestions()
|
||||||
{
|
{
|
||||||
auto typed_text = m_textbox->text();
|
m_model->set_filter_term(m_textbox->text());
|
||||||
Vector<Declaration> suggestions;
|
|
||||||
project().for_each_text_file([&](auto& file) {
|
|
||||||
if (file.name().contains(typed_text, CaseSensitivity::CaseInsensitive))
|
|
||||||
suggestions.append(Declaration::create_filename(file.name()));
|
|
||||||
});
|
|
||||||
|
|
||||||
ProjectDeclarations::the().for_each_declared_symbol([&suggestions, &typed_text](auto& decl) {
|
if (m_model->row_count() == 0)
|
||||||
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)
|
|
||||||
m_suggestion_view->selection().clear();
|
m_suggestion_view->selection().clear();
|
||||||
else
|
else
|
||||||
m_suggestion_view->selection().set(m_suggestion_view->model()->index(0));
|
m_suggestion_view->selection().set(m_suggestion_view->model()->index(0));
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
|
#include <LibGUI/FilteringProxyModel.h>
|
||||||
#include <LibGUI/Widget.h>
|
#include <LibGUI/Widget.h>
|
||||||
|
|
||||||
namespace HackStudio {
|
namespace HackStudio {
|
||||||
|
@ -29,6 +30,7 @@ private:
|
||||||
RefPtr<GUI::TextBox> m_textbox;
|
RefPtr<GUI::TextBox> m_textbox;
|
||||||
RefPtr<GUI::Window> m_popup_window;
|
RefPtr<GUI::Window> m_popup_window;
|
||||||
RefPtr<GUI::TableView> m_suggestion_view;
|
RefPtr<GUI::TableView> m_suggestion_view;
|
||||||
|
RefPtr<GUI::FilteringProxyModel> m_model;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,35 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
|
* Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
|
||||||
|
* Copyright (c) 2024, Sam Atkins <atkinssj@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ProjectDeclarations.h"
|
#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;
|
static ProjectDeclarations s_instance;
|
||||||
return s_instance;
|
return s_instance;
|
||||||
}
|
}
|
||||||
void HackStudio::ProjectDeclarations::set_declared_symbols(ByteString const& filename, Vector<CodeComprehension::Declaration> const& declarations)
|
void ProjectDeclarations::set_declared_symbols(ByteString const& filename, Vector<CodeComprehension::Declaration> const& declarations)
|
||||||
{
|
{
|
||||||
m_document_to_declarations.set(filename, declarations);
|
m_document_to_declarations.set(filename, declarations);
|
||||||
|
// FIXME: Partially invalidate the model instead of fully rebuilding it.
|
||||||
|
update_declarations_model();
|
||||||
if (on_update)
|
if (on_update)
|
||||||
on_update();
|
on_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<GUI::Icon> HackStudio::ProjectDeclarations::get_icon_for(CodeComprehension::DeclarationType type)
|
Optional<GUI::Icon> 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 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());
|
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<GUI::Icon> HackStudio::ProjectDeclarations::get_icon_for(CodeComprehens
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectDeclarations::update_declarations_model()
|
||||||
|
{
|
||||||
|
Vector<Declaration> 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
|
* Copyright (c) 2021, Itamar S. <itamar8910@gmail.com>
|
||||||
|
* Copyright (c) 2024, Sam Atkins <atkinssj@serenityos.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "DeclarationsModel.h"
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
|
@ -25,13 +27,18 @@ public:
|
||||||
|
|
||||||
void set_declared_symbols(ByteString const& filename, Vector<CodeComprehension::Declaration> const&);
|
void set_declared_symbols(ByteString const& filename, Vector<CodeComprehension::Declaration> const&);
|
||||||
|
|
||||||
|
DeclarationsModel& declarations_model() { return m_declarations_model; }
|
||||||
|
void update_declarations_model();
|
||||||
|
|
||||||
static Optional<GUI::Icon> get_icon_for(CodeComprehension::DeclarationType);
|
static Optional<GUI::Icon> get_icon_for(CodeComprehension::DeclarationType);
|
||||||
|
|
||||||
Function<void()> on_update = nullptr;
|
Function<void()> on_update = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProjectDeclarations() = default;
|
ProjectDeclarations();
|
||||||
|
|
||||||
HashMap<ByteString, Vector<CodeComprehension::Declaration>> m_document_to_declarations;
|
HashMap<ByteString, Vector<CodeComprehension::Declaration>> m_document_to_declarations;
|
||||||
|
NonnullRefPtr<DeclarationsModel> m_declarations_model;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue