aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2020-12-25 08:20:09 +0000
committerBlaž Hrastnik2020-12-25 08:20:09 +0000
commit2ab069bb3fc815394cccca50378b62932f3146f5 (patch)
treeac0b3d13198d0a9c5b49a11d3c1f2555a30418b7
parentcd16df19c1f951e1ef0c560ae5e084b18bd2c713 (diff)
lsp: Work on syncing the state with the language server.
-rw-r--r--Cargo.lock3
-rw-r--r--helix-lsp/Cargo.toml1
-rw-r--r--helix-lsp/src/client.rs67
-rw-r--r--helix-term/src/application.rs16
-rw-r--r--helix-term/src/commands.rs6
-rw-r--r--helix-term/src/ui/editor.rs3
-rw-r--r--helix-view/Cargo.toml2
-rw-r--r--helix-view/src/document.rs29
8 files changed, 92 insertions, 35 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 33b7002a..820a77ad 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -553,7 +553,6 @@ dependencies = [
"futures-util",
"glob",
"helix-core",
- "helix-view",
"jsonrpc-core",
"log",
"lsp-types",
@@ -604,7 +603,9 @@ version = "0.1.0"
dependencies = [
"anyhow",
"crossterm",
+ "futures-util",
"helix-core",
+ "helix-lsp",
"once_cell",
"smol",
"tui",
diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml
index d22d8636..70cf9c64 100644
--- a/helix-lsp/Cargo.toml
+++ b/helix-lsp/Cargo.toml
@@ -8,7 +8,6 @@ edition = "2018"
[dependencies]
helix-core = { path = "../helix-core" }
-helix-view = { path = "../helix-view" }
once_cell = "1.4"
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index c3bcddd2..7349792a 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -5,8 +5,7 @@ use crate::{
type Result<T> = core::result::Result<T, Error>;
-use helix_core::{ChangeSet, Transaction};
-use helix_view::Document;
+use helix_core::{ChangeSet, Rope, Transaction};
// use std::collections::HashMap;
use std::sync::atomic::{AtomicU64, Ordering};
@@ -23,10 +22,6 @@ use smol::{
Executor,
};
-fn text_document_identifier(doc: &Document) -> lsp::TextDocumentIdentifier {
- lsp::TextDocumentIdentifier::new(lsp::Url::from_file_path(doc.path().unwrap()).unwrap())
-}
-
pub struct Client {
_process: Child,
stderr: BufReader<ChildStderr>,
@@ -232,13 +227,18 @@ impl Client {
// Text document
// -------------------------------------------------------------------------------------------
- pub async fn text_document_did_open(&self, doc: &Document) -> Result<()> {
+ pub async fn text_document_did_open(
+ &self,
+ uri: lsp::Url,
+ version: i32,
+ doc: &Rope,
+ ) -> Result<()> {
self.notify::<lsp::notification::DidOpenTextDocument>(lsp::DidOpenTextDocumentParams {
text_document: lsp::TextDocumentItem {
- uri: lsp::Url::from_file_path(doc.path().unwrap()).unwrap(),
+ uri,
language_id: "rust".to_string(), // TODO: hardcoded for now
- version: doc.version,
- text: String::from(doc.text()),
+ version,
+ text: String::from(doc),
},
})
.await
@@ -290,6 +290,21 @@ impl Client {
};
}
Insert(s) => {
+ // TODO:
+ // thread 'main' panicked at 'Attempt to index past end of slice: char index 1211, slice char length 0', /home/speed/.cargo/registry/src/github.com-1ecc6299db9ec823/ropey-1.2.0/src/slice.rs:301:9
+ // stack backtrace:
+ // 0: rust_begin_unwind
+ // at /rustc/b32e6e6ac8921035177256ab6806e6ab0d4b9b94/library/std/src/panicking.rs:493:5
+ // 1: std::panicking::begin_panic_fmt
+ // at /rustc/b32e6e6ac8921035177256ab6806e6ab0d4b9b94/library/std/src/panicking.rs:435:5
+ // 2: ropey::slice::RopeSlice::char_to_line
+ // at /home/speed/.cargo/registry/src/github.com-1ecc6299db9ec823/ropey-1.2.0/src/slice.rs:301:9
+ // 3: helix_lsp::util::pos_to_lsp_pos
+ // at /home/speed/src/helix/helix-lsp/src/lib.rs:39:20
+ // 4: helix_lsp::client::Client::to_changes
+ // at /home/speed/src/helix/helix-lsp/src/client.rs:293:33
+ // 5: helix_lsp::client::Client::text_document_did_change::{{closure}}
+ // at /home/speed/src/helix/helix-lsp/src/client.rs:338:55
let start = pos_to_lsp_pos(&old_text, old_pos);
// insert
@@ -309,8 +324,8 @@ impl Client {
// TODO: trigger any time history.commit_revision happens
pub async fn text_document_did_change(
&self,
- doc: &Document,
- transaction: &Transaction,
+ text_document: lsp::VersionedTextDocumentIdentifier,
+ changes: &ChangeSet,
) -> Result<()> {
// figure out what kind of sync the server supports
@@ -335,16 +350,12 @@ impl Client {
text: "".to_string(),
}] // TODO: probably need old_state here too?
}
- lsp::TextDocumentSyncKind::Incremental => Self::to_changes(transaction.changes()),
+ lsp::TextDocumentSyncKind::Incremental => Self::to_changes(changes),
lsp::TextDocumentSyncKind::None => return Ok(()),
};
self.notify::<lsp::notification::DidChangeTextDocument>(lsp::DidChangeTextDocumentParams {
- text_document: lsp::VersionedTextDocumentIdentifier::new(
- // TODO: doc.into() Url
- lsp::Url::from_file_path(doc.path().unwrap()).unwrap(),
- doc.version,
- ),
+ text_document,
content_changes: changes,
})
.await
@@ -352,9 +363,12 @@ impl Client {
// TODO: impl into() TextDocumentIdentifier / VersionedTextDocumentIdentifier for Document.
- pub async fn text_document_did_close(&self, doc: &Document) -> Result<()> {
+ pub async fn text_document_did_close(
+ &self,
+ text_document: lsp::TextDocumentIdentifier,
+ ) -> Result<()> {
self.notify::<lsp::notification::DidCloseTextDocument>(lsp::DidCloseTextDocumentParams {
- text_document: text_document_identifier(doc),
+ text_document,
})
.await
}
@@ -365,16 +379,17 @@ impl Client {
unimplemented!()
}
- pub async fn completion(&self, doc: &Document) -> anyhow::Result<Vec<lsp::CompletionItem>> {
+ pub async fn completion(
+ &self,
+ text_document: lsp::TextDocumentIdentifier,
+ position: lsp::Position,
+ ) -> anyhow::Result<Vec<lsp::CompletionItem>> {
// TODO: figure out what should happen when you complete with multiple cursors
let params = lsp::CompletionParams {
text_document_position: lsp::TextDocumentPositionParams {
- text_document: text_document_identifier(doc),
- position: crate::util::pos_to_lsp_pos(
- &doc.text().slice(..),
- doc.selection().cursor(),
- ),
+ text_document,
+ position,
},
// TODO: support these tokens by async receiving and updating the choice list
work_done_progress_params: lsp::WorkDoneProgressParams {
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index 138f55c2..004c5c61 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -44,16 +44,23 @@ impl Application {
let mut editor = Editor::new();
let size = terminal.size()?;
+ let language_servers = helix_lsp::Registry::new();
+ let language_server = language_servers.get("rust", &executor).unwrap();
+
if let Some(file) = args.values_of_t::<PathBuf>("files").unwrap().pop() {
editor.open(file, (size.width, size.height))?;
+
+ // TODO: do this everywhere
+ editor
+ .view_mut()
+ .unwrap()
+ .doc
+ .set_language_server(Some(language_server.clone()));
}
let mut compositor = Compositor::new();
compositor.push(Box::new(ui::EditorView::new()));
- let language_servers = helix_lsp::Registry::new();
- let language_server = language_servers.get("rust", &executor).unwrap();
-
let mut app = Self {
editor,
terminal,
@@ -90,8 +97,9 @@ impl Application {
pub async fn event_loop(&mut self) {
let mut reader = EventStream::new();
+ let doc = &self.editor.view().unwrap().doc;
self.language_server
- .text_document_did_open(&self.editor.view().unwrap().doc)
+ .text_document_did_open(doc.url().unwrap(), doc.version, doc.text())
.await
.unwrap();
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 862cf312..59490864 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -841,9 +841,13 @@ pub fn completion(cx: &mut Context) {
use std::time::Duration;
// TODO: blocking here is not ideal
+ let pos = helix_lsp::util::pos_to_lsp_pos(
+ &cx.view.doc.text().slice(..),
+ cx.view.doc.selection().cursor(),
+ );
let res = smol::block_on(
language_server
- .completion(&cx.view.doc)
+ .completion(cx.view.doc.identifier(), pos)
.timeout(Duration::from_secs(2)),
)
.expect("completion failed!")
diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs
index 25221922..629cb85c 100644
--- a/helix-term/src/ui/editor.rs
+++ b/helix-term/src/ui/editor.rs
@@ -41,7 +41,8 @@ impl EditorView {
self.render_buffer(view, area, surface, theme);
// clear with background color
- surface.set_style(viewport, theme.get("ui.background"));
+ // TODO: this seems to prevent setting style later
+ // surface.set_style(viewport, theme.get("ui.background"));
let area = Rect::new(0, viewport.height - 2, viewport.width, 1);
self.render_statusline(view, area, surface, theme);
diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml
index 0a48b721..658943c5 100644
--- a/helix-view/Cargo.toml
+++ b/helix-view/Cargo.toml
@@ -13,6 +13,7 @@ default = ["term"]
[dependencies]
anyhow = "1"
helix-core = { path = "../helix-core" }
+helix-lsp = { path = "../helix-lsp"}
# Conversion traits
# tui = { version = "0.12", default-features = false, features = ["crossterm"], optional = true}
@@ -22,3 +23,4 @@ once_cell = "1.4"
url = "2"
smol = "1"
+futures-util = "0.3"
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index d6246c34..785b0ca8 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -1,6 +1,7 @@
use anyhow::Error;
use std::future::Future;
use std::path::{Path, PathBuf};
+use std::sync::Arc;
use helix_core::{
syntax::LOADER, ChangeSet, Diagnostic, History, Position, Range, Rope, RopeSlice, Selection,
@@ -35,6 +36,7 @@ pub struct Document {
pub version: i32, // should be usize?
pub diagnostics: Vec<Diagnostic>,
+ pub language_server: Option<Arc<helix_lsp::Client>>,
}
/// Like std::mem::replace() except it allows the replacement value to be mapped from the
@@ -53,6 +55,8 @@ where
}
}
+use futures_util::TryFutureExt;
+use helix_lsp::lsp;
use url::Url;
impl Document {
@@ -72,6 +76,7 @@ impl Document {
diagnostics: Vec::new(),
version: 0,
history: History::default(),
+ language_server: None,
}
}
@@ -134,7 +139,7 @@ impl Document {
// TODO: flush?
Ok(())
- } // and_then(// lsp.send_text_saved_notification())
+ } // and_then notify save
}
pub fn set_language(&mut self, scope: &str, scopes: &[String]) {
@@ -148,6 +153,10 @@ impl Document {
};
}
+ pub fn set_language_server(&mut self, language_server: Option<Arc<helix_lsp::Client>>) {
+ self.language_server = language_server;
+ }
+
pub fn set_selection(&mut self, selection: Selection) {
// TODO: use a transaction?
self.state.selection = selection;
@@ -181,6 +190,14 @@ impl Document {
}
// TODO: map state.diagnostics over changes::map_pos too
+
+ // emit lsp notification
+ if let Some(language_server) = &self.language_server {
+ let notify = language_server
+ .text_document_did_change(self.versioned_identifier(), transaction.changes());
+
+ smol::block_on(notify).expect("failed to emit textDocument/didChange");
+ }
}
success
}
@@ -263,4 +280,14 @@ impl Document {
// }
// TODO: transact(Fn) ?
+
+ // -- LSP methods
+
+ pub fn identifier(&self) -> lsp::TextDocumentIdentifier {
+ lsp::TextDocumentIdentifier::new(self.url().unwrap())
+ }
+
+ pub fn versioned_identifier(&self) -> lsp::VersionedTextDocumentIdentifier {
+ lsp::VersionedTextDocumentIdentifier::new(self.url().unwrap(), self.version)
+ }
}