mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 06:47:35 +00:00
Assistant: Add a new FileProvider to assist in searching the filesystem
When searching in Assistant, we now dispatch some background jobs to query the whole filesystem. Activating a result will use the Desktop launcher's default way of opening that file or directory.
This commit is contained in:
parent
00f93b2545
commit
e6f0b2d817
3 changed files with 100 additions and 1 deletions
|
@ -6,7 +6,11 @@
|
||||||
|
|
||||||
#include "Providers.h"
|
#include "Providers.h"
|
||||||
#include "FuzzyMatch.h"
|
#include "FuzzyMatch.h"
|
||||||
|
#include <AK/URL.h>
|
||||||
|
#include <LibCore/DirIterator.h>
|
||||||
|
#include <LibCore/File.h>
|
||||||
#include <LibCore/StandardPaths.h>
|
#include <LibCore/StandardPaths.h>
|
||||||
|
#include <LibDesktop/Launcher.h>
|
||||||
#include <LibGUI/Clipboard.h>
|
#include <LibGUI/Clipboard.h>
|
||||||
#include <LibGUI/FileIconProvider.h>
|
#include <LibGUI/FileIconProvider.h>
|
||||||
#include <LibJS/Interpreter.h>
|
#include <LibJS/Interpreter.h>
|
||||||
|
@ -32,6 +36,11 @@ void CalculatorResult::activate() const
|
||||||
GUI::Clipboard::the().set_plain_text(title());
|
GUI::Clipboard::the().set_plain_text(title());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileResult::activate() const
|
||||||
|
{
|
||||||
|
Desktop::Launcher::open(URL::create_with_file_protocol(title()));
|
||||||
|
}
|
||||||
|
|
||||||
void AppProvider::query(String const& query, Function<void(Vector<NonnullRefPtr<Result>>)> on_complete)
|
void AppProvider::query(String const& query, Function<void(Vector<NonnullRefPtr<Result>>)> on_complete)
|
||||||
{
|
{
|
||||||
if (query.starts_with("="))
|
if (query.starts_with("="))
|
||||||
|
@ -82,4 +91,64 @@ void CalculatorProvider::query(String const& query, Function<void(Vector<Nonnull
|
||||||
on_complete(results);
|
on_complete(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileProvider::query(const String& query, Function<void(Vector<NonnullRefPtr<Result>>)> on_complete)
|
||||||
|
{
|
||||||
|
build_filesystem_cache();
|
||||||
|
|
||||||
|
if (m_fuzzy_match_work)
|
||||||
|
m_fuzzy_match_work->cancel();
|
||||||
|
|
||||||
|
m_fuzzy_match_work = Threading::BackgroundAction<Vector<NonnullRefPtr<Result>>>::create([this, query](auto& task) {
|
||||||
|
Vector<NonnullRefPtr<Result>> results;
|
||||||
|
|
||||||
|
for (auto& path : m_full_path_cache) {
|
||||||
|
if (task.is_cancelled())
|
||||||
|
return results;
|
||||||
|
|
||||||
|
auto match_result = fuzzy_match(query, path);
|
||||||
|
if (!match_result.matched)
|
||||||
|
continue;
|
||||||
|
if (match_result.score < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
results.append(adopt_ref(*new FileResult(path, match_result.score)));
|
||||||
|
}
|
||||||
|
return results; }, [on_complete = move(on_complete)](auto results) { on_complete(results); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileProvider::build_filesystem_cache()
|
||||||
|
{
|
||||||
|
if (m_full_path_cache.size() > 0 || m_building_cache)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_building_cache = true;
|
||||||
|
m_work_queue.enqueue("/");
|
||||||
|
|
||||||
|
Threading::BackgroundAction<int>::create([this](auto&) {
|
||||||
|
while (!m_work_queue.is_empty()) {
|
||||||
|
auto start = m_work_queue.dequeue();
|
||||||
|
Core::DirIterator di(start, Core::DirIterator::SkipDots);
|
||||||
|
|
||||||
|
while (di.has_next()) {
|
||||||
|
auto path = di.next_full_path();
|
||||||
|
struct stat st = {};
|
||||||
|
if (lstat(path.characters(), &st) < 0) {
|
||||||
|
perror("stat");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISLNK(st.st_mode))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
m_full_path_cache.append(path);
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
m_work_queue.enqueue(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; }, [this](auto) { m_building_cache = false; });
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,13 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Queue.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <LibDesktop/AppFile.h>
|
#include <LibDesktop/AppFile.h>
|
||||||
#include <LibGUI/Desktop.h>
|
#include <LibGUI/Desktop.h>
|
||||||
#include <LibJS/Interpreter.h>
|
#include <LibJS/Interpreter.h>
|
||||||
#include <LibJS/Runtime/VM.h>
|
#include <LibJS/Runtime/VM.h>
|
||||||
|
#include <LibThreading/BackgroundAction.h>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
namespace Assistant {
|
namespace Assistant {
|
||||||
|
@ -72,6 +74,16 @@ public:
|
||||||
void activate() const override;
|
void activate() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FileResult : public Result {
|
||||||
|
public:
|
||||||
|
explicit FileResult(String title, int score)
|
||||||
|
: Result(GUI::Icon::default_icon("filetype-folder").bitmap_for_size(16), move(title), "", score)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~FileResult() override = default;
|
||||||
|
void activate() const override;
|
||||||
|
};
|
||||||
|
|
||||||
class Provider {
|
class Provider {
|
||||||
public:
|
public:
|
||||||
virtual ~Provider() = default;
|
virtual ~Provider() = default;
|
||||||
|
@ -89,4 +101,16 @@ public:
|
||||||
void query(String const& query, Function<void(Vector<NonnullRefPtr<Result>>)> on_complete) override;
|
void query(String const& query, Function<void(Vector<NonnullRefPtr<Result>>)> on_complete) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FileProvider : public Provider {
|
||||||
|
public:
|
||||||
|
void query(String const& query, Function<void(Vector<NonnullRefPtr<Result>>)> on_complete) override;
|
||||||
|
void build_filesystem_cache();
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<Threading::BackgroundAction<Vector<NonnullRefPtr<Result>>>> m_fuzzy_match_work;
|
||||||
|
bool m_building_cache { false };
|
||||||
|
Vector<String> m_full_path_cache;
|
||||||
|
Queue<String> m_work_queue;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,12 +120,17 @@ public:
|
||||||
explicit Database(AppState& state)
|
explicit Database(AppState& state)
|
||||||
: m_state(state)
|
: m_state(state)
|
||||||
{
|
{
|
||||||
|
m_file_provider.build_filesystem_cache();
|
||||||
}
|
}
|
||||||
|
|
||||||
Function<void(Vector<NonnullRefPtr<Result>>)> on_new_results;
|
Function<void(Vector<NonnullRefPtr<Result>>)> on_new_results;
|
||||||
|
|
||||||
void search(String const& query)
|
void search(String const& query)
|
||||||
{
|
{
|
||||||
|
m_file_provider.query(query, [=, this](auto results) {
|
||||||
|
recv_results(query, results);
|
||||||
|
});
|
||||||
|
|
||||||
m_app_provider.query(query, [=, this](auto results) {
|
m_app_provider.query(query, [=, this](auto results) {
|
||||||
recv_results(query, results);
|
recv_results(query, results);
|
||||||
});
|
});
|
||||||
|
@ -172,6 +177,7 @@ private:
|
||||||
|
|
||||||
AppProvider m_app_provider;
|
AppProvider m_app_provider;
|
||||||
CalculatorProvider m_calculator_provider;
|
CalculatorProvider m_calculator_provider;
|
||||||
|
FileProvider m_file_provider;
|
||||||
|
|
||||||
Threading::Lock m_lock;
|
Threading::Lock m_lock;
|
||||||
HashMap<String, Vector<NonnullRefPtr<Result>>> m_result_cache;
|
HashMap<String, Vector<NonnullRefPtr<Result>>> m_result_cache;
|
||||||
|
@ -183,7 +189,7 @@ static constexpr size_t MAX_SEARCH_RESULTS = 6;
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if (pledge("stdio recvfd sendfd rpath unix proc exec", nullptr) < 0) {
|
if (pledge("stdio recvfd sendfd rpath unix proc exec thread", nullptr) < 0) {
|
||||||
perror("pledge");
|
perror("pledge");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue