summaryrefslogtreecommitdiff
path: root/Userland/Applications/Assistant
diff options
context:
space:
mode:
authorSpencer Dixon <spencercdixon@gmail.com>2021-07-02 10:36:09 -0400
committerAndreas Kling <kling@serenityos.org>2021-07-02 16:47:14 +0200
commite6f0b2d817d04c6af88c6f9f61f04c40e343f64e (patch)
tree17c7022f950508d897fd43993a61068a77a3f4d9 /Userland/Applications/Assistant
parent00f93b254547c6a63e58cfc46591f6db07cc6765 (diff)
downloadserenity-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/Assistant')
-rw-r--r--Userland/Applications/Assistant/Providers.cpp69
-rw-r--r--Userland/Applications/Assistant/Providers.h24
-rw-r--r--Userland/Applications/Assistant/main.cpp8
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;
}