[gnome-builder: 9/17] add rename provider and enhance lsp implementation



commit 50e7a9131365b60d130ce2ff66f345012a3c3abb
Author: Günther Wagner <info gunibert de>
Date:   Sun May 24 12:35:54 2020 +0200

    add rename provider and enhance lsp implementation

 src/libide/lsp/ide-lsp-rename-provider.c           | 181 ++++++++++++++-------
 src/libide/sourceview/ide-source-view.c            |  27 +++
 src/plugins/rust-analyzer/meson.build              |   1 +
 .../rust-analyzer/rust-analyzer-rename-provider.c  |  65 ++++++++
 .../rust-analyzer/rust-analyzer-rename-provider.h  |  31 ++++
 src/plugins/rust-analyzer/rust-analyzer.c          |   4 +
 src/plugins/rust-analyzer/rust-analyzer.plugin     |   2 +-
 7 files changed, 254 insertions(+), 57 deletions(-)
---
diff --git a/src/libide/lsp/ide-lsp-rename-provider.c b/src/libide/lsp/ide-lsp-rename-provider.c
index 123d2e1a1..bdae4de7b 100644
--- a/src/libide/lsp/ide-lsp-rename-provider.c
+++ b/src/libide/lsp/ide-lsp-rename-provider.c
@@ -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;
diff --git a/src/libide/sourceview/ide-source-view.c b/src/libide/sourceview/ide-source-view.c
index 90b4ac3b9..e27dafcff 100644
--- a/src/libide/sourceview/ide-source-view.c
+++ b/src/libide/sourceview/ide-source-view.c
@@ -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);
diff --git a/src/plugins/rust-analyzer/meson.build b/src/plugins/rust-analyzer/meson.build
index aa755b504..1d153a2df 100644
--- a/src/plugins/rust-analyzer/meson.build
+++ b/src/plugins/rust-analyzer/meson.build
@@ -9,6 +9,7 @@ plugins_sources += files([
   'rust-analyzer-formatter.c',
   'rust-analyzer-highlighter.c',
   'rust-analyzer-hover-provider.c',
+  'rust-analyzer-rename-provider.c',
   'rust-analyzer-transfer.c',
   'rust-analyzer-workbench-addin.c',
 ])
diff --git a/src/plugins/rust-analyzer/rust-analyzer-rename-provider.c 
b/src/plugins/rust-analyzer/rust-analyzer-rename-provider.c
new file mode 100644
index 000000000..7e8bb875e
--- /dev/null
+++ b/src/plugins/rust-analyzer/rust-analyzer-rename-provider.c
@@ -0,0 +1,65 @@
+/* rust-analyzer-rename-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
+ */
+
+#include "rust-analyzer-rename-provider.h"
+#include "rust-analyzer-service.h"
+
+struct _RustAnalyzerRenameProvider
+{
+  IdeLspRenameProvider parent_instance;
+};
+
+static void provider_iface_init (IdeRenameProviderInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (RustAnalyzerRenameProvider,
+                         rust_analyzer_rename_provider,
+                         IDE_TYPE_LSP_RENAME_PROVIDER,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_RENAME_PROVIDER, provider_iface_init))
+
+static void
+rust_analyzer_rename_provider_class_init (RustAnalyzerRenameProviderClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+}
+
+static void
+rust_analyzer_rename_provider_init (RustAnalyzerRenameProvider *self)
+{
+}
+
+static void
+rust_analyzer_rename_provider_load (IdeRenameProvider *self)
+{
+  IdeContext *context = NULL;
+  RustAnalyzerService *service = NULL;
+
+  g_assert (RUST_IS_ANALYZER_RENAME_PROVIDER (self));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  service = ide_object_ensure_child_typed (IDE_OBJECT (context), RUST_TYPE_ANALYZER_SERVICE);
+  rust_analyzer_service_ensure_started (service);
+  g_object_bind_property (service, "client", self, "client", G_BINDING_SYNC_CREATE);
+}
+
+static void
+provider_iface_init (IdeRenameProviderInterface *iface)
+{
+  iface->load = rust_analyzer_rename_provider_load;
+}
diff --git a/src/plugins/rust-analyzer/rust-analyzer-rename-provider.h 
b/src/plugins/rust-analyzer/rust-analyzer-rename-provider.h
new file mode 100644
index 000000000..9605bdeed
--- /dev/null
+++ b/src/plugins/rust-analyzer/rust-analyzer-rename-provider.h
@@ -0,0 +1,31 @@
+/* rust-analyzer-rename-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_RENAME_PROVIDER (rust_analyzer_rename_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (RustAnalyzerRenameProvider, rust_analyzer_rename_provider, RUST, 
ANALYZER_RENAME_PROVIDER, IdeLspRenameProvider)
+
+G_END_DECLS
diff --git a/src/plugins/rust-analyzer/rust-analyzer.c b/src/plugins/rust-analyzer/rust-analyzer.c
index 21948d834..f8d5d0062 100644
--- a/src/plugins/rust-analyzer/rust-analyzer.c
+++ b/src/plugins/rust-analyzer/rust-analyzer.c
@@ -28,6 +28,7 @@
 #include "rust-analyzer-highlighter.h"
 #include "rust-analyzer-hover-provider.h"
 #include "rust-analyzer-workbench-addin.h"
+#include "rust-analyzer-rename-provider.h"
 
 _IDE_EXTERN void
 _rust_analyzer_register_types (PeasObjectModule *module)
@@ -53,4 +54,7 @@ _rust_analyzer_register_types (PeasObjectModule *module)
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_HOVER_PROVIDER,
                                               RUST_TYPE_ANALYZER_HOVER_PROVIDER);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_RENAME_PROVIDER,
+                                              RUST_TYPE_ANALYZER_RENAME_PROVIDER);
 }
diff --git a/src/plugins/rust-analyzer/rust-analyzer.plugin b/src/plugins/rust-analyzer/rust-analyzer.plugin
index 42f80d458..53e86e0c7 100644
--- a/src/plugins/rust-analyzer/rust-analyzer.plugin
+++ b/src/plugins/rust-analyzer/rust-analyzer.plugin
@@ -12,4 +12,4 @@ X-Symbol-Resolver-Languages=rust
 X-Formatter-Languages=rust
 X-Highlighter-Languages=rust
 X-Hover-Provider-Languages=rust
-#X-Rename-Provider-Languages=rust
+X-Rename-Provider-Languages=rust


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