feat: migrate LSP to opt-in native language servers
This commit is contained in:
+55
-3
@@ -5,7 +5,8 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
editor::{Editor, Effect, Input, Invocation},
|
||||
editor::{Cursor, Editor, Effect, Input, Invocation, Mode},
|
||||
lsp::Lsp,
|
||||
plugin::{
|
||||
DocumentEvent, DocumentEventKind, DocumentSnapshot, PluginEvent, PluginUpdate,
|
||||
TextPosition, UpdateEffect,
|
||||
@@ -37,6 +38,9 @@ pub struct EditorSession {
|
||||
plugins: BTreeMap<String, RubyPlugin>,
|
||||
documents: BTreeMap<usize, TrackedDocument>,
|
||||
requests: BTreeMap<String, AsyncRequests>,
|
||||
lsp: Lsp,
|
||||
lsp_request_id: u64,
|
||||
lsp_source_cursor: Option<Cursor>,
|
||||
}
|
||||
|
||||
impl EditorSession {
|
||||
@@ -117,6 +121,9 @@ impl EditorSession {
|
||||
plugins,
|
||||
documents: BTreeMap::new(),
|
||||
requests: BTreeMap::new(),
|
||||
lsp: Lsp::new(config.lsp),
|
||||
lsp_request_id: 0,
|
||||
lsp_source_cursor: None,
|
||||
};
|
||||
session.synchronize_documents();
|
||||
Ok(session)
|
||||
@@ -145,6 +152,31 @@ impl EditorSession {
|
||||
}
|
||||
|
||||
fn dispatch(&mut self, invocation: Invocation) {
|
||||
if invocation.plugin == "core" {
|
||||
let result = match invocation.command.as_str() {
|
||||
"lsp_definition" => {
|
||||
if let Some(id) = self.lsp_request_id.checked_add(1) {
|
||||
self.lsp_request_id = id;
|
||||
let context = self.editor.context();
|
||||
let source = InvocationSource {
|
||||
buffer_id: context.buffer_id,
|
||||
revision: context.revision,
|
||||
};
|
||||
self.requests.entry("core".into()).or_default().latest = Some((id, source));
|
||||
self.lsp_source_cursor = Some(self.editor.cursor());
|
||||
self.lsp.definition(&context, id)
|
||||
} else {
|
||||
Err("LSP request IDs exhausted".into())
|
||||
}
|
||||
}
|
||||
"lsp_diagnostics" => self.lsp.diagnostics(self.editor.buffer_id()),
|
||||
_ => unreachable!("session-dispatched core command"),
|
||||
};
|
||||
if let Err(error) = result {
|
||||
self.editor.set_message(format!("LSP: {error}"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
let context = self.editor.context();
|
||||
let result = match self.plugins.get_mut(&invocation.plugin) {
|
||||
Some(plugin) if plugin.is_async() => {
|
||||
@@ -178,7 +210,7 @@ impl EditorSession {
|
||||
}
|
||||
|
||||
fn synchronize_documents(&mut self) -> bool {
|
||||
if !self.plugins.values().any(RubyPlugin::is_async) {
|
||||
if !self.lsp.is_enabled() && !self.plugins.values().any(RubyPlugin::is_async) {
|
||||
self.documents.clear();
|
||||
return false;
|
||||
}
|
||||
@@ -250,6 +282,13 @@ impl EditorSession {
|
||||
});
|
||||
}
|
||||
let mut failures = Vec::new();
|
||||
let mut changed = false;
|
||||
for event in &events {
|
||||
if let Err(error) = self.lsp.notify_document(event) {
|
||||
self.editor.set_message(format!("LSP: {error}"));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
for (owner, plugin) in &mut self.plugins {
|
||||
if !plugin.is_async() {
|
||||
continue;
|
||||
@@ -261,7 +300,7 @@ impl EditorSession {
|
||||
}
|
||||
}
|
||||
}
|
||||
let changed = !failures.is_empty();
|
||||
changed |= !failures.is_empty();
|
||||
for (owner, error) in failures {
|
||||
self.retire(&owner, &error);
|
||||
}
|
||||
@@ -282,6 +321,9 @@ impl EditorSession {
|
||||
) -> bool {
|
||||
self.editor.buffer_id() == source.buffer_id
|
||||
&& self.source_is_current(source)
|
||||
&& (owner != "core"
|
||||
|| (self.lsp_source_cursor == Some(self.editor.cursor())
|
||||
&& self.editor.mode() == Mode::Normal))
|
||||
&& self
|
||||
.requests
|
||||
.get(owner)
|
||||
@@ -406,6 +448,16 @@ impl EditorSession {
|
||||
/// Drains ready plugin work without waiting for command or server responses.
|
||||
pub fn poll(&mut self) -> bool {
|
||||
let mut changed = self.synchronize_documents();
|
||||
for update in self.lsp.poll() {
|
||||
match self.apply_update("core", update) {
|
||||
Ok(applied) => changed |= applied,
|
||||
Err(error) => {
|
||||
self.editor.clear_plugin_diagnostics("core");
|
||||
self.editor.set_message(format!("LSP: {error}"));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut ready = Vec::new();
|
||||
for (owner, plugin) in &mut self.plugins {
|
||||
if plugin.is_async() {
|
||||
|
||||
Reference in New Issue
Block a user