Commit 50e7a913 authored by Günther Wagner's avatar Günther Wagner

add rename provider and enhance lsp implementation

parent 547c915a
Pipeline #182093 failed with stage
in 60 minutes and 1 second
......@@ -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;
......
......@@ -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);
......
......@@ -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',
])
......
/* 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;
}
/* 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
......@@ -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);
}
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment