Work around the rest of the blocking issues.

pull/11/head
Blaž Hrastnik 3 years ago
parent d00414f81a
commit ba97005495

12
Cargo.lock generated

@ -191,6 +191,17 @@ version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815" 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]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.14" version = "0.3.14"
@ -293,6 +304,7 @@ name = "helix-lsp"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"futures-executor",
"futures-util", "futures-util",
"glob", "glob",
"helix-core", "helix-core",

@ -14,6 +14,7 @@ once_cell = "1.4"
lsp-types = { version = "0.89", features = ["proposed"] } lsp-types = { version = "0.89", features = ["proposed"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
tokio-stream = "0.1.5" tokio-stream = "0.1.5"
futures-executor = { version = "0.3" }
url = "2" url = "2"
pathdiff = "0.2" pathdiff = "0.2"
shellexpand = "2.0" shellexpand = "2.0"

@ -152,7 +152,7 @@ impl Client {
timeout(Duration::from_secs(2), rx.recv()) timeout(Duration::from_secs(2), rx.recv())
.await .await
.map_err(|e| Error::Timeout)? // return Timeout .map_err(|_| Error::Timeout)? // return Timeout
.unwrap() // TODO: None if channel closed .unwrap() // TODO: None if channel closed
} }
} }
@ -500,11 +500,11 @@ impl Client {
self.call::<lsp::request::Completion>(params) self.call::<lsp::request::Completion>(params)
} }
pub async fn text_document_signature_help( pub fn text_document_signature_help(
&self, &self,
text_document: lsp::TextDocumentIdentifier, text_document: lsp::TextDocumentIdentifier,
position: lsp::Position, position: lsp::Position,
) -> anyhow::Result<Option<lsp::SignatureHelp>> { ) -> impl Future<Output = Result<Value>> {
let params = lsp::SignatureHelpParams { let params = lsp::SignatureHelpParams {
text_document_position_params: lsp::TextDocumentPositionParams { text_document_position_params: lsp::TextDocumentPositionParams {
text_document, text_document,
@ -517,18 +517,14 @@ impl Client {
// lsp::SignatureHelpContext // lsp::SignatureHelpContext
}; };
let response = self self.call::<lsp::request::SignatureHelpRequest>(params)
.request::<lsp::request::SignatureHelpRequest>(params)
.await?;
Ok(response)
} }
pub async fn text_document_hover( pub fn text_document_hover(
&self, &self,
text_document: lsp::TextDocumentIdentifier, text_document: lsp::TextDocumentIdentifier,
position: lsp::Position, position: lsp::Position,
) -> anyhow::Result<Option<lsp::Hover>> { ) -> impl Future<Output = Result<Value>> {
let params = lsp::HoverParams { let params = lsp::HoverParams {
text_document_position_params: lsp::TextDocumentPositionParams { text_document_position_params: lsp::TextDocumentPositionParams {
text_document, text_document,
@ -540,9 +536,7 @@ impl Client {
// lsp::SignatureHelpContext // lsp::SignatureHelpContext
}; };
let response = self.request::<lsp::request::HoverRequest>(params).await?; self.call::<lsp::request::HoverRequest>(params)
Ok(response)
} }
// formatting // formatting
@ -607,7 +601,7 @@ impl Client {
Ok(response.unwrap_or_default()) Ok(response.unwrap_or_default())
} }
async fn goto_request< fn goto_request<
T: lsp::request::Request< T: lsp::request::Request<
Params = lsp::GotoDefinitionParams, Params = lsp::GotoDefinitionParams,
Result = Option<lsp::GotoDefinitionResponse>, Result = Option<lsp::GotoDefinitionResponse>,
@ -616,7 +610,7 @@ impl Client {
&self, &self,
text_document: lsp::TextDocumentIdentifier, text_document: lsp::TextDocumentIdentifier,
position: lsp::Position, position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> { ) -> impl Future<Output = Result<Value>> {
let params = lsp::GotoDefinitionParams { let params = lsp::GotoDefinitionParams {
text_document_position_params: lsp::TextDocumentPositionParams { text_document_position_params: lsp::TextDocumentPositionParams {
text_document, text_document,
@ -630,56 +624,38 @@ impl Client {
}, },
}; };
let response = self.request::<T>(params).await?; self.call::<T>(params)
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)
} }
pub async fn goto_definition( pub fn goto_definition(
&self, &self,
text_document: lsp::TextDocumentIdentifier, text_document: lsp::TextDocumentIdentifier,
position: lsp::Position, position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> { ) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoDefinition>(text_document, position) self.goto_request::<lsp::request::GotoDefinition>(text_document, position)
.await
} }
pub async fn goto_type_definition( pub fn goto_type_definition(
&self, &self,
text_document: lsp::TextDocumentIdentifier, text_document: lsp::TextDocumentIdentifier,
position: lsp::Position, position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> { ) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoTypeDefinition>(text_document, position) self.goto_request::<lsp::request::GotoTypeDefinition>(text_document, position)
.await
} }
pub async fn goto_implementation( pub fn goto_implementation(
&self, &self,
text_document: lsp::TextDocumentIdentifier, text_document: lsp::TextDocumentIdentifier,
position: lsp::Position, position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> { ) -> impl Future<Output = Result<Value>> {
self.goto_request::<lsp::request::GotoImplementation>(text_document, position) self.goto_request::<lsp::request::GotoImplementation>(text_document, position)
.await
} }
pub async fn goto_reference( pub fn goto_reference(
&self, &self,
text_document: lsp::TextDocumentIdentifier, text_document: lsp::TextDocumentIdentifier,
position: lsp::Position, position: lsp::Position,
) -> anyhow::Result<Vec<lsp::Location>> { ) -> impl Future<Output = Result<Value>> {
let params = lsp::ReferenceParams { let params = lsp::ReferenceParams {
text_document_position: lsp::TextDocumentPositionParams { text_document_position: lsp::TextDocumentPositionParams {
text_document, text_document,
@ -696,8 +672,6 @@ impl Client {
}, },
}; };
let response = self.request::<lsp::request::References>(params).await?; self.call::<lsp::request::References>(params)
Ok(response.unwrap_or_default())
} }
} }

@ -203,8 +203,7 @@ impl Registry {
Client::start(&config.command, &config.args).ok()?; Client::start(&config.command, &config.args).ok()?;
// TODO: run this async without blocking // TODO: run this async without blocking
let rt = tokio::runtime::Handle::current(); futures_executor::block_on(client.initialize()).unwrap();
rt.block_on(client.initialize()).unwrap();
s_incoming.push(UnboundedReceiverStream::new(incoming)); s_incoming.push(UnboundedReceiverStream::new(incoming));

@ -108,16 +108,6 @@ impl<'a> Context<'a> {
/// state (usually by creating and applying a transaction). /// state (usually by creating and applying a transaction).
pub type Command = fn(cx: &mut Context); 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) { pub fn move_char_left(cx: &mut Context) {
let count = cx.count; let count = cx.count;
let (view, doc) = cx.current(); 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) { pub fn move_file_start(cx: &mut Context) {
push_jump(cx); push_jump(cx.editor);
let (view, doc) = cx.current(); let (view, doc) = cx.current();
doc.set_selection(view.id, Selection::point(0)); doc.set_selection(view.id, Selection::point(0));
} }
pub fn move_file_end(cx: &mut Context) { pub fn move_file_end(cx: &mut Context) {
push_jump(cx); push_jump(cx.editor);
let (view, doc) = cx.current(); let (view, doc) = cx.current();
let text = doc.text(); let text = doc.text();
let last_line = text.line_to_char(text.len_lines().saturating_sub(2)); 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 // TODO: non-blocking via save() command
let id = editor.view().doc; let id = editor.view().doc;
let doc = &mut editor.documents[id]; 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. // Store a jump on the jumplist.
fn push_jump(cx: &mut Context) { fn push_jump(editor: &mut Editor) {
let (view, doc) = cx.current(); let (view, doc) = editor.current();
let jump = { (doc.id(), doc.selection(view.id).clone()) }; let jump = { (doc.id(), doc.selection(view.id).clone()) };
view.jumps.push(jump); view.jumps.push(jump);
} }
@ -1089,7 +1079,7 @@ pub fn goto_mode(cx: &mut Context) {
let count = cx.count; let count = cx.count;
if count > 1 { 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 // TODO: can't go to line 1 since we can't distinguish between g and 1g, g gets converted
// to 1g // to 1g
@ -1127,10 +1117,15 @@ pub fn exit_select_mode(cx: &mut Context) {
cx.doc().mode = Mode::Normal; 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; use helix_view::editor::Action;
push_jump(cx); push_jump(editor);
fn jump_to( fn jump_to(
editor: &mut Editor, editor: &mut Editor,
@ -1152,7 +1147,7 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>, offset_encoding: Offse
match locations.as_slice() { match locations.as_slice() {
[location] => { [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? [] => (), // maybe show user message that no definition was found?
_locations => { _locations => {
@ -1167,7 +1162,7 @@ fn _goto(cx: &mut Context, locations: Vec<lsp::Location>, offset_encoding: Offse
jump_to(editor, location, offset_encoding, action) 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); let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails // TODO: handle fails
let res = block_on(language_server.goto_definition(doc.identifier(), pos)).unwrap_or_default(); let future = language_server.goto_definition(doc.identifier(), pos);
_goto(cx, res, offset_encoding);
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) { 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); let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails // TODO: handle fails
let res = let future = language_server.goto_type_definition(doc.identifier(), pos);
block_on(language_server.goto_type_definition(doc.identifier(), pos)).unwrap_or_default();
_goto(cx, res, offset_encoding); 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) { 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); let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails // TODO: handle fails
let res = let future = language_server.goto_implementation(doc.identifier(), pos);
block_on(language_server.goto_implementation(doc.identifier(), pos)).unwrap_or_default();
_goto(cx, res, offset_encoding); 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) { 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); let pos = pos_to_lsp_pos(doc.text(), doc.selection(view.id).cursor(), offset_encoding);
// TODO: handle fails // TODO: handle fails
let res = block_on(language_server.goto_reference(doc.identifier(), pos)).unwrap_or_default(); let future = language_server.goto_reference(doc.identifier(), pos);
_goto(cx, res, offset_encoding);
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) { pub fn signature_help(cx: &mut Context) {
@ -1253,23 +1322,28 @@ pub fn signature_help(cx: &mut Context) {
); );
// TODO: handle fails // 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)) cx.callback(
.unwrap_or_default(); future,
move |editor: &mut Editor,
if let Some(signature_help) = res { compositor: &mut Compositor,
log::info!("{:?}", signature_help); response: Option<lsp::SignatureHelp>| {
// signatures if let Some(signature_help) = response {
// active_signature log::info!("{:?}", signature_help);
// active_parameter // signatures
// render as: // active_signature
// active_parameter
// signature // render as:
// ----------
// doc // signature
// ----------
// with active param highlighted // doc
}
// with active param highlighted
}
},
);
} }
// NOTE: Transactions in this module get appended to history when we switch back to normal mode. // 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: handle fails
// TODO: concurrent map // TODO: concurrent map
let edits = block_on(language_server.text_document_range_formatting( unimplemented!(); // neeed to block to get the formatting
doc.identifier(),
range, // let edits = block_on(language_server.text_document_range_formatting(
lsp::FormattingOptions::default(), // doc.identifier(),
)) // range,
.unwrap_or_default(); // lsp::FormattingOptions::default(),
// ))
let transaction = helix_lsp::util::generate_transaction_from_edits( // .unwrap_or_default();
doc.text(),
edits, // let transaction = helix_lsp::util::generate_transaction_from_edits(
language_server.offset_encoding(), // doc.text(),
); // edits,
// language_server.offset_encoding(),
doc.apply(&transaction, view.id); // );
// doc.apply(&transaction, view.id);
} }
doc.append_changes_to_history(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: handle save errors somehow?
// TODO: don't block // TODO: don't block
block_on(cx.doc().save()); tokio::spawn(cx.doc().save());
} }
pub fn completion(cx: &mut Context) { pub fn completion(cx: &mut Context) {
@ -1847,30 +1923,34 @@ pub fn hover(cx: &mut Context) {
); );
// TODO: handle fails // TODO: handle fails
let res = let future = language_server.text_document_hover(doc.identifier(), pos);
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,
};
// 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); // skip if contents empty
let mut popup = Popup::new(contents);
cx.push_layer(Box::new(popup)); let contents = ui::Markdown::new(contents);
} let mut popup = Popup::new(contents);
compositor.push(Box::new(popup));
}
},
);
} }
// view movements // view movements
@ -1971,7 +2051,7 @@ pub fn space_mode(cx: &mut Context) {
'w' => { 'w' => {
// save current buffer // save current buffer
let doc = cx.doc(); let doc = cx.doc();
block_on(doc.save()); tokio::spawn(doc.save());
} }
'c' => { 'c' => {
// close current split // close current split

Loading…
Cancel
Save