[gnome-builder] lsp: implement workspace edit



commit dacd799593855d3d0b895cab2826142c98d12d33
Author: Georg Vienna <georg vienna himbarsoft com>
Date:   Thu Nov 11 15:06:12 2021 +0100

    lsp: implement workspace edit

 src/libide/lsp/ide-lsp-client.c          |  68 +------------
 src/libide/lsp/ide-lsp-rename-provider.c |  90 ++---------------
 src/libide/lsp/ide-lsp-workspace-edit.c  | 163 +++++++++++++++++++++++++++++++
 src/libide/lsp/ide-lsp-workspace-edit.h  |  42 ++++++++
 src/libide/lsp/libide-lsp.h              |   1 +
 src/libide/lsp/meson.build               |   2 +
 6 files changed, 218 insertions(+), 148 deletions(-)
---
diff --git a/src/libide/lsp/ide-lsp-client.c b/src/libide/lsp/ide-lsp-client.c
index 0e72fe720..bb09923e1 100644
--- a/src/libide/lsp/ide-lsp-client.c
+++ b/src/libide/lsp/ide-lsp-client.c
@@ -34,6 +34,7 @@
 
 #include "ide-lsp-client.h"
 #include "ide-lsp-enums.h"
+#include "ide-lsp-workspace-edit.h"
 
 typedef struct
 {
@@ -968,7 +969,7 @@ ide_lsp_client_handle_apply_edit (IdeLspClient  *self,
                                   GVariant      *params)
 {
   g_autoptr(GVariant) parent = NULL;
-  g_autoptr(GVariant) changes = NULL;
+  g_autoptr(IdeLspWorkspaceEdit) workspace_edit = NULL;
   g_autoptr(GPtrArray) edits = NULL;
 
   IDE_ENTRY;
@@ -983,69 +984,8 @@ ide_lsp_client_handle_apply_edit (IdeLspClient  *self,
 
   edits = g_ptr_array_new_with_free_func (g_object_unref);
 
-#if 0
-  /* We'd prefer to support this, but do not currently */
-  if (JSONRPC_MESSAGE_PARSE (edit, "documentChanges", JSONRPC_MESSAGE_GET_VARIANT (&changes)))
-    {
-    }
-#endif
-
-  if (JSONRPC_MESSAGE_PARSE (parent, "changes", JSONRPC_MESSAGE_GET_VARIANT (&changes)))
-    {
-      if (g_variant_is_of_type (changes, G_VARIANT_TYPE_VARDICT))
-        {
-          GVariantIter iter;
-          GVariant *value;
-          gchar *uri;
-
-          g_variant_iter_init (&iter, changes);
-          while (g_variant_iter_loop (&iter, "{sv}", &uri, &value))
-            {
-              GVariantIter edit_iter;
-              GVariant *item;
-              struct {
-                gint64 line;
-                gint64 column;
-              } begin, end;
-
-              g_variant_iter_init (&edit_iter, value);
-              while (g_variant_iter_loop (&edit_iter, "v", &item))
-                {
-                  const gchar *new_text = NULL;
-                  gboolean r;
-
-                  r = JSONRPC_MESSAGE_PARSE (item,
-                    "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 (r)
-                    {
-                      g_autoptr(IdeLocation) begin_loc = NULL;
-                      g_autoptr(IdeLocation) end_loc = NULL;
-                      g_autoptr(IdeRange) range = NULL;
-                      g_autoptr(GFile) file = NULL;
-
-                      file = g_file_new_for_uri (uri);
-                      begin_loc = ide_location_new (file, begin.line, begin.column);
-                      end_loc = ide_location_new (file, end.line, end.column);
-                      range = ide_range_new (begin_loc, end_loc);
-
-                      g_ptr_array_add (edits, ide_text_edit_new (range, new_text));
-                    }
-                }
-            }
-        }
-    }
+  workspace_edit = ide_lsp_workspace_edit_new(parent);
+  edits = ide_lsp_workspace_edit_get_edits(workspace_edit);
 
   if (edits->len > 0)
     {
diff --git a/src/libide/lsp/ide-lsp-rename-provider.c b/src/libide/lsp/ide-lsp-rename-provider.c
index 6f9cc65b0..389001954 100644
--- a/src/libide/lsp/ide-lsp-rename-provider.c
+++ b/src/libide/lsp/ide-lsp-rename-provider.c
@@ -29,6 +29,7 @@
 #include "ide-lsp-client.h"
 #include "ide-lsp-rename-provider.h"
 #include "ide-lsp-util.h"
+#include "ide-lsp-workspace-edit.h"
 
 typedef struct
 {
@@ -145,84 +146,6 @@ ide_lsp_rename_provider_init (IdeLspRenameProvider *self)
 {
 }
 
-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 = ide_lsp_decode_text_edit (change, gfile);
-          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 = ide_lsp_decode_text_edit (edit, gfile);
-          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,
@@ -232,7 +155,8 @@ ide_lsp_rename_provider_rename_cb (GObject      *object,
   g_autoptr(GVariant) return_value = NULL;
   g_autoptr(GError) error = NULL;
   g_autoptr(IdeTask) task = user_data;
-  g_autoptr(GVariantDict) dict = NULL;
+  g_autoptr(IdeLspWorkspaceEdit) workspace_edit = NULL;
+  g_autoptr(GPtrArray) ret = NULL;
 
   IDE_ENTRY;
 
@@ -246,11 +170,9 @@ ide_lsp_rename_provider_rename_cb (GObject      *object,
       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);
+  workspace_edit = ide_lsp_workspace_edit_new(return_value);
+  ret = ide_lsp_workspace_edit_get_edits(workspace_edit);
+  ide_task_return_pointer (task, g_steal_pointer (&ret), g_ptr_array_unref);
 
   IDE_EXIT;
 }
diff --git a/src/libide/lsp/ide-lsp-workspace-edit.c b/src/libide/lsp/ide-lsp-workspace-edit.c
new file mode 100644
index 000000000..66cc274d8
--- /dev/null
+++ b/src/libide/lsp/ide-lsp-workspace-edit.c
@@ -0,0 +1,163 @@
+/* ide-lsp-workspace-edit.c
+ *
+ * Copyright 2021 Georg Vienna <georg vienna himbarsoft com>
+ *
+ * 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 "ide-lsp-workspace-edit"
+
+#include "config.h"
+
+#include <jsonrpc-glib.h>
+
+#include "ide-lsp-workspace-edit.h"
+#include "ide-lsp-util.h"
+
+struct _IdeLspWorkspaceEdit
+{
+  GObject parent_instance;
+
+  GVariant* variant;
+};
+
+G_DEFINE_FINAL_TYPE (IdeLspWorkspaceEdit, ide_lsp_workspace_edit, G_TYPE_OBJECT)
+
+static void
+ide_lsp_workspace_edit_finalize (GObject *object)
+{
+  IdeLspWorkspaceEdit *self = (IdeLspWorkspaceEdit *)object;
+
+  g_clear_pointer (&self->variant, g_variant_unref);
+
+  G_OBJECT_CLASS (ide_lsp_workspace_edit_parent_class)->finalize (object);
+}
+
+static void
+ide_lsp_workspace_edit_class_init (IdeLspWorkspaceEditClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ide_lsp_workspace_edit_finalize;
+}
+
+static void
+ide_lsp_workspace_edit_init (IdeLspWorkspaceEdit *self)
+{
+}
+
+IdeLspWorkspaceEdit *
+ide_lsp_workspace_edit_new (GVariant *variant)
+{
+  IdeLspWorkspaceEdit *self;
+
+  g_return_val_if_fail (variant != NULL, NULL);
+
+  self = g_object_new (IDE_TYPE_LSP_WORKSPACE_EDIT, NULL);
+  self->variant = g_variant_ref (variant);
+
+  return self;
+}
+
+/**
+ * ide_lsp_workspace_edit_get_edits:
+ *
+ * Returns the list of text edits that this workspace edit contains.
+ *
+ * Returns: (element-type IdeTextEdit) (transfer full): a #GPtrArray of #IdeTextEdit.
+ *
+ */
+GPtrArray *
+ide_lsp_workspace_edit_get_edits(IdeLspWorkspaceEdit *self)
+{
+  g_autoptr(GVariant) changes = NULL;
+  g_autoptr(GPtrArray) edits = NULL;
+
+  IDE_ENTRY;
+  g_return_val_if_fail(IDE_IS_LSP_WORKSPACE_EDIT(self), NULL);
+
+  edits = g_ptr_array_new_with_free_func(g_object_unref);
+
+  if (JSONRPC_MESSAGE_PARSE(self->variant, "documentChanges", JSONRPC_MESSAGE_GET_VARIANT(&changes)))
+    {
+      if (g_variant_is_of_type(changes, G_VARIANT_TYPE_ARRAY))
+        {
+          GVariantIter iter;
+          g_autoptr(GVariant) text_document_edit = NULL;
+          const gchar *uri = NULL;
+
+          g_variant_iter_init(&iter, changes);
+          while (g_variant_iter_loop(&iter, "v", &text_document_edit))
+            {
+              g_autoptr(GVariant) text_edits = NULL;
+
+              if (JSONRPC_MESSAGE_PARSE(text_document_edit,
+                                        "textDocument", "{",
+                                          "uri", JSONRPC_MESSAGE_GET_STRING(&uri),
+                                        "}",
+                                        "edits", JSONRPC_MESSAGE_GET_VARIANT(&text_edits)
+                                        ))
+                {
+                  g_autoptr(GFile) gfile = NULL;
+                  GVariantIter text_edit_iter;
+                  g_autoptr(GVariant) item = NULL;
+
+                  gfile = g_file_new_for_uri(uri);
+                  g_variant_iter_init(&text_edit_iter, text_edits);
+                  while (g_variant_iter_loop(&text_edit_iter, "v", &item))
+                    {
+                      IdeTextEdit* edit = ide_lsp_decode_text_edit(item, gfile);
+                      if (edit)
+                        {
+                          g_ptr_array_add(edits, edit);
+                        }
+                    }
+                }
+            }
+        }
+    }
+  else if (JSONRPC_MESSAGE_PARSE(self->variant, "changes", JSONRPC_MESSAGE_GET_VARIANT(&changes)))
+    {
+      if (g_variant_is_of_type(changes, G_VARIANT_TYPE_VARDICT))
+        {
+          GVariantIter iter;
+          g_autoptr(GVariant) value = NULL;
+          gchar *uri;
+
+          g_variant_iter_init(&iter, changes);
+          while (g_variant_iter_loop(&iter, "{sv}", &uri, &value))
+            {
+              g_autoptr(GFile) gfile = NULL;
+              GVariantIter edit_iter;
+              g_autoptr(GVariant) item = NULL;
+
+              gfile = g_file_new_for_uri(uri);
+              g_variant_iter_init(&edit_iter, value);
+              while (g_variant_iter_loop(&edit_iter, "v", &item))
+                {
+                  IdeTextEdit* edit = ide_lsp_decode_text_edit(item, gfile);
+                  if (edit)
+                    {
+                      g_ptr_array_add(edits, edit);
+                    }
+                }
+            }
+        }
+    }
+
+  IDE_RETURN(IDE_PTR_ARRAY_STEAL_FULL(&edits));
+}
+
diff --git a/src/libide/lsp/ide-lsp-workspace-edit.h b/src/libide/lsp/ide-lsp-workspace-edit.h
new file mode 100644
index 000000000..370de42dd
--- /dev/null
+++ b/src/libide/lsp/ide-lsp-workspace-edit.h
@@ -0,0 +1,42 @@
+/* ide-lsp-workspace-edit.h
+ *
+ * Copyright 2021 Georg Vienna <georg vienna himbarsoft com>
+ *
+ * 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
+
+#if !defined (IDE_LSP_INSIDE) && !defined (IDE_LSP_COMPILATION)
+# error "Only <libide-lsp.h> can be included directly."
+#endif
+
+#include <libide-code.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_LSP_WORKSPACE_EDIT (ide_lsp_workspace_edit_get_type())
+
+IDE_AVAILABLE_IN_42
+G_DECLARE_FINAL_TYPE(IdeLspWorkspaceEdit, ide_lsp_workspace_edit, IDE, LSP_WORKSPACE_EDIT, GObject)
+
+IDE_AVAILABLE_IN_42
+IdeLspWorkspaceEdit *ide_lsp_workspace_edit_new      (GVariant * variant);
+
+IDE_AVAILABLE_IN_42
+GPtrArray*           ide_lsp_workspace_edit_get_edits(IdeLspWorkspaceEdit *self);
+
+G_END_DECLS
diff --git a/src/libide/lsp/libide-lsp.h b/src/libide/lsp/libide-lsp.h
index a0eccb0cc..5f08b2410 100644
--- a/src/libide/lsp/libide-lsp.h
+++ b/src/libide/lsp/libide-lsp.h
@@ -41,5 +41,6 @@
 #include "ide-lsp-symbol-resolver.h"
 #include "ide-lsp-symbol-tree.h"
 #include "ide-lsp-util.h"
+#include "ide-lsp-workspace-edit.h"
 
 #undef IDE_LSP_INSIDE
diff --git a/src/libide/lsp/meson.build b/src/libide/lsp/meson.build
index 786e5eb04..f365940d8 100644
--- a/src/libide/lsp/meson.build
+++ b/src/libide/lsp/meson.build
@@ -22,6 +22,7 @@ libide_lsp_public_headers = [
   'ide-lsp-symbol-resolver.h',
   'ide-lsp-symbol-tree.h',
   'ide-lsp-types.h',
+  'ide-lsp-workspace-edit.h',
 ]
 
 libide_lsp_private_headers = [
@@ -51,6 +52,7 @@ libide_lsp_public_sources = [
   'ide-lsp-symbol-node.c',
   'ide-lsp-symbol-resolver.c',
   'ide-lsp-symbol-tree.c',
+  'ide-lsp-workspace-edit.c',
 ]
 
 libide_lsp_private_sources = [


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]