aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock12
-rw-r--r--helix-lsp/Cargo.toml1
-rw-r--r--helix-lsp/src/client.rs64
-rw-r--r--helix-lsp/src/lib.rs3
-rw-r--r--helix-term/src/commands.rs248
5 files changed, 197 insertions, 131 deletions
diff --git a/Cargo.lock b/Cargo.lock
index de62a98e..abf6e630 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -192,6 +192,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815"
[[package]]
+name = "futures-executor"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
name = "futures-macro"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -293,6 +304,7 @@ name = "helix-lsp"
version = "0.1.0"
dependencies = [
"anyhow",
+ "futures-executor",
"futures-util",
"glob",
"helix-core",
diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml
index 09351f97..0fae9cb2 100644
--- a/helix-lsp/Cargo.toml
+++ b/helix-lsp/Cargo.toml
@@ -14,6 +14,7 @@ once_cell = "1.4"
lsp-types = { version = "0.89", features = ["proposed"] }
tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1.5"
+futures-executor = { version = "0.3" }
url = "2"
pathdiff = "0.2"
shellexpand = "2.0"
diff --git a/helix-lsp/src/client.rs b/helix-lsp/src/client.rs
index c54560de..8de4b95a 100644
--- a/helix-lsp/src/client.rs
+++ b/helix-lsp/src/client.rs
@@ -152,7 +152,7 @@ impl Client {
timeout(Duration::from_secs(2), rx.recv())
.await
- .map_err(|e| Error::Timeout)? // return Timeout
+ .map_err(|_| Error::Timeout)? // return Timeout
.unwrap() // TODO: None if channel closed
}
}
@@ -500,11 +500,11 @@ impl Client {
self.call::<lsp::request::Completion>(params)
}
- pub async fn text_document_signature_help(
+ pub fn text_document_signature_help(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
- ) -> anyhow::Result<Option<lsp::SignatureHelp>> {
+ ) -> impl Future<Output = Result<Value>> {
let params = lsp::SignatureHelpParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document,
@@ -517,18 +517,14 @@ impl Client {
// lsp::SignatureHelpContext
};
- let response = self
- .request::<lsp::request::SignatureHelpRequest>(params)
- .await?;
-
- Ok(response)
+ self.call::<lsp::request::SignatureHelpRequest>(params)
}
- pub async fn text_document_hover(
+ pub fn text_document_hover(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
- ) -> anyhow::Result<Option<lsp::Hover>> {
+ ) -> impl Future<Output = Result<Value>> {
let params = lsp::HoverParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document,
@@ -540,9 +536,7 @@ impl Client {
// lsp::SignatureHelpContext
};
- let response = self.request::<lsp::request::HoverRequest>(params).await?;
-
- Ok(response)
+ self.call::<lsp::request::HoverRequest>(params)
}
// formatting
@@ -607,7 +601,7 @@ impl Client {
Ok(response.unwrap_or_default())
}
- async fn goto_request<
+ fn goto_request<
T: lsp::request::Request<
Params = lsp::GotoDefinitionParams,
Result = Option<lsp::GotoDefinitionResponse>,
@@ -616,7 +610,7 @@ impl Client {
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
- ) -> anyhow::Result<Vec<lsp::Location>> {
+ ) -> impl Future<Output = Result<Value>> {
let params = lsp::GotoDefinitionParams {
text_document_position_params: lsp::TextDocumentPositionParams {
text_document,
@@ -630,56 +624,38 @@ impl Client {
},
};
- let response = self.request::<T>(params).await?;
-
- let items = match response {
- Some(lsp::GotoDefinitionResponse::Scalar(location)) => vec![location],
- Some(lsp::GotoDefinitionResponse::Array(locations)) => locations,
- Some(lsp::GotoDefinitionResponse::Link(locations)) => locations
- .into_iter()
- .map(|location_link| lsp::Location {
- uri: location_link.target_uri,
- range: location_link.target_range,
- })
- .collect(),
- None => Vec::new(),
- };
-
- Ok(items)
+ self.call::<T>(params)
}
- pub async fn goto_definition(
+ pub fn goto_definition(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
- ) -> anyhow::Result<Vec<lsp::Location>> {
+ ) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoDefinition>(text_document, position)
- .await
}
- pub async fn goto_type_definition(
+ pub fn goto_type_definition(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
- ) -> anyhow::Result<Vec<lsp::Location>> {
+ ) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoTypeDefinition>(text_document, position)
- .await
}
- pub async fn goto_implementation(
+ pub fn goto_implementation(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
- ) -> anyhow::Result<Vec<lsp::Location>> {
+ ) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoImplementation>(text_document, position)
- .await
}
- pub async fn goto_reference(
+ pub fn goto_reference(
&self,
text_document: lsp::TextDocumentIdentifier,
position: lsp::Position,
- ) -> anyhow::Result<Vec<lsp::Location>> {
+ ) -> impl Future<Output = Result<Value>> {
let params = lsp::ReferenceParams {
text_document_position: lsp::TextDocumentPositionParams {
text_document,
@@ -696,8 +672,6 @@ impl Client {
},
};
- let response = self.request::<lsp::request::References>(params).await?;
-
- Ok(response.unwrap_or_default())
+ self.call::<lsp::request::References>(params)
}
}
diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs
index fd7e6fd3..6adaa3f8 100644
--- a/helix-lsp/src/lib.rs
+++ b/helix-lsp/src/lib.rs
@@ -203,8 +203,7 @@ impl Registry {
Client::start(&config.command, &config.args).ok()?;
// TODO: run this async without blocking
- let rt = tokio::runtime::Handle::current();
- rt.block_on(client.initialize()).unwrap();
+ futures_executor::block_on(client.initialize()).unwrap();
s_incoming.push(UnboundedReceiverStream::new(incoming));
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 1e53d010..aebdb465 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -108,16 +108,6 @@ impl<'a> Context<'a> {
/// state (usually by creating and applying a transaction).
pub type Command = fn(cx: &mut Context);
-#[inline]
-fn block_on<T>(future: impl Future<Output = T>) -> T {
- use tokio::runtime::Runtime;
- // let rt = Runtime::new().unwrap();
- let rt = tokio::runtime::Handle::current();
- // let local = LocalSet::new();
- // local.block_on(&rt, future)
- rt.block_on(future)
-}
-
pub fn move_char_left(cx: &mut Context) {
let count = cx.count;
let (view, doc) = cx.current();
@@ -260,13 +250,13 @@ pub fn move_next_word_end(cx: &mut Context) {
}
pub fn move_file_start(cx: &mut Context) {
- push_jump(cx);
+ push_jump(cx.editor);
let (view, doc) = cx.current();
doc.set_selection(view.id, Selection::point(0));
}
pub fn move_file_end(cx: &mut Context) {
- push_jump(cx);
+ push_jump(cx.editor);
let (view, doc) = cx.current();
let text = doc.text();
let last_line = text.line_to_char(text.len_lines().saturating_sub(2));
@@ -880,7 +870,7 @@ pub fn command_mode(cx: &mut Context) {
// TODO: non-blocking via save() command
let id = editor.view().doc;
let doc = &mut editor.documents[id];
- block_on(doc.save());
+ tokio::spawn(doc.save());
}
_ => (),
@@ -1079,8 +1069,8 @@ pub fn normal_mode(cx: &mut Context) {
}
// Store a jump on the jumplist.
-fn push_jump(cx: &mut Context) {
- let (view, doc) = cx.current();
+fn push_jump(editor: &mut Editor) {
+ let (view, doc) = editor.current();
let jump = { (doc.id(), doc.selection(view.id).clone()) };
view.jumps.push(jump);
}
@@ -1089,7 +1079,7 @@ pub fn goto_mode(cx: &mut Context) {
let count = cx.count;
if count > 1 {
- push_jump(cx);
+ push_jump(cx.editor);
// TODO: can't go to line 1 since we can't distinguish between g and 1g, g gets converted
// to 1g
@@ -1127,10 +1117,15 @@ pub fn exit_select_mode(cx: &mut Context) {
cx.doc().mode = Mode::Normal;
}
-fn _goto(cx: &mut Context, locations: Vec<lsp::Location>, offset_encoding: OffsetEncoding) {
+fn _goto(
+ editor: &mut Editor,
+ compositor: &mut Compositor,
+ locations: Vec<lsp::Location>,
+ offset_encoding: OffsetEncoding,
+) {
use helix_view::editor::Action;
- push_jump(cx);
+ push_jump(editor);
fn jump_to(
editor: &mut Editor,
@@ -1152,7 +1147,7 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>, offset_encoding: Offse
match locations.as_slice() {
[location] => {
- jump_to(cx.editor, location, offset_encoding, Action::Replace);
+ jump_to(editor, location, offset_encoding, Action::Replace);
}
[] => (), // maybe show user message that no definition was found?
_locations => {
@@ -1167,7 +1162,7 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>, offset_encoding: Offse
jump_to(editor, location, offset_encoding, action)
},
);
- cx.push_layer(Box::new(picker));
+ compositor.push(Box::new(picker));
}
}
}
@@ -1184,8 +1179,29 @@ pub fn goto_definition(cx: &mut Context) {
let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails
- let res = block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default();
- _goto(cx, res, offset_encoding);
+ let future = language_server.goto_definition(doc.identifier(), pos);
+
+ cx.callback(
+ future,
+ move |editor: &mut Editor,
+ compositor: &mut Compositor,
+ response: Option<lsp::GotoDefinitionResponse>| {
+ let items = match response {
+ Some(lsp::GotoDefinitionResponse::Scalar(location)) => vec![location],
+ Some(lsp::GotoDefinitionResponse::Array(locations)) => locations,
+ Some(lsp::GotoDefinitionResponse::Link(locations)) => locations
+ .into_iter()
+ .map(|location_link| lsp::Location {
+ uri: location_link.target_uri,
+ range: location_link.target_range,
+ })
+ .collect(),
+ None => Vec::new(),
+ };
+
+ _goto(editor, compositor, items, offset_encoding);
+ },
+ );
}
pub fn goto_type_definition(cx: &mut Context) {
@@ -1200,9 +1216,29 @@ pub fn goto_type_definition(cx: &mut Context) {
let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails
- let res =
- block_on(language_server.goto_type_definition(doc.identifier(), pos)).unwrap_or_default();
- _goto(cx, res, offset_encoding);
+ let future = language_server.goto_type_definition(doc.identifier(), pos);
+
+ cx.callback(
+ future,
+ move |editor: &mut Editor,
+ compositor: &mut Compositor,
+ response: Option<lsp::GotoDefinitionResponse>| {
+ let items = match response {
+ Some(lsp::GotoDefinitionResponse::Scalar(location)) => vec![location],
+ Some(lsp::GotoDefinitionResponse::Array(locations)) => locations,
+ Some(lsp::GotoDefinitionResponse::Link(locations)) => locations
+ .into_iter()
+ .map(|location_link| lsp::Location {
+ uri: location_link.target_uri,
+ range: location_link.target_range,
+ })
+ .collect(),
+ None => Vec::new(),
+ };
+
+ _goto(editor, compositor, items, offset_encoding);
+ },
+ );
}
pub fn goto_implementation(cx: &mut Context) {
@@ -1217,9 +1253,29 @@ pub fn goto_implementation(cx: &mut Context) {
let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails
- let res =
- block_on(language_server.goto_implementation(doc.identifier(), pos)).unwrap_or_default();
- _goto(cx, res, offset_encoding);
+ let future = language_server.goto_implementation(doc.identifier(), pos);
+
+ cx.callback(
+ future,
+ move |editor: &mut Editor,
+ compositor: &mut Compositor,
+ response: Option<lsp::GotoDefinitionResponse>| {
+ let items = match response {
+ Some(lsp::GotoDefinitionResponse::Scalar(location)) => vec![location],
+ Some(lsp::GotoDefinitionResponse::Array(locations)) => locations,
+ Some(lsp::GotoDefinitionResponse::Link(locations)) => locations
+ .into_iter()
+ .map(|location_link| lsp::Location {
+ uri: location_link.target_uri,
+ range: location_link.target_range,
+ })
+ .collect(),
+ None => Vec::new(),
+ };
+
+ _goto(editor, compositor, items, offset_encoding);
+ },
+ );
}
pub fn goto_reference(cx: &mut Context) {
@@ -1234,8 +1290,21 @@ pub fn goto_reference(cx: &mut Context) {
let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails
- let res = block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default();
- _goto(cx, res, offset_encoding);
+ let future = language_server.goto_reference(doc.identifier(), pos);
+
+ cx.callback(
+ future,
+ move |editor: &mut Editor,
+ compositor: &mut Compositor,
+ items: Option<Vec<lsp::Location>>| {
+ _goto(
+ editor,
+ compositor,
+ items.unwrap_or_default(),
+ offset_encoding,
+ );
+ },
+ );
}
pub fn signature_help(cx: &mut Context) {
@@ -1253,23 +1322,28 @@ pub fn signature_help(cx: &mut Context) {
);
// TODO: handle fails
+ let future = language_server.text_document_signature_help(doc.identifier(), pos);
- let res = block_on(language_server.text_document_signature_help(doc.identifier(), pos))
- .unwrap_or_default();
-
- if let Some(signature_help) = res {
- log::info!("{:?}", signature_help);
- // signatures
- // active_signature
- // active_parameter
- // render as:
-
- // signature
- // ----------
- // doc
-
- // with active param highlighted
- }
+ cx.callback(
+ future,
+ move |editor: &mut Editor,
+ compositor: &mut Compositor,
+ response: Option<lsp::SignatureHelp>| {
+ if let Some(signature_help) = response {
+ log::info!("{:?}", signature_help);
+ // signatures
+ // active_signature
+ // active_parameter
+ // render as:
+
+ // signature
+ // ----------
+ // doc
+
+ // with active param highlighted
+ }
+ },
+ );
}
// NOTE: Transactions in this module get appended to history when we switch back to normal mode.
@@ -1643,20 +1717,22 @@ pub fn format_selections(cx: &mut Context) {
};
// TODO: handle fails
// TODO: concurrent map
- let edits = block_on(language_server.text_document_range_formatting(
- doc.identifier(),
- range,
- lsp::FormattingOptions::default(),
- ))
- .unwrap_or_default();
-
- let transaction = helix_lsp::util::generate_transaction_from_edits(
- doc.text(),
- edits,
- language_server.offset_encoding(),
- );
-
- doc.apply(&transaction, view.id);
+ unimplemented!(); // neeed to block to get the formatting
+
+ // let edits = block_on(language_server.text_document_range_formatting(
+ // doc.identifier(),
+ // range,
+ // lsp::FormattingOptions::default(),
+ // ))
+ // .unwrap_or_default();
+
+ // let transaction = helix_lsp::util::generate_transaction_from_edits(
+ // doc.text(),
+ // edits,
+ // language_server.offset_encoding(),
+ // );
+
+ // doc.apply(&transaction, view.id);
}
doc.append_changes_to_history(view.id);
@@ -1734,7 +1810,7 @@ pub fn save(cx: &mut Context) {
// TODO: handle save errors somehow?
// TODO: don't block
- block_on(cx.doc().save());
+ tokio::spawn(cx.doc().save());
}
pub fn completion(cx: &mut Context) {
@@ -1847,30 +1923,34 @@ pub fn hover(cx: &mut Context) {
);
// TODO: handle fails
- let res =
- block_on(language_server.text_document_hover(doc.identifier(), pos)).unwrap_or_default();
-
- if let Some(hover) = res {
- // hover.contents / .range <- used for visualizing
- let contents = match hover.contents {
- lsp::HoverContents::Scalar(contents) => {
- // markedstring(string/languagestring to be highlighted)
- // TODO
- unimplemented!("{:?}", contents)
- }
- lsp::HoverContents::Array(contents) => {
- unimplemented!("{:?}", contents)
- }
- // TODO: render markdown
- lsp::HoverContents::Markup(contents) => contents.value,
- };
+ let future = language_server.text_document_hover(doc.identifier(), pos);
- // skip if contents empty
+ cx.callback(
+ future,
+ move |editor: &mut Editor, compositor: &mut Compositor, response: Option<lsp::Hover>| {
+ if let Some(hover) = response {
+ // hover.contents / .range <- used for visualizing
+ let contents = match hover.contents {
+ lsp::HoverContents::Scalar(contents) => {
+ // markedstring(string/languagestring to be highlighted)
+ // TODO
+ unimplemented!("{:?}", contents)
+ }
+ lsp::HoverContents::Array(contents) => {
+ unimplemented!("{:?}", contents)
+ }
+ // TODO: render markdown
+ lsp::HoverContents::Markup(contents) => contents.value,
+ };
- let contents = ui::Markdown::new(contents);
- let mut popup = Popup::new(contents);
- cx.push_layer(Box::new(popup));
- }
+ // skip if contents empty
+
+ let contents = ui::Markdown::new(contents);
+ let mut popup = Popup::new(contents);
+ compositor.push(Box::new(popup));
+ }
+ },
+ );
}
// view movements
@@ -1971,7 +2051,7 @@ pub fn space_mode(cx: &mut Context) {
'w' => {
// save current buffer
let doc = cx.doc();
- block_on(doc.save());
+ tokio::spawn(doc.save());
}
'c' => {
// close current split