Add function Editor::language_server_by_id and refactor/simplify related code, also don't 'crash' in completion menu if language_server somehow disappeared

This commit is contained in:
Philipp Mildenberger 2023-04-05 18:50:05 +02:00
parent 521cdec5a1
commit 39b9a4bba2
4 changed files with 33 additions and 30 deletions

View File

@ -665,7 +665,7 @@ pub async fn handle_language_server_message(
macro_rules! language_server { macro_rules! language_server {
() => { () => {
match self.editor.language_servers.get_by_id(server_id) { match self.editor.language_server_by_id(server_id) {
Some(language_server) => language_server, Some(language_server) => language_server,
None => { None => {
warn!("can't find language server with id `{}`", server_id); warn!("can't find language server with id `{}`", server_id);

View File

@ -301,7 +301,7 @@ fn diag_picker(
flat_diag.reserve(diags.len()); flat_diag.reserve(diags.len());
for (diag, ls) in diags { for (diag, ls) in diags {
if let Some(ls) = cx.editor.language_servers.get_by_id(ls) { if let Some(ls) = cx.editor.language_server_by_id(ls) {
flat_diag.push(PickerDiagnostic { flat_diag.push(PickerDiagnostic {
url: url.clone(), url: url.clone(),
diag, diag,
@ -725,7 +725,7 @@ pub fn code_action(cx: &mut Context) {
// always present here // always present here
let action = action.unwrap(); let action = action.unwrap();
let Some(language_server) = editor.language_servers.get_by_id(action.language_server_id) else { let Some(language_server) = editor.language_server_by_id(action.language_server_id) else {
editor.set_error("Language Server disappeared"); editor.set_error("Language Server disappeared");
return; return;
}; };
@ -772,8 +772,7 @@ pub fn execute_lsp_command(editor: &mut Editor, language_server_id: usize, cmd:
// the command is executed on the server and communicated back // the command is executed on the server and communicated back
// to the client asynchronously using workspace edits // to the client asynchronously using workspace edits
let future = match editor let future = match editor
.language_servers .language_server_by_id(language_server_id)
.get_by_id(language_server_id)
.and_then(|language_server| language_server.command(cmd)) .and_then(|language_server| language_server.command(cmd))
{ {
Some(future) => future, Some(future) => future,

View File

@ -212,6 +212,23 @@ fn completion_changes(transaction: &Transaction, trigger_offset: usize) -> Vec<C
let (view, doc) = current!(editor); let (view, doc) = current!(editor);
macro_rules! language_server {
($item:expr) => {
match editor
.language_servers
.get_by_id($item.language_server_id)
{
Some(ls) => ls,
None => {
editor.set_error("language server disappeared between completion request and application");
// TODO close the completion menu somehow,
// currently there is no trivial way to access the EditorView to close the completion menu
return;
}
}
};
}
match event { match event {
PromptEvent::Abort => {} PromptEvent::Abort => {}
PromptEvent::Update => { PromptEvent::Update => {
@ -236,17 +253,11 @@ fn completion_changes(transaction: &Transaction, trigger_offset: usize) -> Vec<C
// always present here // always present here
let item = item.unwrap(); let item = item.unwrap();
let offset_encoding = editor
.language_servers
.get_by_id(item.language_server_id)
.expect("language server disappeared between completion request and application")
.offset_encoding();
let transaction = item_to_transaction( let transaction = item_to_transaction(
doc, doc,
view.id, view.id,
item, item,
offset_encoding, language_server!(item).offset_encoding(),
trigger_offset, trigger_offset,
true, true,
replace_mode, replace_mode,
@ -262,11 +273,8 @@ fn completion_changes(transaction: &Transaction, trigger_offset: usize) -> Vec<C
// always present here // always present here
let mut item = item.unwrap().clone(); let mut item = item.unwrap().clone();
let offset_encoding = editor let language_server = language_server!(item);
.language_servers let offset_encoding = language_server.offset_encoding();
.get_by_id(item.language_server_id)
.expect("language server disappeared between completion request and application")
.offset_encoding();
let language_server = editor let language_server = editor
.language_servers .language_servers
@ -401,20 +409,11 @@ pub fn ensure_item_resolved(&mut self, cx: &mut commands::Context) -> bool {
Some(item) if !item.resolved => item.clone(), Some(item) if !item.resolved => item.clone(),
_ => return false, _ => return false,
}; };
let language_server = match cx
.editor let Some(language_server) = cx.editor.language_server_by_id(current_item.language_server_id) else { return false; };
.language_servers
.get_by_id(current_item.language_server_id)
{
Some(language_server) => language_server,
None => return false,
};
// This method should not block the compositor so we handle the response asynchronously. // This method should not block the compositor so we handle the response asynchronously.
let future = match language_server.resolve_completion_item(current_item.item.clone()) { let Some(future) = language_server.resolve_completion_item(current_item.item.clone()) else { return false; };
Some(future) => future,
None => return false,
};
cx.callback( cx.callback(
future, future,

View File

@ -874,7 +874,7 @@ pub struct Editor {
/// times during rendering and should not be set by other functions. /// times during rendering and should not be set by other functions.
pub cursor_cache: Cell<Option<Option<Position>>>, pub cursor_cache: Cell<Option<Option<Position>>>,
/// When a new completion request is sent to the server old /// When a new completion request is sent to the server old
/// unifinished request must be dropped. Each completion /// unfinished request must be dropped. Each completion
/// request is associated with a channel that cancels /// request is associated with a channel that cancels
/// when the channel is dropped. That channel is stored /// when the channel is dropped. That channel is stored
/// here. When a new completion request is sent this /// here. When a new completion request is sent this
@ -1093,6 +1093,11 @@ fn set_theme_impl(&mut self, theme: Theme, preview: ThemeAction) {
self._refresh(); self._refresh();
} }
#[inline]
pub fn language_server_by_id(&self, language_server_id: usize) -> Option<&helix_lsp::Client> {
self.language_servers.get_by_id(language_server_id)
}
/// Refreshes the language server for a given document /// Refreshes the language server for a given document
pub fn refresh_language_servers(&mut self, doc_id: DocumentId) -> Option<()> { pub fn refresh_language_servers(&mut self, doc_id: DocumentId) -> Option<()> {
self.launch_language_servers(doc_id) self.launch_language_servers(doc_id)