[gnome-builder: 11/17] rust-analyzer: added search provider for symbols
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder: 11/17] rust-analyzer: added search provider for symbols
- Date: Mon, 22 Jun 2020 19:23:31 +0000 (UTC)
commit b727ef2168d0c7632e8d2c6827491208948d595d
Author: Günther Wagner <info gunibert de>
Date: Sun May 31 13:23:33 2020 +0200
rust-analyzer: added search provider for symbols
src/plugins/rust-analyzer/meson.build | 2 +
.../rust-analyzer/rust-analyzer-search-provider.c | 261 +++++++++++++++++++++
.../rust-analyzer/rust-analyzer-search-provider.h | 36 +++
.../rust-analyzer/rust-analyzer-search-result.c | 146 ++++++++++++
.../rust-analyzer/rust-analyzer-search-result.h | 37 +++
src/plugins/rust-analyzer/rust-analyzer-service.c | 33 ++-
6 files changed, 509 insertions(+), 6 deletions(-)
---
diff --git a/src/plugins/rust-analyzer/meson.build b/src/plugins/rust-analyzer/meson.build
index 1d153a2df..cb32b05c1 100644
--- a/src/plugins/rust-analyzer/meson.build
+++ b/src/plugins/rust-analyzer/meson.build
@@ -11,6 +11,8 @@ plugins_sources += files([
'rust-analyzer-hover-provider.c',
'rust-analyzer-rename-provider.c',
'rust-analyzer-transfer.c',
+ 'rust-analyzer-search-provider.c',
+ 'rust-analyzer-search-result.c',
'rust-analyzer-workbench-addin.c',
])
diff --git a/src/plugins/rust-analyzer/rust-analyzer-search-provider.c
b/src/plugins/rust-analyzer/rust-analyzer-search-provider.c
new file mode 100644
index 000000000..8dd921999
--- /dev/null
+++ b/src/plugins/rust-analyzer/rust-analyzer-search-provider.c
@@ -0,0 +1,261 @@
+/* rust-analyzer-search-provider.c
+ *
+ * Copyright 2020 Günther Wagner <info gunibert de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "rust-analyzer-search-provider"
+
+#include "rust-analyzer-search-provider.h"
+#include <libide-search.h>
+#include <jsonrpc-glib.h>
+#include <libide-lsp.h>
+#include "rust-analyzer-service.h"
+#include "rust-analyzer-search-result.h"
+
+struct _RustAnalyzerSearchProvider
+{
+ IdeObject parent_instance;
+
+ IdeLspClient *client;
+};
+
+static void provider_iface_init (IdeSearchProviderInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (RustAnalyzerSearchProvider,
+ rust_analyzer_search_provider,
+ IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_SEARCH_PROVIDER, provider_iface_init))
+
+enum {
+ PROP_0,
+ PROP_CLIENT,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+RustAnalyzerSearchProvider *
+rust_analyzer_search_provider_new (void)
+{
+ return g_object_new (RUST_TYPE_ANALYZER_SEARCH_PROVIDER, NULL);
+}
+
+static void
+rust_analyzer_search_provider_finalize (GObject *object)
+{
+ RustAnalyzerSearchProvider *self = (RustAnalyzerSearchProvider *)object;
+
+ g_clear_object (&self->client);
+
+ G_OBJECT_CLASS (rust_analyzer_search_provider_parent_class)->finalize (object);
+}
+
+static void
+rust_analyzer_search_provider_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ RustAnalyzerSearchProvider *self = RUST_ANALYZER_SEARCH_PROVIDER (object);
+
+ switch (prop_id)
+ {
+ case PROP_CLIENT:
+ g_value_set_object (value, rust_analyzer_search_provider_get_client (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+rust_analyzer_search_provider_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ RustAnalyzerSearchProvider *self = RUST_ANALYZER_SEARCH_PROVIDER (object);
+
+ switch (prop_id)
+ {
+ case PROP_CLIENT:
+ rust_analyzer_search_provider_set_client (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+rust_analyzer_search_provider_class_init (RustAnalyzerSearchProviderClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = rust_analyzer_search_provider_finalize;
+ object_class->get_property = rust_analyzer_search_provider_get_property;
+ object_class->set_property = rust_analyzer_search_provider_set_property;
+
+ properties[PROP_CLIENT] =
+ g_param_spec_object ("client",
+ "client",
+ "The Language Server client",
+ IDE_TYPE_LSP_CLIENT,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+rust_analyzer_search_provider_init (RustAnalyzerSearchProvider *self)
+{
+}
+
+static void
+rust_analyzer_search_provider_search_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ IdeLspClient *client = (IdeLspClient *) source_object;
+ GPtrArray *ar;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GVariant) result = NULL;
+ g_autoptr(GVariantIter) iter = NULL;
+ GVariant *symbol_information;
+ GError *error = NULL;
+
+ IDE_ENTRY;
+
+ ar = g_ptr_array_new ();
+
+ ide_lsp_client_call_finish (client, res, &result, &error);
+ if (error != NULL)
+ {
+ ide_task_return_error (task, error);
+ return;
+ }
+
+ iter = g_variant_iter_new (result);
+
+ while (g_variant_iter_loop (iter, "v", &symbol_information))
+ {
+ g_autoptr(GFile) gfile = NULL;
+ g_autoptr(IdeLocation) location = NULL;
+ const gchar *title;
+ const gchar *uri;
+ gint64 kind;
+ gint64 line, character;
+ IdeSymbolKind symbol_kind;
+ const gchar *icon_name;
+
+ JSONRPC_MESSAGE_PARSE (symbol_information,
+ "name", JSONRPC_MESSAGE_GET_STRING (&title),
+ "kind", JSONRPC_MESSAGE_GET_INT64 (&kind),
+ "location", "{",
+ "uri", JSONRPC_MESSAGE_GET_STRING (&uri),
+ "range", "{",
+ "start", "{",
+ "line", JSONRPC_MESSAGE_GET_INT64 (&line),
+ "character", JSONRPC_MESSAGE_GET_INT64 (&character),
+ "}",
+ "}",
+ "}");
+
+ symbol_kind = ide_lsp_decode_symbol_kind (kind);
+ icon_name = ide_symbol_kind_get_icon_name (symbol_kind);
+
+ gfile = g_file_new_for_uri (uri);
+ location = ide_location_new (gfile, line, character);
+
+ g_ptr_array_add (ar, rust_analyzer_search_result_new (title, g_file_get_basename (gfile), location,
icon_name));
+ }
+
+ ide_task_return_pointer (task,
+ g_steal_pointer(&ar),
+ g_ptr_array_unref);
+
+ IDE_EXIT;
+}
+
+static void
+rust_analyzer_search_provider_search_async (IdeSearchProvider *provider,
+ const gchar *query,
+ guint max_results,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ RustAnalyzerSearchProvider *self = (RustAnalyzerSearchProvider *)provider;
+ g_autoptr(IdeTask) task = NULL;
+ g_autoptr(GVariant) params = NULL;
+
+ IDE_ENTRY;
+
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (RUST_IS_ANALYZER_SEARCH_PROVIDER (self));
+ g_return_if_fail (query != NULL);
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, rust_analyzer_search_provider_search_async);
+
+ params = JSONRPC_MESSAGE_NEW ("query", JSONRPC_MESSAGE_PUT_STRING (query));
+
+ ide_lsp_client_call_async (self->client,
+ "workspace/symbol",
+ params,
+ cancellable,
+ rust_analyzer_search_provider_search_cb,
+ g_steal_pointer (&task));
+
+ IDE_EXIT;
+}
+
+static GPtrArray *
+rust_analyzer_search_provider_search_finish (IdeSearchProvider *provider,
+ GAsyncResult *result,
+ GError **error)
+{
+ return ide_task_propagate_pointer (IDE_TASK (result), error);
+}
+
+static void
+provider_iface_init (IdeSearchProviderInterface *iface)
+{
+ iface->search_async = rust_analyzer_search_provider_search_async;
+ iface->search_finish = rust_analyzer_search_provider_search_finish;
+}
+
+IdeLspClient *
+rust_analyzer_search_provider_get_client (RustAnalyzerSearchProvider *self)
+{
+ g_return_val_if_fail (RUST_IS_ANALYZER_SEARCH_PROVIDER (self), NULL);
+
+ return self->client;
+}
+
+void
+rust_analyzer_search_provider_set_client (RustAnalyzerSearchProvider *self,
+ IdeLspClient *client)
+{
+ g_return_if_fail (RUST_IS_ANALYZER_SEARCH_PROVIDER (self));
+ g_return_if_fail (!client || IDE_IS_LSP_CLIENT (client));
+
+ if (self->client != NULL)
+ g_clear_pointer (&self->client, g_object_unref);
+ self->client = g_object_ref (client);
+}
diff --git a/src/plugins/rust-analyzer/rust-analyzer-search-provider.h
b/src/plugins/rust-analyzer/rust-analyzer-search-provider.h
new file mode 100644
index 000000000..30ed6f96c
--- /dev/null
+++ b/src/plugins/rust-analyzer/rust-analyzer-search-provider.h
@@ -0,0 +1,36 @@
+/* rust-analyzer-search-provider.h
+ *
+ * Copyright 2020 Günther Wagner <info gunibert de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-lsp.h>
+
+G_BEGIN_DECLS
+
+#define RUST_TYPE_ANALYZER_SEARCH_PROVIDER (rust_analyzer_search_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (RustAnalyzerSearchProvider, rust_analyzer_search_provider, RUST,
ANALYZER_SEARCH_PROVIDER, IdeObject)
+
+RustAnalyzerSearchProvider *rust_analyzer_search_provider_new (void);
+IdeLspClient *rust_analyzer_search_provider_get_client (RustAnalyzerSearchProvider *self);
+void rust_analyzer_search_provider_set_client (RustAnalyzerSearchProvider *self,
+ IdeLspClient *client);
+
+G_END_DECLS
diff --git a/src/plugins/rust-analyzer/rust-analyzer-search-result.c
b/src/plugins/rust-analyzer/rust-analyzer-search-result.c
new file mode 100644
index 000000000..a7c9e2201
--- /dev/null
+++ b/src/plugins/rust-analyzer/rust-analyzer-search-result.c
@@ -0,0 +1,146 @@
+/* rust-analyzer-search-result.c
+ *
+ * Copyright 2020 Günther Wagner <info gunibert de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "rust-analyzer-search-result.h"
+#include <libide-editor.h>
+
+struct _RustAnalyzerSearchResult
+{
+ IdeSearchResult parent_instance;
+ IdeLocation *location;
+};
+
+G_DEFINE_TYPE (RustAnalyzerSearchResult, rust_analyzer_search_result, IDE_TYPE_SEARCH_RESULT)
+
+enum {
+ PROP_0,
+ PROP_LOCATION,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+RustAnalyzerSearchResult *
+rust_analyzer_search_result_new (const gchar *title,
+ const gchar *subtitle,
+ IdeLocation *location,
+ const gchar *icon_name)
+{
+ return g_object_new (RUST_TYPE_ANALYZER_SEARCH_RESULT,
+ "title", title,
+ "subtitle", subtitle,
+ "location", location,
+ "icon-name", icon_name,
+ // place search results before the other search providers
+ "priority", -1,
+ NULL);
+}
+
+static void
+rust_analyzer_search_result_finalize (GObject *object)
+{
+ RustAnalyzerSearchResult *self = (RustAnalyzerSearchResult *)object;
+
+ g_clear_object (&self->location);
+
+ G_OBJECT_CLASS (rust_analyzer_search_result_parent_class)->finalize (object);
+}
+
+static void
+rust_analyzer_search_result_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ RustAnalyzerSearchResult *self = RUST_ANALYZER_SEARCH_RESULT (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_object (value, self->location);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+rust_analyzer_search_result_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ RustAnalyzerSearchResult *self = RUST_ANALYZER_SEARCH_RESULT (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ self->location = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+rust_analyzer_search_result_activate (IdeSearchResult *result,
+ GtkWidget *last_focus)
+{
+
+ RustAnalyzerSearchResult *self = (RustAnalyzerSearchResult *)result;
+ IdeWorkspace *workspace;
+ IdeSurface *editor;
+
+ g_assert (RUST_IS_ANALYZER_SEARCH_RESULT (self));
+ g_assert (GTK_IS_WIDGET (last_focus));
+
+ if (!last_focus)
+ return;
+
+ if ((workspace = ide_widget_get_workspace (last_focus)) &&
+ (editor = ide_workspace_get_surface_by_name (workspace, "editor")))
+ ide_editor_surface_focus_location (IDE_EDITOR_SURFACE (editor), self->location);
+}
+
+static void
+rust_analyzer_search_result_class_init (RustAnalyzerSearchResultClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ IdeSearchResultClass *search_class = IDE_SEARCH_RESULT_CLASS (klass);
+
+ object_class->finalize = rust_analyzer_search_result_finalize;
+ object_class->get_property = rust_analyzer_search_result_get_property;
+ object_class->set_property = rust_analyzer_search_result_set_property;
+ search_class->activate = rust_analyzer_search_result_activate;
+
+ properties [PROP_LOCATION] =
+ g_param_spec_object ("location",
+ "location",
+ "Location of the symbol",
+ IDE_TYPE_LOCATION,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+rust_analyzer_search_result_init (RustAnalyzerSearchResult *self)
+{
+}
diff --git a/src/plugins/rust-analyzer/rust-analyzer-search-result.h
b/src/plugins/rust-analyzer/rust-analyzer-search-result.h
new file mode 100644
index 000000000..8e9cd60bc
--- /dev/null
+++ b/src/plugins/rust-analyzer/rust-analyzer-search-result.h
@@ -0,0 +1,37 @@
+/* rust-analyzer-search-result.h
+ *
+ * Copyright 2020 Günther Wagner <info gunibert de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-code.h>
+#include <libide-search.h>
+
+G_BEGIN_DECLS
+
+#define RUST_TYPE_ANALYZER_SEARCH_RESULT (rust_analyzer_search_result_get_type())
+
+G_DECLARE_FINAL_TYPE (RustAnalyzerSearchResult, rust_analyzer_search_result, RUST, ANALYZER_SEARCH_RESULT,
IdeSearchResult)
+
+RustAnalyzerSearchResult *rust_analyzer_search_result_new (const gchar *title,
+ const gchar *subtitle,
+ IdeLocation *location,
+ const gchar *icon_name);
+
+G_END_DECLS
diff --git a/src/plugins/rust-analyzer/rust-analyzer-service.c
b/src/plugins/rust-analyzer/rust-analyzer-service.c
index f770ac32f..88f9cd7a3 100644
--- a/src/plugins/rust-analyzer/rust-analyzer-service.c
+++ b/src/plugins/rust-analyzer/rust-analyzer-service.c
@@ -28,6 +28,8 @@
#include <libide-core.h>
#include <jsonrpc-glib.h>
#include <glib/gi18n.h>
+#include <libide-search.h>
+#include "rust-analyzer-search-provider.h"
struct _RustAnalyzerService
{
@@ -35,6 +37,7 @@ struct _RustAnalyzerService
IdeLspClient *client;
IdeSubprocessSupervisor *supervisor;
GFileMonitor *cargo_monitor;
+ RustAnalyzerSearchProvider *search_provider;
ServiceState state;
};
@@ -74,14 +77,15 @@ _cargo_toml_changed_cb (GFileMonitor *monitor,
}
}
-static void
-rust_analyzer_service_finalize (GObject *object)
+static IdeSearchEngine *
+_get_search_engine (RustAnalyzerService *self)
{
- RustAnalyzerService *self = (RustAnalyzerService *)object;
+ IdeContext *context = NULL;
- g_clear_object (&self->client);
+ g_assert (RUST_IS_ANALYZER_SERVICE (self));
- G_OBJECT_CLASS (rust_analyzer_service_parent_class)->finalize (object);
+ context = ide_object_get_context (IDE_OBJECT (self));
+ return ide_object_get_child_typed (IDE_OBJECT (context), IDE_TYPE_SEARCH_ENGINE);
}
static void
@@ -162,6 +166,7 @@ static void
rust_analyzer_service_destroy (IdeObject *object)
{
RustAnalyzerService *self = RUST_ANALYZER_SERVICE (object);
+ IdeSearchEngine *search_engine = NULL;
if (self->supervisor != NULL)
{
@@ -170,6 +175,13 @@ rust_analyzer_service_destroy (IdeObject *object)
ide_subprocess_supervisor_stop (supervisor);
}
+ g_clear_object (&self->client);
+
+ search_engine = _get_search_engine (self);
+ if (search_engine != NULL)
+ ide_search_engine_remove_provider (search_engine, IDE_SEARCH_PROVIDER (self->search_provider));
+ g_clear_object (&self->search_provider);
+
IDE_OBJECT_CLASS (rust_analyzer_service_parent_class)->destroy (object);
}
@@ -179,7 +191,6 @@ rust_analyzer_service_class_init (RustAnalyzerServiceClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
IdeObjectClass *i_class = IDE_OBJECT_CLASS (klass);
- object_class->finalize = rust_analyzer_service_finalize;
object_class->get_property = rust_analyzer_service_get_property;
object_class->set_property = rust_analyzer_service_set_property;
@@ -254,6 +265,16 @@ rust_analyzer_service_lsp_started (IdeSubprocessSupervisor *supervisor,
ide_object_append (IDE_OBJECT (self), IDE_OBJECT (client));
ide_lsp_client_add_language (client, "rust");
ide_lsp_client_start (client);
+
+ // register SearchProvider
+ if (self->search_provider == NULL)
+ {
+ IdeSearchEngine *search_engine = _get_search_engine (self);
+
+ self->search_provider = rust_analyzer_search_provider_new ();
+ ide_search_engine_add_provider (search_engine, IDE_SEARCH_PROVIDER (self->search_provider));
+ }
+ rust_analyzer_search_provider_set_client (self->search_provider, client);
}
static gboolean
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]