[gnome-builder] LSP: add full text synchronization alternative for didChange signal
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] LSP: add full text synchronization alternative for didChange signal
- Date: Mon, 11 May 2020 23:41:48 +0000 (UTC)
commit 3381f396eb69ef48570cd20700a1affa63e6ce24
Author: Günther Wagner <info gunibert de>
Date: Sun Apr 26 11:52:39 2020 +0200
LSP: add full text synchronization alternative for didChange signal
meson_options.txt | 2 +-
src/libide/lsp/ide-lsp-client.c | 97 +++++++++++++++++------
src/plugins/rust-analyzer/rust_analyzer_plugin.py | 48 +++++------
3 files changed, 97 insertions(+), 50 deletions(-)
---
diff --git a/meson_options.txt b/meson_options.txt
index f187c821f..0a103b57e 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -64,7 +64,7 @@ option('plugin_python_pack', type: 'boolean')
option('plugin_qemu', type: 'boolean')
option('plugin_quick_highlight', type: 'boolean')
option('plugin_retab', type: 'boolean')
-option('plugin_rls', type: 'boolean', value: false)
+option('plugin_rls', type: 'boolean')
option('plugin_rust_analyzer', type: 'boolean')
option('plugin_rustup', type: 'boolean')
option('plugin_shellcmd', type: 'boolean')
diff --git a/src/libide/lsp/ide-lsp-client.c b/src/libide/lsp/ide-lsp-client.c
index 927a8ea05..fb4e85605 100644
--- a/src/libide/lsp/ide-lsp-client.c
+++ b/src/libide/lsp/ide-lsp-client.c
@@ -68,6 +68,12 @@ enum {
SEVERITY_HINT = 4,
};
+enum {
+ TEXT_DOCUMENT_SYNC_NONE,
+ TEXT_DOCUMENT_SYNC_FULL,
+ TEXT_DOCUMENT_SYNC_INCREMENTAL,
+};
+
enum {
PROP_0,
PROP_IO_STREAM,
@@ -208,10 +214,9 @@ ide_lsp_client_buffer_insert_text (IdeLspClient *self,
{
g_autoptr(GVariant) params = NULL;
g_autofree gchar *uri = NULL;
- g_autofree gchar *copy = NULL;
+ GVariant *capabilities = NULL;
gint64 version;
- gint line;
- gint column;
+ gint64 text_document_sync = TEXT_DOCUMENT_SYNC_NONE;
IDE_ENTRY;
@@ -220,37 +225,79 @@ ide_lsp_client_buffer_insert_text (IdeLspClient *self,
g_assert (location != NULL);
g_assert (IDE_IS_BUFFER (buffer));
- copy = g_strndup (new_text, len);
+ capabilities = ide_lsp_client_get_server_capabilities (self);
+ if (capabilities != NULL) {
+ gint64 tds = 0;
+
+ // for backwards compatibility reasons LS can stick to a number instead of the structure
+ if (JSONRPC_MESSAGE_PARSE (capabilities, "textDocumentSync", JSONRPC_MESSAGE_GET_INT64 (&tds))
+ | JSONRPC_MESSAGE_PARSE (capabilities, "textDocumentSync", "{", "change", JSONRPC_MESSAGE_GET_INT64
(&tds), "}"))
+ {
+ text_document_sync = tds;
+ }
+ }
uri = ide_buffer_dup_uri (buffer);
/* We get called before this change is registered */
version = (gint64)ide_buffer_get_change_count (buffer) + 1;
- line = gtk_text_iter_get_line (location);
- column = gtk_text_iter_get_line_offset (location);
+ if (text_document_sync == TEXT_DOCUMENT_SYNC_INCREMENTAL)
+ {
+ g_autofree gchar *copy = NULL;
+ gint line;
+ gint column;
- params = JSONRPC_MESSAGE_NEW (
- "textDocument", "{",
- "uri", JSONRPC_MESSAGE_PUT_STRING (uri),
- "version", JSONRPC_MESSAGE_PUT_INT64 (version),
- "}",
- "contentChanges", "[",
- "{",
- "range", "{",
- "start", "{",
- "line", JSONRPC_MESSAGE_PUT_INT64 (line),
- "character", JSONRPC_MESSAGE_PUT_INT64 (column),
- "}",
- "end", "{",
- "line", JSONRPC_MESSAGE_PUT_INT64 (line),
- "character", JSONRPC_MESSAGE_PUT_INT64 (column),
+ copy = g_strndup (new_text, len);
+
+ line = gtk_text_iter_get_line (location);
+ column = gtk_text_iter_get_line_offset (location);
+
+ params = JSONRPC_MESSAGE_NEW (
+ "textDocument", "{",
+ "uri", JSONRPC_MESSAGE_PUT_STRING (uri),
+ "version", JSONRPC_MESSAGE_PUT_INT64 (version),
+ "}",
+ "contentChanges", "[",
+ "{",
+ "range", "{",
+ "start", "{",
+ "line", JSONRPC_MESSAGE_PUT_INT64 (line),
+ "character", JSONRPC_MESSAGE_PUT_INT64 (column),
+ "}",
+ "end", "{",
+ "line", JSONRPC_MESSAGE_PUT_INT64 (line),
+ "character", JSONRPC_MESSAGE_PUT_INT64 (column),
+ "}",
+ "}",
+ "rangeLength", JSONRPC_MESSAGE_PUT_INT64 (0),
+ "text", JSONRPC_MESSAGE_PUT_STRING (copy),
"}",
+ "]");
+ }
+ else if (text_document_sync == TEXT_DOCUMENT_SYNC_FULL)
+ {
+ g_autoptr(GBytes) content = NULL;
+ const gchar *text;
+ g_autoptr(GString) str = NULL;
+
+ content = ide_buffer_dup_content (buffer);
+ text = (const gchar *)g_bytes_get_data (content, NULL);
+ str = g_string_new (text);
+ g_string_insert_len (str, gtk_text_iter_get_offset (location), new_text, len);
+
+ params = JSONRPC_MESSAGE_NEW (
+ "textDocument", "{",
+ "uri", JSONRPC_MESSAGE_PUT_STRING (uri),
+ "version", JSONRPC_MESSAGE_PUT_INT64 (version),
"}",
- "rangeLength", JSONRPC_MESSAGE_PUT_INT64 (0),
- "text", JSONRPC_MESSAGE_PUT_STRING (copy),
- "}",
- "]");
+ "contentChanges", "[",
+ "{",
+ "text", JSONRPC_MESSAGE_PUT_STRING (str->str),
+ "}",
+ "]");
+ }
+
ide_lsp_client_send_notification_async (self,
"textDocument/didChange",
diff --git a/src/plugins/rust-analyzer/rust_analyzer_plugin.py
b/src/plugins/rust-analyzer/rust_analyzer_plugin.py
index 93dff63e2..eeec191b1 100644
--- a/src/plugins/rust-analyzer/rust_analyzer_plugin.py
+++ b/src/plugins/rust-analyzer/rust_analyzer_plugin.py
@@ -33,7 +33,7 @@ from gi.repository import Ide
DEV_MODE = False
-class RlsService(Ide.Object):
+class RustAnalyzerService(Ide.Object):
_client = None
_has_started = False
_supervisor = None
@@ -41,7 +41,7 @@ class RlsService(Ide.Object):
@classmethod
def from_context(klass, context):
- return context.ensure_child_typed(RlsService)
+ return context.ensure_child_typed(RustAnalyzerService)
@GObject.Property(type=Ide.LspClient)
def client(self):
@@ -86,8 +86,8 @@ class RlsService(Ide.Object):
def do_stop(self):
"""
- Stops the Rust Language Server upon request to shutdown the
- RlsService.
+ Stops the Rust Analyzer Language Server upon request to shutdown the
+ RustAnalyzerService.
"""
if self._monitor is not None:
monitor, self._monitor = self._monitor, None
@@ -106,9 +106,9 @@ class RlsService(Ide.Object):
Ide.SubprocessSupervisor.
Various extension points (diagnostics, symbol providers, etc) use
- the RlsService to access the rust components they need.
+ the RustAnalyzerService to access the rust components they need.
"""
- # To avoid starting the `rust-analyzer-linux` process unconditionally at startup,
+ # To avoid starting the `rust-analyzer` process unconditionally at startup,
# we lazily start it when the first provider tries to bind a client
# to its :client property.
if not self._has_started:
@@ -130,7 +130,7 @@ class RlsService(Ide.Object):
# If rls was installed with Cargo, try to discover that
# to save the user having to update PATH.
- path_to_rust_analyzer_bin = os.path.expanduser("~/.cargo/bin/rust-analyzer-linux")
+ path_to_rust_analyzer_bin = os.path.expanduser("~/.cargo/bin/rust-analyzer")
if os.path.exists(path_to_rust_analyzer_bin):
old_path = os.getenv('PATH')
new_path = os.path.expanduser('~/.cargo/bin')
@@ -138,11 +138,11 @@ class RlsService(Ide.Object):
new_path += os.path.pathsep + old_path
launcher.setenv('PATH', new_path, True)
else:
- path_to_rls = "rust-analyzer-linux"
+ path_to_rust_analyzer_bin = "rust-analyzer"
# Setup our Argv. We want to communicate over STDIN/STDOUT,
# so it does not require any command line options.
- launcher.push_argv(path_to_rls)
+ launcher.push_argv(path_to_rust_analyzer_bin)
# Spawn our peer process and monitor it for
# crashes. We may need to restart it occasionally.
@@ -214,41 +214,41 @@ class RlsService(Ide.Object):
our `rls` process has crashed.
"""
context = provider.get_context()
- self = RlsService.from_context(context)
+ self = RustAnalyzerService.from_context(context)
self._ensure_started()
self.bind_property('client', provider, 'client', GObject.BindingFlags.SYNC_CREATE)
-class RlsDiagnosticProvider(Ide.LspDiagnosticProvider, Ide.DiagnosticProvider):
+class RustAnalyzerDiagnosticProvider(Ide.LspDiagnosticProvider, Ide.DiagnosticProvider):
def do_load(self):
- RlsService.bind_client(self)
+ RustAnalyzerService.bind_client(self)
-class RlsCompletionProvider(Ide.LspCompletionProvider, Ide.CompletionProvider):
+class RustAnalyzerCompletionProvider(Ide.LspCompletionProvider, Ide.CompletionProvider):
def do_load(self, context):
- RlsService.bind_client(self)
+ RustAnalyzerService.bind_client(self)
def do_get_priority(self, context):
# This provider only activates when it is very likely that we
# want the results. So use high priority (negative is better).
return -1000
-class RlsRenameProvider(Ide.LspRenameProvider, Ide.RenameProvider):
+class RustAnalyzerRenameProvider(Ide.LspRenameProvider, Ide.RenameProvider):
def do_load(self):
- RlsService.bind_client(self)
+ RustAnalyzerService.bind_client(self)
-class RlsSymbolResolver(Ide.LspSymbolResolver, Ide.SymbolResolver):
+class RustAnalyzerSymbolResolver(Ide.LspSymbolResolver, Ide.SymbolResolver):
def do_load(self):
- RlsService.bind_client(self)
+ RustAnalyzerService.bind_client(self)
-class RlsHighlighter(Ide.LspHighlighter, Ide.Highlighter):
+class RustAnalyzerHighlighter(Ide.LspHighlighter, Ide.Highlighter):
def do_load(self):
- RlsService.bind_client(self)
+ RustAnalyzerService.bind_client(self)
-class RlsFormatter(Ide.LspFormatter, Ide.Formatter):
+class RustAnalyzerFormatter(Ide.LspFormatter, Ide.Formatter):
def do_load(self):
- RlsService.bind_client(self)
+ RustAnalyzerService.bind_client(self)
-class RlsHoverProvider(Ide.LspHoverProvider, Ide.HoverProvider):
+class RustAnalyzerHoverProvider(Ide.LspHoverProvider, Ide.HoverProvider):
def do_prepare(self):
self.props.category = 'Rust'
self.props.priority = 200
- RlsService.bind_client(self)
+ RustAnalyzerService.bind_client(self)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]