Skip to content

Commit e7eedb5

Browse files
committed
lsp: Check server provider capabilities
Language Servers may signal that they do not support a method in the initialization result (server capabilities). We can check these when making LSP requests and hint in the status line when a method is not supported by the server. This can also prevent crashes in servers which assume that clients do not send requests for methods which are disabled in the server capabilities. We already check server capabilities for automatic auto-complete and signature-help. This change covers manually invoked LSP commands like hover, documentHighlight, codeActions, etc.
1 parent 86a8ea5 commit e7eedb5

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

helix-term/src/commands/lsp.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,16 @@ pub fn symbol_picker(cx: &mut Context) {
325325
let doc = doc!(cx.editor);
326326

327327
let language_server = language_server!(cx.editor, doc);
328+
329+
if matches!(
330+
language_server.capabilities().workspace_symbol_provider,
331+
None | Some(lsp::OneOf::Left(false))
332+
) {
333+
cx.editor
334+
.set_status("Document symbols are not enabled by the Language Server");
335+
return;
336+
}
337+
328338
let current_url = doc.url();
329339
let offset_encoding = language_server.offset_encoding();
330340

@@ -359,6 +369,16 @@ pub fn workspace_symbol_picker(cx: &mut Context) {
359369
let doc = doc!(cx.editor);
360370
let current_url = doc.url();
361371
let language_server = language_server!(cx.editor, doc);
372+
373+
if matches!(
374+
language_server.capabilities().workspace_symbol_provider,
375+
None | Some(lsp::OneOf::Left(false))
376+
) {
377+
cx.editor
378+
.set_status("Workspace symbols are not enabled by the Language Server");
379+
return;
380+
}
381+
362382
let offset_encoding = language_server.offset_encoding();
363383
let future = language_server.workspace_symbols("".to_string());
364384

@@ -426,6 +446,15 @@ pub fn code_action(cx: &mut Context) {
426446

427447
let language_server = language_server!(cx.editor, doc);
428448

449+
if matches!(
450+
language_server.capabilities().code_action_provider,
451+
None | Some(lsp::CodeActionProviderCapability::Simple(false))
452+
) {
453+
cx.editor
454+
.set_status("Code actions are not enabled by the Language Server");
455+
return;
456+
}
457+
429458
let selection_range = doc.selection(view.id).primary();
430459
let offset_encoding = language_server.offset_encoding();
431460

@@ -737,6 +766,16 @@ fn to_locations(definitions: Option<lsp::GotoDefinitionResponse>) -> Vec<lsp::Lo
737766
pub fn goto_definition(cx: &mut Context) {
738767
let (view, doc) = current!(cx.editor);
739768
let language_server = language_server!(cx.editor, doc);
769+
770+
if matches!(
771+
language_server.capabilities().definition_provider,
772+
None | Some(lsp::OneOf::Left(false))
773+
) {
774+
cx.editor
775+
.set_status("Find definition is not enabled by the Language Server");
776+
return;
777+
}
778+
740779
let offset_encoding = language_server.offset_encoding();
741780

742781
let pos = doc.position(view.id, offset_encoding);
@@ -755,6 +794,16 @@ pub fn goto_definition(cx: &mut Context) {
755794
pub fn goto_type_definition(cx: &mut Context) {
756795
let (view, doc) = current!(cx.editor);
757796
let language_server = language_server!(cx.editor, doc);
797+
798+
if matches!(
799+
language_server.capabilities().type_definition_provider,
800+
None | Some(lsp::TypeDefinitionProviderCapability::Simple(false))
801+
) {
802+
cx.editor
803+
.set_status("Find type definition is not enabled by the Language Server");
804+
return;
805+
}
806+
758807
let offset_encoding = language_server.offset_encoding();
759808

760809
let pos = doc.position(view.id, offset_encoding);
@@ -773,6 +822,16 @@ pub fn goto_type_definition(cx: &mut Context) {
773822
pub fn goto_implementation(cx: &mut Context) {
774823
let (view, doc) = current!(cx.editor);
775824
let language_server = language_server!(cx.editor, doc);
825+
826+
if matches!(
827+
language_server.capabilities().implementation_provider,
828+
None | Some(lsp::ImplementationProviderCapability::Simple(false))
829+
) {
830+
cx.editor
831+
.set_status("Find implementation is not enabled by the Language Server");
832+
return;
833+
}
834+
776835
let offset_encoding = language_server.offset_encoding();
777836

778837
let pos = doc.position(view.id, offset_encoding);
@@ -791,6 +850,16 @@ pub fn goto_implementation(cx: &mut Context) {
791850
pub fn goto_reference(cx: &mut Context) {
792851
let (view, doc) = current!(cx.editor);
793852
let language_server = language_server!(cx.editor, doc);
853+
854+
if matches!(
855+
language_server.capabilities().references_provider,
856+
None | Some(lsp::OneOf::Left(false))
857+
) {
858+
cx.editor
859+
.set_status("Find references is not enabled by the Language Server");
860+
return;
861+
}
862+
794863
let offset_encoding = language_server.offset_encoding();
795864

796865
let pos = doc.position(view.id, offset_encoding);
@@ -832,6 +901,18 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) {
832901
return;
833902
}
834903
};
904+
905+
if was_manually_invoked
906+
&& language_server
907+
.capabilities()
908+
.signature_help_provider
909+
.is_none()
910+
{
911+
cx.editor
912+
.set_status("Signature help is not enabled by the Language Server");
913+
return;
914+
}
915+
835916
let offset_encoding = language_server.offset_encoding();
836917

837918
let pos = doc.position(view.id, offset_encoding);
@@ -928,6 +1009,16 @@ pub fn signature_help_impl(cx: &mut Context, invoked: SignatureHelpInvoked) {
9281009
pub fn hover(cx: &mut Context) {
9291010
let (view, doc) = current!(cx.editor);
9301011
let language_server = language_server!(cx.editor, doc);
1012+
1013+
if matches!(
1014+
language_server.capabilities().hover_provider,
1015+
None | Some(lsp::HoverProviderCapability::Simple(false))
1016+
) {
1017+
cx.editor
1018+
.set_status("Hover is not enabled by the Language Server");
1019+
return;
1020+
}
1021+
9311022
let offset_encoding = language_server.offset_encoding();
9321023

9331024
// TODO: factor out a doc.position_identifier() that returns lsp::TextDocumentPositionIdentifier
@@ -1016,6 +1107,16 @@ pub fn rename_symbol(cx: &mut Context) {
10161107
pub fn select_references_to_symbol_under_cursor(cx: &mut Context) {
10171108
let (view, doc) = current!(cx.editor);
10181109
let language_server = language_server!(cx.editor, doc);
1110+
1111+
if matches!(
1112+
language_server.capabilities().document_highlight_provider,
1113+
None | Some(lsp::OneOf::Left(false))
1114+
) {
1115+
cx.editor
1116+
.set_status("Document highlight is not enabled by the Language Server");
1117+
return;
1118+
}
1119+
10191120
let offset_encoding = language_server.offset_encoding();
10201121

10211122
let pos = doc.position(view.id, offset_encoding);

0 commit comments

Comments
 (0)