Skip to content

Commit 68be73a

Browse files
committed
add :lsp-restart command
1 parent 8a75795 commit 68be73a

File tree

2 files changed

+124
-38
lines changed

2 files changed

+124
-38
lines changed

helix-lsp/src/lib.rs

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ pub use lsp::{Position, Url};
99
pub use lsp_types as lsp;
1010

1111
use futures_util::stream::select_all::SelectAll;
12-
use helix_core::syntax::LanguageConfiguration;
12+
use helix_core::syntax::{LanguageConfiguration, LanguageServerConfiguration};
13+
use tokio::sync::mpsc::UnboundedReceiver;
1314

1415
use std::{
1516
collections::{hash_map::Entry, HashMap},
@@ -320,56 +321,51 @@ impl Registry {
320321
.map(|(_, client)| client.as_ref())
321322
}
322323

324+
pub fn restart(&mut self, language_config: &LanguageConfiguration) -> Result<Arc<Client>> {
325+
let config = match &language_config.language_server {
326+
Some(config) => config,
327+
None => {
328+
return Err(Error::LspNotDefined);
329+
}
330+
};
331+
332+
let scope = language_config.scope.clone();
333+
334+
match self.inner.entry(scope) {
335+
Entry::Vacant(_) => Err(Error::LspNotDefined),
336+
Entry::Occupied(mut entry) => {
337+
// initialize a new client
338+
let id = self.counter.fetch_add(1, Ordering::Relaxed);
339+
340+
let (client, incoming) = start_client(id, language_config, config)?;
341+
self.incoming.push(UnboundedReceiverStream::new(incoming));
342+
343+
entry.insert((id, client.clone()));
344+
345+
Ok(client)
346+
}
347+
}
348+
}
349+
323350
pub fn get(&mut self, language_config: &LanguageConfiguration) -> Result<Arc<Client>> {
324351
let config = match &language_config.language_server {
325352
Some(config) => config,
326353
None => return Err(Error::LspNotDefined),
327354
};
328355

329-
match self.inner.entry(language_config.scope.clone()) {
356+
let scope = language_config.scope.clone();
357+
358+
match self.inner.entry(scope) {
330359
Entry::Occupied(entry) => Ok(entry.get().1.clone()),
331360
Entry::Vacant(entry) => {
332361
// initialize a new client
333362
let id = self.counter.fetch_add(1, Ordering::Relaxed);
334-
let (client, incoming, initialize_notify) = Client::start(
335-
&config.command,
336-
&config.args,
337-
language_config.config.clone(),
338-
&language_config.roots,
339-
id,
340-
config.timeout,
341-
)?;
363+
364+
let NewClientResult(client, incoming) = start_client(id, language_config, config)?;
342365
self.incoming.push(UnboundedReceiverStream::new(incoming));
343-
let client = Arc::new(client);
344-
345-
// Initialize the client asynchronously
346-
let _client = client.clone();
347-
tokio::spawn(async move {
348-
use futures_util::TryFutureExt;
349-
let value = _client
350-
.capabilities
351-
.get_or_try_init(|| {
352-
_client
353-
.initialize()
354-
.map_ok(|response| response.capabilities)
355-
})
356-
.await;
357-
358-
if let Err(e) = value {
359-
log::error!("failed to initialize language server: {}", e);
360-
return;
361-
}
362-
363-
// next up, notify<initialized>
364-
_client
365-
.notify::<lsp::notification::Initialized>(lsp::InitializedParams {})
366-
.await
367-
.unwrap();
368-
369-
initialize_notify.notify_one();
370-
});
371366

372367
entry.insert((id, client.clone()));
368+
373369
Ok(client)
374370
}
375371
}
@@ -380,6 +376,55 @@ impl Registry {
380376
}
381377
}
382378

379+
struct NewClientResult(Arc<Client>, UnboundedReceiver<(usize, Call)>);
380+
381+
/// start_client takes both a LanguageConfiguration and a LanguageServerConfiguration to ensure that
382+
/// it is only called when it makes sense, specifically, start_client shouldn't care whether.
383+
fn start_client(
384+
id: usize,
385+
config: &LanguageConfiguration,
386+
ls_config: &LanguageServerConfiguration,
387+
) -> Result<NewClientResult> {
388+
let (client, incoming, initialize_notify) = Client::start(
389+
&ls_config.command,
390+
&ls_config.args,
391+
config.config.clone(),
392+
&config.roots,
393+
id,
394+
ls_config.timeout,
395+
)?;
396+
let client = Arc::new(client);
397+
398+
// Initialize the client asynchronously
399+
let _client = client.clone();
400+
tokio::spawn(async move {
401+
use futures_util::TryFutureExt;
402+
let value = _client
403+
.capabilities
404+
.get_or_try_init(|| {
405+
_client
406+
.initialize()
407+
.map_ok(|response| response.capabilities)
408+
})
409+
.await;
410+
411+
if let Err(e) = value {
412+
log::error!("failed to initialize language server: {}", e);
413+
return;
414+
}
415+
416+
// next up, notify<initialized>
417+
_client
418+
.notify::<lsp::notification::Initialized>(lsp::InitializedParams {})
419+
.await
420+
.unwrap();
421+
422+
initialize_notify.notify_one();
423+
});
424+
425+
Ok((client, incoming))
426+
}
427+
383428
#[derive(Debug)]
384429
pub enum ProgressStatus {
385430
Created,

helix-term/src/commands/typed.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::ops::Deref;
22

33
use super::*;
44

5+
use helix_core::surround::Error;
56
use helix_view::editor::{Action, ConfigEvent};
67
use ui::completers::{self, Completer};
78

@@ -982,6 +983,39 @@ fn reload(
982983
})
983984
}
984985

986+
fn lsp_restart(
987+
cx: &mut compositor::Context,
988+
_args: &[Cow<str>],
989+
event: PromptEvent,
990+
) -> anyhow::Result<()> {
991+
if event != PromptEvent::Validate {
992+
return Ok(());
993+
}
994+
995+
let (_view, doc) = current!(cx.editor);
996+
let config = doc
997+
.language_config()
998+
.ok_or(anyhow!("LSP not defined for current document"))?;
999+
1000+
let scope = config.scope.clone();
1001+
cx.editor.language_servers.restart(config)?;
1002+
1003+
let to_refresh: Vec<DocumentId> = cx
1004+
.editor
1005+
.documents_mut()
1006+
.filter_map(|doc| match doc.language_config() {
1007+
Some(config) if config.scope.eq(&scope) => Some(doc.id()),
1008+
_ => None,
1009+
})
1010+
.collect();
1011+
1012+
to_refresh.into_iter().for_each(|id| {
1013+
cx.editor.refresh_language_server(id);
1014+
});
1015+
1016+
Ok(())
1017+
}
1018+
9851019
fn tree_sitter_scopes(
9861020
cx: &mut compositor::Context,
9871021
_args: &[Cow<str>],
@@ -1827,6 +1861,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
18271861
fun: reload,
18281862
completer: None,
18291863
},
1864+
TypableCommand {
1865+
name: "lsp-reload",
1866+
aliases: &[],
1867+
doc: "Reload the LSP the is in use by the current doc",
1868+
fun: lsp_restart,
1869+
completer: None,
1870+
},
18301871
TypableCommand {
18311872
name: "tree-sitter-scopes",
18321873
aliases: &[],

0 commit comments

Comments
 (0)