diff options
author | Spencer Dixon <spencercdixon@gmail.com> | 2021-07-02 10:36:09 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-07-02 16:47:14 +0200 |
commit | e6f0b2d817d04c6af88c6f9f61f04c40e343f64e (patch) | |
tree | 17c7022f950508d897fd43993a61068a77a3f4d9 /Userland/Applications | |
parent | 00f93b254547c6a63e58cfc46591f6db07cc6765 (diff) | |
download | serenity-e6f0b2d817d04c6af88c6f9f61f04c40e343f64e.zip |
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.
Diffstat (limited to 'Userland/Applications')
-rw-r--r-- | Userland/Applications/Assistant/Providers.cpp | 69 | ||||
-rw-r--r-- | Userland/Applications/Assistant/Providers.h | 24 | ||||
-rw-r--r-- | Userland/Applications/Assistant/main.cpp | 8 |
3 files changed, 100 insertions, 1 deletions
diff --git a/Userland/Applications/Assistant/Providers.cpp b/Userland/Applications/Assistant/Providers.cpp index 02d0fabfe4..c4cd58e6c3 100644 --- a/Userland/Applications/Assistant/Providers.cpp +++ b/Userland/Applications/Assistant/Providers.cpp @@ -6,7 +6,11 @@ #include "Providers.h" #include "FuzzyMatch.h" +#include <AK/URL.h> +#include <LibCore/DirIterator.h> +#include <LibCore/File.h> #include <LibCore/StandardPaths.h> +#include <LibDesktop/Launcher.h> #include <LibGUI/Clipboard.h> #include <LibGUI/FileIconProvider.h> #include <LibJS/Interpreter.h> @@ -32,6 +36,11 @@ void CalculatorResult::activate() const 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) { if (query.starts_with("=")) @@ -82,4 +91,64 @@ void CalculatorProvider::query(String const& query, Function<void(Vector<Nonnull 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; }); +} + } diff --git a/Userland/Applications/Assistant/Providers.h b/Userland/Applications/Assistant/Providers.h index 7d94e1fd12..538568d0ad 100644 --- a/Userland/Applications/Assistant/Providers.h +++ b/Userland/Applications/Assistant/Providers.h @@ -6,11 +6,13 @@ #pragma once +#include <AK/Queue.h> #include <AK/String.h> #include <LibDesktop/AppFile.h> #include <LibGUI/Desktop.h> #include <LibJS/Interpreter.h> #include <LibJS/Runtime/VM.h> +#include <LibThreading/BackgroundAction.h> #include <typeinfo> namespace Assistant { @@ -72,6 +74,16 @@ public: 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 { public: virtual ~Provider() = default; @@ -89,4 +101,16 @@ public: 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; +}; + } diff --git a/Userland/Applications/Assistant/main.cpp b/Userland/Applications/Assistant/main.cpp index 1e18ac40ed..783ccc819f 100644 --- a/Userland/Applications/Assistant/main.cpp +++ b/Userland/Applications/Assistant/main.cpp @@ -120,12 +120,17 @@ public: explicit Database(AppState& state) : m_state(state) { + m_file_provider.build_filesystem_cache(); } Function<void(Vector<NonnullRefPtr<Result>>)> on_new_results; 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) { recv_results(query, results); }); @@ -172,6 +177,7 @@ private: AppProvider m_app_provider; CalculatorProvider m_calculator_provider; + FileProvider m_file_provider; Threading::Lock m_lock; 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) { - 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"); return 1; } |