[gnome-builder/wip/chergert/langserv] langserv: add call and notifications access
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/langserv] langserv: add call and notifications access
- Date: Sat, 22 Oct 2016 23:22:16 +0000 (UTC)
commit 5abd5013f2eac350240ca6f816de71f2f767f9c4
Author: Christian Hergert <chergert redhat com>
Date: Sat Oct 22 16:21:49 2016 -0700
langserv: add call and notifications access
This allows external tooling to use the JsonrpcClient when necessary.
I think we'll probably want to do as much as we can for internal libide
machanincs in IdeLangservClient rather than the plugins. Otherwise, we
have to come up with exotic caching in external structures rather than
just in the LangservClient directly.
libide/Makefile.am | 2 +-
libide/langserv/ide-langserv-client.c | 204 ++++++++++++++++++++++++++++++---
libide/langserv/ide-langserv-client.h | 24 +++-
3 files changed, 207 insertions(+), 23 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 7174fc9..33ca2a8 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -640,7 +640,7 @@ introspection_sources = \
$(NULL)
Ide-1.0.gir: libide-1.0.la
-Ide_1_0_gir_INCLUDES = Gio-2.0 GtkSource-3.0 Peas-1.0
+Ide_1_0_gir_INCLUDES = Gio-2.0 GtkSource-3.0 Peas-1.0 Json-1.0
Ide_1_0_gir_CFLAGS = $(libide_1_0_la_CFLAGS)
Ide_1_0_gir_LIBS = \
libide-1.0.la \
diff --git a/libide/langserv/ide-langserv-client.c b/libide/langserv/ide-langserv-client.c
index 14907d7..cdf51ac 100644
--- a/libide/langserv/ide-langserv-client.c
+++ b/libide/langserv/ide-langserv-client.c
@@ -18,6 +18,7 @@
#define G_LOG_DOMAIN "ide-langserv-client"
+#include <egg-counter.h>
#include <egg-signal-group.h>
#include <jsonrpc-glib.h>
#include <unistd.h>
@@ -27,6 +28,8 @@
#include "buffers/ide-buffer.h"
#include "buffers/ide-buffer-manager.h"
+#include "diagnostics/ide-diagnostic.h"
+#include "diagnostics/ide-diagnostics.h"
#include "langserv/ide-langserv-client.h"
#include "projects/ide-project.h"
#include "vcs/ide-vcs.h"
@@ -37,6 +40,7 @@ typedef struct
EggSignalGroup *project_signals;
JsonrpcClient *rpc_client;
GIOStream *io_stream;
+ GHashTable *diagnostics_by_uri;
} IdeLangservClientPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (IdeLangservClient, ide_langserv_client, IDE_TYPE_OBJECT)
@@ -53,7 +57,13 @@ enum {
N_PROPS
};
+enum {
+ NOTIFICATION,
+ N_SIGNALS
+};
+
static GParamSpec *properties [N_PROPS];
+static guint signals [N_SIGNALS];
static void
ide_langserv_client_buffer_loaded (IdeLangservClient *self,
@@ -208,11 +218,85 @@ ide_langserv_client_project_file_renamed (IdeLangservClient *self,
}
static void
+ide_langserv_client_text_document_publish_diagnostics (IdeLangservClient *self,
+ JsonNode *params)
+{
+ const gchar *uri = NULL;
+ JsonArray *diagnostics = NULL;
+ gboolean success;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_LANGSERV_CLIENT (self));
+ g_assert (params != NULL);
+
+ success = JCON_EXTRACT (params,
+ "uri", JCONE_STRING (uri),
+ "diagnostics", JCONE_ARRAY (diagnostics)
+ );
+
+ if (!success)
+ IDE_EXIT;
+
+ IDE_TRACE_MSG ("Diagnostics received for %s", uri);
+
+ IDE_EXIT;
+}
+
+static void
+ide_langserv_client_real_notification (IdeLangservClient *self,
+ const gchar *method,
+ JsonNode *params)
+{
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_LANGSERV_CLIENT (self));
+ g_assert (method != NULL);
+ g_assert (params != NULL);
+
+ if (g_str_equal (method, "textDocument/publishDiagnostics"))
+ ide_langserv_client_text_document_publish_diagnostics (self, params);
+
+ IDE_EXIT;
+}
+
+static void
+ide_langserv_client_notification (IdeLangservClient *self,
+ const gchar *method,
+ JsonNode *params,
+ JsonrpcClient *rpc_client)
+{
+ GQuark detail;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_LANGSERV_CLIENT (self));
+ g_assert (method != NULL);
+ g_assert (params != NULL);
+ g_assert (rpc_client != NULL);
+
+ IDE_TRACE_MSG ("Notification: %s", method);
+
+ /*
+ * To avoid leaking quarks we do not create a quark for the string unless
+ * it already exists. This should be fine in practice because we only need
+ * the quark if there is a caller that has registered for it. And the callers
+ * registering for it will necessarily create the quark.
+ */
+ detail = g_quark_try_string (method);
+
+ g_signal_emit (self, signals [NOTIFICATION], detail, method, params);
+
+ IDE_EXIT;
+}
+
+static void
ide_langserv_client_finalize (GObject *object)
{
IdeLangservClient *self = (IdeLangservClient *)object;
IdeLangservClientPrivate *priv = ide_langserv_client_get_instance_private (self);
+ g_clear_pointer (&priv->diagnostics_by_uri, g_hash_table_unref);
g_clear_object (&priv->rpc_client);
g_clear_object (&priv->buffer_manager_signals);
g_clear_object (&priv->project_signals);
@@ -269,6 +353,8 @@ ide_langserv_client_class_init (IdeLangservClientClass *klass)
object_class->get_property = ide_langserv_client_get_property;
object_class->set_property = ide_langserv_client_set_property;
+ klass->notification = ide_langserv_client_real_notification;
+
properties [PROP_IO_STREAM] =
g_param_spec_object ("io-stream",
"IO Stream",
@@ -277,6 +363,17 @@ ide_langserv_client_class_init (IdeLangservClientClass *klass)
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ signals [NOTIFICATION] =
+ g_signal_new ("notification",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (IdeLangservClientClass, notification),
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
+ JSON_TYPE_NODE);
}
static void
@@ -284,6 +381,11 @@ ide_langserv_client_init (IdeLangservClient *self)
{
IdeLangservClientPrivate *priv = ide_langserv_client_get_instance_private (self);
+ priv->diagnostics_by_uri = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)ide_diagnostics_unref);
+
priv->buffer_manager_signals = egg_signal_group_new (IDE_TYPE_BUFFER_MANAGER);
egg_signal_group_connect_object (priv->buffer_manager_signals,
@@ -323,24 +425,6 @@ ide_langserv_client_init (IdeLangservClient *self)
}
static void
-ide_langserv_client_notification (IdeLangservClient *self,
- const gchar *method,
- JsonNode *params,
- JsonrpcClient *rpc_client)
-{
- IDE_ENTRY;
-
- g_assert (IDE_IS_LANGSERV_CLIENT (self));
- g_assert (method != NULL);
- g_assert (params != NULL);
- g_assert (rpc_client != NULL);
-
- IDE_TRACE_MSG ("Notification: %s", method);
-
- IDE_EXIT;
-}
-
-static void
ide_langserv_client_initialize_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
@@ -456,3 +540,87 @@ ide_langserv_client_stop (IdeLangservClient *self)
IDE_EXIT;
}
+
+static void
+ide_langserv_client_call_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ JsonrpcClient *client = (JsonrpcClient *)object;
+ g_autoptr(JsonNode) return_value = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GTask) task = user_data;
+
+ IDE_ENTRY;
+
+ g_assert (JSONRPC_IS_CLIENT (client));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ if (!jsonrpc_client_call_finish (client, result, &return_value, &error))
+ {
+ g_task_return_error (task, error);
+ return;
+ }
+
+ g_task_return_pointer (task, g_steal_pointer (&return_value), (GDestroyNotify)json_node_unref);
+
+ IDE_EXIT;
+}
+
+void
+ide_langserv_client_call_async (IdeLangservClient *self,
+ const gchar *method,
+ JsonNode *params,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IdeLangservClientPrivate *priv = ide_langserv_client_get_instance_private (self);
+ g_autoptr(GTask) task = NULL;
+
+ IDE_ENTRY;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, ide_langserv_client_call_async);
+
+ if (priv->rpc_client == NULL)
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_CONNECTED,
+ "No connection to language server");
+ IDE_EXIT;
+ }
+
+ jsonrpc_client_call_async (priv->rpc_client,
+ method,
+ params,
+ cancellable,
+ ide_langserv_client_call_cb,
+ g_steal_pointer (&task));
+
+ IDE_EXIT;
+}
+
+gboolean
+ide_langserv_client_call_finish (IdeLangservClient *self,
+ GAsyncResult *result,
+ JsonNode **return_value,
+ GError **error)
+{
+ g_autoptr(JsonNode) local_return_value = NULL;
+ gboolean ret;
+
+ IDE_ENTRY;
+
+ g_return_val_if_fail (IDE_IS_LANGSERV_CLIENT (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ local_return_value = g_task_propagate_pointer (G_TASK (result), error);
+ ret = local_return_value != NULL;
+
+ if (return_value != NULL)
+ *return_value = g_steal_pointer (&local_return_value);
+
+ IDE_RETURN (ret);
+}
diff --git a/libide/langserv/ide-langserv-client.h b/libide/langserv/ide-langserv-client.h
index 98950b5..dac9a35 100644
--- a/libide/langserv/ide-langserv-client.h
+++ b/libide/langserv/ide-langserv-client.h
@@ -19,6 +19,8 @@
#ifndef IDE_LANGSERV_CLIENT_H
#define IDE_LANGSERV_CLIENT_H
+#include <json-glib/json-glib.h>
+
#include "ide-object.h"
G_BEGIN_DECLS
@@ -31,6 +33,10 @@ struct _IdeLangservClientClass
{
IdeObjectClass parent_class;
+ void (*notification) (IdeLangservClient *self,
+ const gchar *method,
+ JsonNode *params);
+
gpointer _reserved1;
gpointer _reserved2;
gpointer _reserved3;
@@ -41,10 +47,20 @@ struct _IdeLangservClientClass
gpointer _reserved8;
};
-IdeLangservClient *ide_langserv_client_new (IdeContext *context,
- GIOStream *io_stream);
-void ide_langserv_client_start (IdeLangservClient *self);
-void ide_langserv_client_stop (IdeLangservClient *self);
+IdeLangservClient *ide_langserv_client_new (IdeContext *context,
+ GIOStream *io_stream);
+void ide_langserv_client_start (IdeLangservClient *self);
+void ide_langserv_client_stop (IdeLangservClient *self);
+void ide_langserv_client_call_async (IdeLangservClient *self,
+ const gchar *method,
+ JsonNode *params,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_langserv_client_call_finish (IdeLangservClient *self,
+ GAsyncResult *result,
+ JsonNode **return_value,
+ GError **error);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]