Commit 73a451ad authored by Christian Hergert's avatar Christian Hergert
Browse files

Merge branch 'gwagner/gnome-builder-gwagner/rust-analyzer-2'

parents f7cb219f b993e563
......@@ -83,6 +83,7 @@ enum {
};
enum {
INITIALIZED,
LOAD_CONFIGURATION,
NOTIFICATION,
PUBLISHED_DIAGNOSTICS,
......@@ -744,8 +745,64 @@ ide_lsp_client_real_notification (IdeLspClient *self,
if (params != NULL)
{
if (g_str_equal (method, "textDocument/publishDiagnostics"))
{
ide_lsp_client_text_document_publish_diagnostics (self, params);
}
else if (g_str_equal (method, "$/progress"))
{
gboolean notification_exists = FALSE;
const gchar *token = NULL;
const gchar *message = NULL;
const gchar *title = NULL;
const gchar *kind = NULL;
IdeContext *context;
IdeNotifications *notifications;
IdeNotification *notification = NULL;
JSONRPC_MESSAGE_PARSE (params, "token", JSONRPC_MESSAGE_GET_STRING (&token),
"value", "{",
"kind", JSONRPC_MESSAGE_GET_STRING (&kind),
"}");
JSONRPC_MESSAGE_PARSE (params, "value", "{",
"title", JSONRPC_MESSAGE_GET_STRING (&title),
"}");
JSONRPC_MESSAGE_PARSE (params, "value", "{",
"message", JSONRPC_MESSAGE_GET_STRING (&message),
"}");
context = ide_object_get_context (IDE_OBJECT (self));
notifications = ide_object_get_child_typed (IDE_OBJECT (context), IDE_TYPE_NOTIFICATIONS);
notification = ide_notifications_find_by_id (notifications, token);
if (notification == NULL)
notification_exists = FALSE;
else
notification_exists = TRUE;
if (ide_str_equal0 (kind, "begin"))
{
if (!notification_exists)
{
notification = ide_notification_new ();
ide_notification_set_id (notification, token);
ide_notification_set_has_progress (notification, TRUE);
ide_notification_set_progress_is_imprecise (notification, TRUE);
}
ide_notification_set_title (notification, title);
ide_notification_set_body (notification, message != NULL ? message : title);
if (!notification_exists)
ide_notification_attach (notification, IDE_OBJECT (context));
}
else
{
if (message != NULL && notification != NULL)
ide_notification_set_body (notification, message);
}
if (ide_str_equal0 (kind, "end") && notification != NULL)
ide_notification_withdraw (notification);
}
}
IDE_EXIT;
}
......@@ -958,6 +1015,10 @@ ide_lsp_client_handle_call (IdeLspClient *self,
IDE_RETURN (ret);
}
else if (strcmp (method, "window/workDoneProgress/create") == 0)
{
IDE_RETURN (TRUE);
}
IDE_RETURN (FALSE);
}
......@@ -1090,6 +1151,17 @@ ide_lsp_client_class_init (IdeLspClientClass *klass)
g_object_class_install_properties (object_class, N_PROPS, properties);
signals [INITIALIZED] =
g_signal_new ("initialized",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (IdeLspClientClass, initialized),
NULL,
NULL,
NULL,
G_TYPE_NONE, 0);
/**
* IdeLspClient::load-configuration:
* @self: a #IdeLspClient
......@@ -1235,6 +1307,8 @@ ide_lsp_client_initialized_cb (GObject *object,
project = ide_project_from_context (context);
dzl_signal_group_set_target (priv->project_signals, project);
g_signal_emit (self, signals[INITIALIZED], 0);
IDE_EXIT;
}
......@@ -1429,6 +1503,9 @@ ide_lsp_client_start (IdeLspClient *self)
"}",
"}",
"}",
"window", "{",
"workDoneProgress", JSONRPC_MESSAGE_PUT_BOOLEAN (TRUE),
"}",
"}"
);
......
......@@ -53,6 +53,7 @@ struct _IdeLspClientClass
GFile *file,
IdeDiagnostics *diagnostics);
GVariant *(*load_configuration) (IdeLspClient *self);
void (*initialized) (IdeLspClient *self);
/*< private >*/
gpointer _reserved[15];
......
......@@ -96,8 +96,18 @@ parse_marked_string (GVariant *v)
if (g_variant_is_of_type (v, G_VARIANT_TYPE_VARIANT))
v = child = g_variant_get_variant (v);
g_variant_iter_init (&iter, v);
if (g_variant_is_of_type (v, G_VARIANT_TYPE_DICTIONARY))
{
const gchar *value = "";
g_variant_lookup (v, "value", "&s", &value);
if (!ide_str_empty0 (value))
g_string_append_printf (gstr, "%s", value);
}
else
{
g_variant_iter_init (&iter, v);
if ((item = g_variant_iter_next_value (&iter)))
{
GVariant *asv = item;
......@@ -116,20 +126,20 @@ parse_marked_string (GVariant *v)
g_variant_lookup (asv, "language", "&s", &lang);
g_variant_lookup (asv, "value", "&s", &value);
#if 0
#if 0
if (!ide_str_empty0 (lang) && !ide_str_empty0 (value))
g_string_append_printf (str, "```%s\n%s\n```", lang, value);
else if (!ide_str_empty0 (value))
g_string_append (str, value);
#else
#else
if (!ide_str_empty0 (value))
g_string_append_printf (gstr, "```\n%s\n```", value);
#endif
#endif
}
g_variant_unref (item);
}
}
if (gstr->len)
return ide_marked_content_new_from_data (gstr->str, gstr->len, IDE_MARKED_KIND_MARKDOWN);
......
......@@ -144,50 +144,14 @@ ide_lsp_rename_provider_init (IdeLspRenameProvider *self)
{
}
static void
ide_lsp_rename_provider_rename_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
/*
* Parsing a TextEdit Variant happens here. See specification
* https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textEdit
* for further details
*/
static IdeTextEdit *
_extract_text_edit (GFile *gfile, GVariant *change)
{
IdeLspClient *client = (IdeLspClient *)object;
g_autoptr(GVariant) return_value = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(IdeTask) task = user_data;
g_autoptr(GPtrArray) ret = NULL;
g_autoptr(GVariantIter) changes_by_uri = NULL;
const gchar *uri;
GVariant *changes;
IDE_ENTRY;
g_assert (IDE_IS_LSP_CLIENT (client));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
if (!ide_lsp_client_call_finish (client, result, &return_value, &error))
{
ide_task_return_error (task, g_steal_pointer (&error));
IDE_EXIT;
}
if (!JSONRPC_MESSAGE_PARSE (return_value, "changes", JSONRPC_MESSAGE_GET_ITER (&changes_by_uri)))
IDE_EXIT;
ret = g_ptr_array_new_with_free_func (g_object_unref);
while (g_variant_iter_loop (changes_by_uri, "{sv}", &uri, &changes))
{
g_autoptr(GFile) gfile = g_file_new_for_uri (uri);
GVariantIter changes_iter;
GVariant *change;
if (!g_variant_is_container (changes))
continue;
g_variant_iter_init (&changes_iter, changes);
while (g_variant_iter_loop (&changes_iter, "v", &change))
{
g_autoptr(IdeLocation) begin_location = NULL;
g_autoptr(IdeLocation) end_location = NULL;
g_autoptr(IdeRange) range = NULL;
......@@ -215,14 +179,47 @@ ide_lsp_rename_provider_rename_cb (GObject *object,
if (!success)
{
IDE_TRACE_MSG ("Failed to extract change from variant");
continue;
return NULL;
}
begin_location = ide_location_new (gfile, begin.line, begin.column);
end_location = ide_location_new (gfile, end.line, end.column);
range = ide_range_new (begin_location, end_location);
g_ptr_array_add (ret, ide_text_edit_new (range, new_text));
return ide_text_edit_new (range, new_text);
}
static void
ide_lsp_rename_provider_rename_cb_changes (IdeTask *task, GVariant *return_value)
{
g_autoptr(GPtrArray) ret = NULL;
g_autoptr(GVariantIter) changes_by_uri = NULL;
const gchar *uri;
GVariant *changes;
IDE_ENTRY;
if (!JSONRPC_MESSAGE_PARSE (return_value, "changes", JSONRPC_MESSAGE_GET_ITER (&changes_by_uri)))
IDE_EXIT;
ret = g_ptr_array_new_with_free_func (g_object_unref);
while (g_variant_iter_loop (changes_by_uri, "{sv}", &uri, &changes))
{
g_autoptr(GFile) gfile = g_file_new_for_uri (uri);
GVariantIter changes_iter;
GVariant *change;
if (!g_variant_is_container (changes))
continue;
g_variant_iter_init (&changes_iter, changes);
while (g_variant_iter_loop (&changes_iter, "v", &change))
{
IdeTextEdit *edit = _extract_text_edit (gfile, change);
if (edit != NULL)
g_ptr_array_add (ret, edit);
}
}
......@@ -231,6 +228,78 @@ ide_lsp_rename_provider_rename_cb (GObject *object,
IDE_EXIT;
}
static void
ide_lsp_rename_provider_rename_cb_document_changes (IdeTask *task, GVariant *return_value)
{
g_autoptr(GPtrArray) ret = NULL;
g_autoptr(GVariantIter) changes_by_textdocument = NULL;
GVariant *changes;
IDE_ENTRY;
if (!JSONRPC_MESSAGE_PARSE (return_value, "documentChanges", JSONRPC_MESSAGE_GET_ITER (&changes_by_textdocument)))
IDE_EXIT;
ret = g_ptr_array_new_with_free_func (g_object_unref);
while (g_variant_iter_loop (changes_by_textdocument, "v", &changes))
{
g_autoptr(GFile) gfile = NULL;
g_autoptr(GVariantIter) edits = NULL;
const gchar *uri;
GVariant *edit;
JSONRPC_MESSAGE_PARSE (changes, "textDocument", "{", "uri", JSONRPC_MESSAGE_GET_STRING (&uri), "}");
gfile = g_file_new_for_uri (uri);
if (!JSONRPC_MESSAGE_PARSE (changes, "edits", JSONRPC_MESSAGE_GET_ITER (&edits)))
IDE_EXIT;
while (g_variant_iter_loop (edits, "v", &edit))
{
IdeTextEdit *tedit = _extract_text_edit (gfile, edit);
if (tedit != NULL)
g_ptr_array_add (ret, tedit);
}
}
ide_task_return_pointer (task, g_steal_pointer (&ret), g_ptr_array_unref);
IDE_EXIT;
}
static void
ide_lsp_rename_provider_rename_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
IdeLspClient *client = (IdeLspClient *)object;
g_autoptr(GVariant) return_value = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(IdeTask) task = user_data;
g_autoptr(GVariantDict) dict = NULL;
IDE_ENTRY;
g_assert (IDE_IS_LSP_CLIENT (client));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (IDE_IS_TASK (task));
if (!ide_lsp_client_call_finish (client, result, &return_value, &error))
{
ide_task_return_error (task, g_steal_pointer (&error));
IDE_EXIT;
}
dict = g_variant_dict_new (return_value);
if (g_variant_dict_contains (dict, "changes"))
ide_lsp_rename_provider_rename_cb_changes (g_steal_pointer (&task), return_value);
else if (g_variant_dict_contains (dict, "documentChanges"))
ide_lsp_rename_provider_rename_cb_document_changes (g_steal_pointer (&task), return_value);
IDE_EXIT;
}
static void
ide_lsp_rename_provider_rename_async (IdeRenameProvider *provider,
IdeLocation *location,
......
......@@ -39,5 +39,6 @@
#include "ide-lsp-symbol-node.h"
#include "ide-lsp-symbol-resolver.h"
#include "ide-lsp-symbol-tree.h"
#include "ide-lsp-util.h"
#undef IDE_LSP_INSIDE
......@@ -36,6 +36,7 @@ struct _IdeSearchEngine
{
IdeObject parent_instance;
PeasExtensionSet *extensions;
GPtrArray *custom_provider;
guint active_count;
};
......@@ -139,6 +140,7 @@ ide_search_engine_destroy (IdeObject *object)
IdeSearchEngine *self = (IdeSearchEngine *)object;
g_clear_object (&self->extensions);
g_clear_object (&self->custom_provider);
IDE_OBJECT_CLASS (ide_search_engine_parent_class)->destroy (object);
}
......@@ -186,6 +188,7 @@ ide_search_engine_class_init (IdeSearchEngineClass *klass)
static void
ide_search_engine_init (IdeSearchEngine *self)
{
self->custom_provider = g_ptr_array_new ();
}
IdeSearchEngine *
......@@ -264,6 +267,27 @@ cleanup:
ide_task_return_pointer (task, g_steal_pointer (&r->store), g_object_unref);
}
static void
_provider_search_async (IdeSearchProvider *provider,
Request *request)
{
g_assert (IDE_IS_SEARCH_PROVIDER (provider));
g_assert (request != NULL);
g_assert (IDE_IS_TASK (request->task));
g_assert (G_IS_LIST_STORE (request->store));
request->outstanding++;
ide_search_provider_search_async (provider,
request->query,
request->max_results,
ide_task_get_cancellable (request->task),
ide_search_engine_search_cb,
g_object_ref (request->task));
}
static void
ide_search_engine_search_foreach (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
......@@ -280,14 +304,22 @@ ide_search_engine_search_foreach (PeasExtensionSet *set,
g_assert (IDE_IS_TASK (r->task));
g_assert (G_IS_LIST_STORE (r->store));
r->outstanding++;
_provider_search_async (provider, r);
}
static void
ide_search_engine_search_foreach_custom_provider (gpointer data,
gpointer user_data)
{
IdeSearchProvider *provider = (IdeSearchProvider *)data;
Request *r = user_data;
ide_search_provider_search_async (provider,
r->query,
r->max_results,
ide_task_get_cancellable (r->task),
ide_search_engine_search_cb,
g_object_ref (r->task));
g_assert (IDE_IS_SEARCH_PROVIDER (provider));
g_assert (r != NULL);
g_assert (IDE_IS_TASK (r->task));
g_assert (G_IS_LIST_STORE (r->store));
_provider_search_async (provider, r);
}
void
......@@ -322,6 +354,9 @@ ide_search_engine_search_async (IdeSearchEngine *self,
peas_extension_set_foreach (self->extensions,
ide_search_engine_search_foreach,
r);
g_ptr_array_foreach (self->custom_provider,
ide_search_engine_search_foreach_custom_provider,
r);
self->active_count += r->outstanding;
......@@ -357,3 +392,43 @@ ide_search_engine_search_finish (IdeSearchEngine *self,
return ide_task_propagate_pointer (IDE_TASK (result), error);
}
/**
* ide_search_engine_add_provider:
* @self: a #IdeSearchEngine
* @provider: a #IdeSearchProvider
*
* Adds a custom search provider to the #IdeSearchEngine. This enables
* to bring in custom #IdeSearchProvider during the runtime.
*
* Since: 3.38
*/
void
ide_search_engine_add_provider (IdeSearchEngine *self,
IdeSearchProvider *provider)
{
g_return_if_fail (IDE_IS_SEARCH_ENGINE (self));
g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
g_ptr_array_add (self->custom_provider, provider);
}
/**
* ide_search_engine_remove_provider:
* @self: a #IdeSearchEngine
* @provider: a #IdeSearchProvider
*
* Remove a custom search provider from the #IdeSearchEngine. This removes
* custom #IdeSearchProvider during the runtime.
*
* Since: 3.38
*/
void
ide_search_engine_remove_provider (IdeSearchEngine *self,
IdeSearchProvider *provider)
{
g_return_if_fail (IDE_IS_SEARCH_ENGINE (self));
g_return_if_fail (IDE_IS_SEARCH_PROVIDER (provider));
g_ptr_array_remove (self->custom_provider, provider);
}
......@@ -25,6 +25,7 @@
#endif
#include <libide-core.h>
#include "ide-search-provider.h"
G_BEGIN_DECLS
......@@ -32,7 +33,6 @@ G_BEGIN_DECLS
IDE_AVAILABLE_IN_3_32
G_DECLARE_FINAL_TYPE (IdeSearchEngine, ide_search_engine, IDE, SEARCH_ENGINE, IdeObject)
IDE_AVAILABLE_IN_3_32
IdeSearchEngine *ide_search_engine_new (void);
IDE_AVAILABLE_IN_3_32
......@@ -48,5 +48,11 @@ IDE_AVAILABLE_IN_3_32
GListModel *ide_search_engine_search_finish (IdeSearchEngine *self,
GAsyncResult *result,
GError **error);
IDE_AVAILABLE_IN_3_36
void ide_search_engine_add_provider (IdeSearchEngine *self,
IdeSearchProvider *provider);
IDE_AVAILABLE_IN_3_36
void ide_search_engine_remove_provider (IdeSearchEngine *self,
IdeSearchProvider *provider);
G_END_DECLS
......@@ -4951,6 +4951,9 @@ ide_source_view_real_begin_rename (IdeSourceView *self)
GtkTextBuffer *buffer;
GtkTextMark *insert;
GtkTextIter iter;
GtkTextIter word_start;
GtkTextIter word_end;
g_autofree gchar *symbol = NULL;
GdkRectangle loc;
IDE_ENTRY;
......@@ -4982,9 +4985,33 @@ ide_source_view_real_begin_rename (IdeSourceView *self)
GTK_TEXT_WINDOW_WIDGET,
loc.x, loc.y, &loc.x, &loc.y);
// get symbol to rename (for the popup)
if (gtk_text_iter_inside_word (&iter) && !gtk_text_iter_starts_word (&iter))
{
word_start = iter;
word_end = iter;
gtk_text_iter_backward_word_start (&word_start);
gtk_text_iter_forward_word_end (&word_end);
}
else if (gtk_text_iter_starts_word (&iter))
{
word_start = iter;
word_end = iter;
gtk_text_iter_forward_word_end (&word_end);
}
else if (gtk_text_iter_ends_word (&iter))
{
word_start = iter;
word_end = iter;
gtk_text_iter_backward_word_start (&word_start);
}
symbol = gtk_text_iter_get_text (&word_start, &word_end);
popover = g_object_new (DZL_TYPE_SIMPLE_POPOVER,
"title", _("Rename symbol"),
"button-text", _("Rename"),
"text", symbol,
"relative-to", self,
"pointing-to", &loc,
NULL);
......
......@@ -7,8 +7,14 @@ plugins_sources += files([
'rust-analyzer-symbol-resolver.c',
'rust-analyzer-diagnostic-provider.c',
'rust-analyzer-formatter.c',
'rust-analyzer-highlighter.c',
'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',
'rust-analyzer-preferences-addin.c',
])
plugin_rust_analyzer_resources = gnome.compile_resources(
......@@ -19,4 +25,6 @@ plugin_rust_analyzer_resources = gnome.compile_resources(
plugins_sources += plugin_rust_analyzer_resources
install_data(['org.gnome.builder.rust-analyzer.gschema.xml'], install_dir: schema_dir)
endif
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema id="org.gnome.builder.rust-analyzer" path="/org/gnome/builder/plugins/rust-analyzer/" gettext-domain="gnome-builder">
<key name="cargo-command" type="s">
<choices>
<choice value="check"/>
<choice value="clippy"/>
</choices>
<default>'check'</default>
</key>
</schema>
</schemalist>