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,7 +745,63 @@ 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);
{
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,40 +96,50 @@ 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 ((item = g_variant_iter_next_value (&iter)))
if (g_variant_is_of_type (v, G_VARIANT_TYPE_DICTIONARY))
{
GVariant *asv = item;
g_autoptr(GVariant) child2 = NULL;
const gchar *value = "";
if (g_variant_is_of_type (item, G_VARIANT_TYPE_VARIANT))
asv = child2 = g_variant_get_variant (item);
if (g_variant_is_of_type (asv, G_VARIANT_TYPE_STRING))
g_string_append (gstr, g_variant_get_string (asv, NULL));
else if (g_variant_is_of_type (asv, G_VARIANT_TYPE_VARDICT))
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)))
{
const gchar *lang = "";
const gchar *value = "";
g_variant_lookup (asv, "language", "&s", &lang);
g_variant_lookup (asv, "value", "&s", &value);
#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
if (!ide_str_empty0 (value))
g_string_append_printf (gstr, "```\n%s\n```", value);
#endif
GVariant *asv = item;
g_autoptr(GVariant) child2 = NULL;
if (g_variant_is_of_type (item, G_VARIANT_TYPE_VARIANT))
asv = child2 = g_variant_get_variant (item);
if (g_variant_is_of_type (asv, G_VARIANT_TYPE_STRING))
g_string_append (gstr, g_variant_get_string (asv, NULL));
else if (g_variant_is_of_type (asv, G_VARIANT_TYPE_VARDICT))
{
const gchar *lang = "";
const gchar *value = "";
g_variant_lookup (asv, "language", "&s", &lang);
g_variant_lookup (asv, "value", "&s", &value);
#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
if (!ide_str_empty0 (value))
g_string_append_printf (gstr, "```\n%s\n```", value);
#endif
}
g_variant_unref (item);
}
g_variant_unref (item);
}
if (gstr->len)
return ide_marked_content_new_from_data (gstr->str, gstr->len, IDE_MARKED_KIND_MARKDOWN);
......
......@@ -144,32 +144,61 @@ ide_lsp_rename_provider_init (IdeLspRenameProvider *self)
{
}
/*
* 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)
{
g_autoptr(IdeLocation) begin_location = NULL;
g_autoptr(IdeLocation) end_location = NULL;
g_autoptr(IdeRange) range = NULL;
const gchar *new_text = NULL;
gboolean success;
struct {
gint64 line;
gint64 column;
} begin, end;
success = JSONRPC_MESSAGE_PARSE (change,
"range", "{",
"start", "{",
"line", JSONRPC_MESSAGE_GET_INT64 (&begin.line),
"character", JSONRPC_MESSAGE_GET_INT64 (&begin.column),
"}",
"end", "{",
"line", JSONRPC_MESSAGE_GET_INT64 (&end.line),
"character", JSONRPC_MESSAGE_GET_INT64 (&end.column),
"}",
"}",
"newText", JSONRPC_MESSAGE_GET_STRING (&new_text)
);
if (!success)
{
IDE_TRACE_MSG ("Failed to extract change from variant");
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);
return ide_text_edit_new (range, new_text);
}
static void
ide_lsp_rename_provider_rename_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
ide_lsp_rename_provider_rename_cb_changes (IdeTask *task, GVariant *return_value)
{
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;
......@@ -188,41 +217,49 @@ ide_lsp_rename_provider_rename_cb (GObject *object,
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;
const gchar *new_text = NULL;
gboolean success;
struct {
gint64 line;
gint64 column;
} begin, end;
success = JSONRPC_MESSAGE_PARSE (change,
"range", "{",
"start", "{",
"line", JSONRPC_MESSAGE_GET_INT64 (&begin.line),
"character", JSONRPC_MESSAGE_GET_INT64 (&begin.column),
"}",
"end", "{",
"line", JSONRPC_MESSAGE_GET_INT64 (&end.line),
"character", JSONRPC_MESSAGE_GET_INT64 (&end.column),
"}",
"}",
"newText", JSONRPC_MESSAGE_GET_STRING (&new_text)
);
if (!success)
{
IDE_TRACE_MSG ("Failed to extract change from variant");
continue;
}
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));
IdeTextEdit *edit = _extract_text_edit (gfile, change);
if (edit != NULL)
g_ptr_array_add (ret, edit);
}
}
ide_task_return_pointer (task, g_steal_pointer (&ret), g_ptr_array_unref);
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);
}
}
......@@ -231,6 +268,38 @@ ide_lsp_rename_provider_rename_cb (GObject *object,
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,
......@@ -307,9 +376,9 @@ ide_lsp_rename_provider_rename_async (IdeRenameProvider *provider,
static gboolean
ide_lsp_rename_provider_rename_finish (IdeRenameProvider *provider,
GAsyncResult *result,
GPtrArray **edits,
GError **error)
GAsyncResult *result,
GPtrArray **edits,
GError **error)
{
g_autoptr(GPtrArray) ar = NULL;
gboolean ret;
......
......@@ -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);
}
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));
static void
ide_search_engine_search_foreach_custom_provider (gpointer data,
gpointer user_data)
{
IdeSearchProvider *provider = (IdeSearchProvider *)data;
Request *r = user_data;
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,21 +33,26 @@ 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);
IdeSearchEngine *ide_search_engine_new (void);
IDE_AVAILABLE_IN_3_32
gboolean ide_search_engine_get_busy (IdeSearchEngine *self);
gboolean ide_search_engine_get_busy (IdeSearchEngine *self);
IDE_AVAILABLE_IN_3_32
void ide_search_engine_search_async (IdeSearchEngine *self,
const gchar *query,
guint max_results,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
void ide_search_engine_search_async (IdeSearchEngine *self,
const gchar *query,
guint max_results,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
IDE_AVAILABLE_IN_3_32
GListModel *ide_search_engine_search_finish (IdeSearchEngine *self,
GAsyncResult *result,
GError **error);
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,