Commit 3381f396 authored by Günther Wagner's avatar Günther Wagner Committed by Christian Hergert

LSP: add full text synchronization alternative for didChange signal

parent 8d605491
......@@ -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')
......
......@@ -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",
......
......@@ -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)
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