@@ -4,7 +4,6 @@ use crate::{
4 Call, Error, OffsetEncoding, Result,
4 Call, Error, OffsetEncoding, Result,
8use helix_core::{find_root, ChangeSet, Rope};
7use helix_core::{find_root, ChangeSet, Rope};
9use lsp_types as lsp;
8use lsp_types as lsp;
10use serde::Deserialize;
9use serde::Deserialize;
@@ -546,16 +545,17 @@ impl Client {
546 new_text: &Rope,
545 new_text: &Rope,
547 changes: &ChangeSet,
546 changes: &ChangeSet,
548 ) -> Option<impl Future<Output = Result<()>>> {
547 ) -> Option<impl Future<Output = Result<()>>> {
549− // figure out what kind of sync the server supports
551 let capabilities = self.capabilities.get().unwrap();
548 let capabilities = self.capabilities.get().unwrap();
550+ // Return early if the server does not support document sync.
553 let sync_capabilities = match capabilities.text_document_sync {
551 let sync_capabilities = match capabilities.text_document_sync {
554− Some(lsp::TextDocumentSyncCapability::Kind(kind))
553+ lsp::TextDocumentSyncCapability::Kind(kind)
555− | Some(lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
554+ | lsp::TextDocumentSyncCapability::Options(lsp::TextDocumentSyncOptions {
556− change: Some(kind),
555+ change: Some(kind),
558− })) => kind,
558+ ) => kind,
559 // None | SyncOptions { changes: None }
559 // None | SyncOptions { changes: None }
560 _ => return None,
560 _ => return None,
@@ -631,8 +631,12 @@ impl Client {
631 text_document: lsp::TextDocumentIdentifier,
631 text_document: lsp::TextDocumentIdentifier,
632 position: lsp::Position,
632 position: lsp::Position,
633 work_done_token: Option<lsp::ProgressToken>,
633 work_done_token: Option<lsp::ProgressToken>,
634− ) -> impl Future<Output = Result<Value>> {
634+ ) -> Option<impl Future<Output = Result<Value>>> {
635− // ) -> Result<Vec<lsp::CompletionItem>> {
635+ let capabilities = self.capabilities.get().unwrap();
637+ // Return early if the server does not support completion.
638+ capabilities.completion_provider.as_ref()?;
636 let params = lsp::CompletionParams {
640 let params = lsp::CompletionParams {
637 text_document_position: lsp::TextDocumentPositionParams {
641 text_document_position: lsp::TextDocumentPositionParams {
638 text_document,
642 text_document,
@@ -647,14 +651,25 @@ impl Client {
647 // lsp::CompletionContext { trigger_kind: , trigger_character: Some(), }
651 // lsp::CompletionContext { trigger_kind: , trigger_character: Some(), }
650− self.call::<lsp::request::Completion>(params)
654+ Some(self.call::<lsp::request::Completion>(params))
653 pub fn resolve_completion_item(
657 pub fn resolve_completion_item(
655 completion_item: lsp::CompletionItem,
659 completion_item: lsp::CompletionItem,
656− ) -> impl Future<Output = Result<Value>> {
660+ ) -> Option<impl Future<Output = Result<Value>>> {
661+ let capabilities = self.capabilities.get().unwrap();
663+ // Return early if the server does not support resolving completion items.
664+ match capabilities.completion_provider {
665+ Some(lsp::CompletionOptions {
666+ resolve_provider: Some(true),
657− self.call::<lsp::request::ResolveCompletionItem>(completion_item)
672+ Some(self.call::<lsp::request::ResolveCompletionItem>(completion_item))
660 pub fn text_document_signature_help(
675 pub fn text_document_signature_help(
@@ -665,7 +680,7 @@ impl Client {
665 ) -> Option<impl Future<Output = Result<Value>>> {
680 ) -> Option<impl Future<Output = Result<Value>>> {
666 let capabilities = self.capabilities.get().unwrap();
681 let capabilities = self.capabilities.get().unwrap();
668− // Return early if signature help is not supported
683+ // Return early if the server does not support signature help.
669 capabilities.signature_help_provider.as_ref()?;
684 capabilities.signature_help_provider.as_ref()?;
671 let params = lsp::SignatureHelpParams {
686 let params = lsp::SignatureHelpParams {
@@ -686,7 +701,18 @@ impl Client {
686 text_document: lsp::TextDocumentIdentifier,
701 text_document: lsp::TextDocumentIdentifier,
687 position: lsp::Position,
702 position: lsp::Position,
688 work_done_token: Option<lsp::ProgressToken>,
703 work_done_token: Option<lsp::ProgressToken>,
689− ) -> impl Future<Output = Result<Value>> {
704+ ) -> Option<impl Future<Output = Result<Value>>> {
705+ let capabilities = self.capabilities.get().unwrap();
707+ // Return early if the server does not support hover.
708+ match capabilities.hover_provider {
710+ lsp::HoverProviderCapability::Simple(true)
711+ | lsp::HoverProviderCapability::Options(_),
690 let params = lsp::HoverParams {
716 let params = lsp::HoverParams {
691 text_document_position_params: lsp::TextDocumentPositionParams {
717 text_document_position_params: lsp::TextDocumentPositionParams {
692 text_document,
718 text_document,
@@ -696,7 +722,7 @@ impl Client {
696 // lsp::SignatureHelpContext
722 // lsp::SignatureHelpContext
699− self.call::<lsp::request::HoverRequest>(params)
725+ Some(self.call::<lsp::request::HoverRequest>(params))
702 // formatting
728 // formatting
@@ -709,13 +735,11 @@ impl Client {
709 ) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>> {
735 ) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>> {
710 let capabilities = self.capabilities.get().unwrap();
736 let capabilities = self.capabilities.get().unwrap();
712− // check if we're able to format
738+ // Return early if the server does not support formatting.
713 match capabilities.document_formatting_provider {
739 match capabilities.document_formatting_provider {
714− Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
740+ Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
715− // None | Some(false)
716 _ => return None,
741 _ => return None,
718− // TODO: return err::unavailable so we can fall back to tree sitter formatting
720 // merge FormattingOptions with 'config.format'
744 // merge FormattingOptions with 'config.format'
721 let config_format = self
745 let config_format = self
@@ -750,22 +774,20 @@ impl Client {
753− pub async fn text_document_range_formatting(
777+ pub fn text_document_range_formatting(
755 text_document: lsp::TextDocumentIdentifier,
779 text_document: lsp::TextDocumentIdentifier,
756 range: lsp::Range,
780 range: lsp::Range,
757 options: lsp::FormattingOptions,
781 options: lsp::FormattingOptions,
758 work_done_token: Option<lsp::ProgressToken>,
782 work_done_token: Option<lsp::ProgressToken>,
759− ) -> anyhow::Result<Vec<lsp::TextEdit>> {
783+ ) -> Option<impl Future<Output = Result<Vec<lsp::TextEdit>>>> {
760 let capabilities = self.capabilities.get().unwrap();
784 let capabilities = self.capabilities.get().unwrap();
762− // check if we're able to format
786+ // Return early if the server does not support range formatting.
763 match capabilities.document_range_formatting_provider {
787 match capabilities.document_range_formatting_provider {
764− Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
788+ Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
765− // None | Some(false)
789+ _ => return None,
766− _ => return Ok(Vec::new()),
768− // TODO: return err::unavailable so we can fall back to tree sitter formatting
770 let params = lsp::DocumentRangeFormattingParams {
792 let params = lsp::DocumentRangeFormattingParams {
771 text_document,
793 text_document,
@@ -774,11 +796,13 @@ impl Client {
774 work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
796 work_done_progress_params: lsp::WorkDoneProgressParams { work_done_token },
778− .request::<lsp::request::RangeFormatting>(params)
799+ let request = self.call::<lsp::request::RangeFormatting>(params);
802+ let json = request.await?;
803+ let response: Option<Vec<lsp::TextEdit>> = serde_json::from_value(json)?;
781− Ok(response.unwrap_or_default())
804+ Ok(response.unwrap_or_default())
784 pub fn text_document_document_highlight(
808 pub fn text_document_document_highlight(
@@ -786,7 +810,15 @@ impl Client {
786 text_document: lsp::TextDocumentIdentifier,
810 text_document: lsp::TextDocumentIdentifier,
787 position: lsp::Position,
811 position: lsp::Position,
788 work_done_token: Option<lsp::ProgressToken>,
812 work_done_token: Option<lsp::ProgressToken>,
789− ) -> impl Future<Output = Result<Value>> {
813+ ) -> Option<impl Future<Output = Result<Value>>> {
814+ let capabilities = self.capabilities.get().unwrap();
816+ // Return early if the server does not support document highlight.
817+ match capabilities.document_highlight_provider {
818+ Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
790 let params = lsp::DocumentHighlightParams {
822 let params = lsp::DocumentHighlightParams {
791 text_document_position_params: lsp::TextDocumentPositionParams {
823 text_document_position_params: lsp::TextDocumentPositionParams {
792 text_document,
824 text_document,
@@ -798,7 +830,7 @@ impl Client {
801− self.call::<lsp::request::DocumentHighlightRequest>(params)
833+ Some(self.call::<lsp::request::DocumentHighlightRequest>(params))
804 fn goto_request<
836 fn goto_request<
@@ -831,8 +863,20 @@ impl Client {
831 text_document: lsp::TextDocumentIdentifier,
863 text_document: lsp::TextDocumentIdentifier,
832 position: lsp::Position,
864 position: lsp::Position,
833 work_done_token: Option<lsp::ProgressToken>,
865 work_done_token: Option<lsp::ProgressToken>,
834− ) -> impl Future<Output = Result<Value>> {
866+ ) -> Option<impl Future<Output = Result<Value>>> {
867+ let capabilities = self.capabilities.get().unwrap();
869+ // Return early if the server does not support goto-definition.
870+ match capabilities.definition_provider {
871+ Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
835− self.goto_request::<lsp::request::GotoDefinition>(text_document, position, work_done_token)
875+ Some(self.goto_request::<lsp::request::GotoDefinition>(
838 pub fn goto_type_definition(
882 pub fn goto_type_definition(
@@ -840,12 +884,23 @@ impl Client {
840 text_document: lsp::TextDocumentIdentifier,
884 text_document: lsp::TextDocumentIdentifier,
841 position: lsp::Position,
885 position: lsp::Position,
842 work_done_token: Option<lsp::ProgressToken>,
886 work_done_token: Option<lsp::ProgressToken>,
843− ) -> impl Future<Output = Result<Value>> {
887+ ) -> Option<impl Future<Output = Result<Value>>> {
888+ let capabilities = self.capabilities.get().unwrap();
890+ // Return early if the server does not support goto-type-definition.
891+ match capabilities.type_definition_provider {
893+ lsp::TypeDefinitionProviderCapability::Simple(true)
894+ | lsp::TypeDefinitionProviderCapability::Options(_),
844− self.goto_request::<lsp::request::GotoTypeDefinition>(
899+ Some(self.goto_request::<lsp::request::GotoTypeDefinition>(
845 text_document,
900 text_document,
846 position,
901 position,
847 work_done_token,
902 work_done_token,
851 pub fn goto_implementation(
906 pub fn goto_implementation(
@@ -853,12 +908,23 @@ impl Client {
853 text_document: lsp::TextDocumentIdentifier,
908 text_document: lsp::TextDocumentIdentifier,
854 position: lsp::Position,
909 position: lsp::Position,
855 work_done_token: Option<lsp::ProgressToken>,
910 work_done_token: Option<lsp::ProgressToken>,
856− ) -> impl Future<Output = Result<Value>> {
911+ ) -> Option<impl Future<Output = Result<Value>>> {
912+ let capabilities = self.capabilities.get().unwrap();
914+ // Return early if the server does not support goto-definition.
915+ match capabilities.implementation_provider {
917+ lsp::ImplementationProviderCapability::Simple(true)
918+ | lsp::ImplementationProviderCapability::Options(_),
857− self.goto_request::<lsp::request::GotoImplementation>(
923+ Some(self.goto_request::<lsp::request::GotoImplementation>(
858 text_document,
924 text_document,
859 position,
925 position,
860 work_done_token,
926 work_done_token,
864 pub fn goto_reference(
930 pub fn goto_reference(
@@ -866,7 +932,15 @@ impl Client {
866 text_document: lsp::TextDocumentIdentifier,
932 text_document: lsp::TextDocumentIdentifier,
867 position: lsp::Position,
933 position: lsp::Position,
868 work_done_token: Option<lsp::ProgressToken>,
934 work_done_token: Option<lsp::ProgressToken>,
869− ) -> impl Future<Output = Result<Value>> {
935+ ) -> Option<impl Future<Output = Result<Value>>> {
936+ let capabilities = self.capabilities.get().unwrap();
938+ // Return early if the server does not support goto-reference.
939+ match capabilities.references_provider {
940+ Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
870 let params = lsp::ReferenceParams {
944 let params = lsp::ReferenceParams {
871 text_document_position: lsp::TextDocumentPositionParams {
945 text_document_position: lsp::TextDocumentPositionParams {
872 text_document,
946 text_document,
@@ -881,31 +955,47 @@ impl Client {
884− self.call::<lsp::request::References>(params)
958+ Some(self.call::<lsp::request::References>(params))
887 pub fn document_symbols(
961 pub fn document_symbols(
889 text_document: lsp::TextDocumentIdentifier,
963 text_document: lsp::TextDocumentIdentifier,
890− ) -> impl Future<Output = Result<Value>> {
964+ ) -> Option<impl Future<Output = Result<Value>>> {
965+ let capabilities = self.capabilities.get().unwrap();
967+ // Return early if the server does not support document symbols.
968+ match capabilities.document_symbol_provider {
969+ Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
891 let params = lsp::DocumentSymbolParams {
973 let params = lsp::DocumentSymbolParams {
892 text_document,
974 text_document,
893 work_done_progress_params: lsp::WorkDoneProgressParams::default(),
975 work_done_progress_params: lsp::WorkDoneProgressParams::default(),
894 partial_result_params: lsp::PartialResultParams::default(),
976 partial_result_params: lsp::PartialResultParams::default(),
897− self.call::<lsp::request::DocumentSymbolRequest>(params)
979+ Some(self.call::<lsp::request::DocumentSymbolRequest>(params))
900 // empty string to get all symbols
982 // empty string to get all symbols
901− pub fn workspace_symbols(&self, query: String) -> impl Future<Output = Result<Value>> {
983+ pub fn workspace_symbols(&self, query: String) -> Option<impl Future<Output = Result<Value>>> {
984+ let capabilities = self.capabilities.get().unwrap();
986+ // Return early if the server does not support workspace symbols.
987+ match capabilities.workspace_symbol_provider {
988+ Some(lsp::OneOf::Left(true) | lsp::OneOf::Right(_)) => (),
902 let params = lsp::WorkspaceSymbolParams {
992 let params = lsp::WorkspaceSymbolParams {
904 work_done_progress_params: lsp::WorkDoneProgressParams::default(),
994 work_done_progress_params: lsp::WorkDoneProgressParams::default(),
905 partial_result_params: lsp::PartialResultParams::default(),
995 partial_result_params: lsp::PartialResultParams::default(),
908− self.call::<lsp::request::WorkspaceSymbol>(params)
998+ Some(self.call::<lsp::request::WorkspaceSymbol>(params))
911 pub fn code_actions(
1001 pub fn code_actions(
@@ -913,7 +1003,18 @@ impl Client {
913 text_document: lsp::TextDocumentIdentifier,
1003 text_document: lsp::TextDocumentIdentifier,
914 range: lsp::Range,
1004 range: lsp::Range,
915 context: lsp::CodeActionContext,
1005 context: lsp::CodeActionContext,
916− ) -> impl Future<Output = Result<Value>> {
1006+ ) -> Option<impl Future<Output = Result<Value>>> {
1007+ let capabilities = self.capabilities.get().unwrap();
1009+ // Return early if the server does not support code actions.
1010+ match capabilities.code_action_provider {
1012+ lsp::CodeActionProviderCapability::Simple(true)
1013+ | lsp::CodeActionProviderCapability::Options(_),
917 let params = lsp::CodeActionParams {
1018 let params = lsp::CodeActionParams {
918 text_document,
1019 text_document,
@@ -922,26 +1023,22 @@ impl Client {
922 partial_result_params: lsp::PartialResultParams::default(),
1023 partial_result_params: lsp::PartialResultParams::default(),
925− self.call::<lsp::request::CodeActionRequest>(params)
1026+ Some(self.call::<lsp::request::CodeActionRequest>(params))
928− pub async fn rename_symbol(
1029+ pub fn rename_symbol(
930 text_document: lsp::TextDocumentIdentifier,
1031 text_document: lsp::TextDocumentIdentifier,
931 position: lsp::Position,
1032 position: lsp::Position,
932 new_name: String,
1033 new_name: String,
933− ) -> anyhow::Result<lsp::WorkspaceEdit> {
1034+ ) -> Option<impl Future<Output = Result<lsp::WorkspaceEdit>>> {
934 let capabilities = self.capabilities.get().unwrap();
1035 let capabilities = self.capabilities.get().unwrap();
936− // check if we're able to rename
1037+ // Return early if the language server does not support renaming.
937 match capabilities.rename_provider {
1038 match capabilities.rename_provider {
938 Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
1039 Some(lsp::OneOf::Left(true)) | Some(lsp::OneOf::Right(_)) => (),
939 // None | Some(false)
1040 // None | Some(false)
941− log::warn!("rename_symbol failed: The server does not support rename");
942− let err = "The server does not support rename";
943− return Err(anyhow!(err));
1041+ _ => return None,
947 let params = lsp::RenameParams {
1044 let params = lsp::RenameParams {
@@ -955,11 +1052,21 @@ impl Client {
958− let response = self.request::<lsp::request::Rename>(params).await?;
1055+ let request = self.call::<lsp::request::Rename>(params);
1058+ let json = request.await?;
1059+ let response: Option<lsp::WorkspaceEdit> = serde_json::from_value(json)?;
959− Ok(response.unwrap_or_default())
1060+ Ok(response.unwrap_or_default())
962− pub fn command(&self, command: lsp::Command) -> impl Future<Output = Result<Value>> {
1064+ pub fn command(&self, command: lsp::Command) -> Option<impl Future<Output = Result<Value>>> {
1065+ let capabilities = self.capabilities.get().unwrap();
1067+ // Return early if the language server does not support executing commands.
1068+ capabilities.execute_command_provider.as_ref()?;
963 let params = lsp::ExecuteCommandParams {
1070 let params = lsp::ExecuteCommandParams {
964 command: command.command,
1071 command: command.command,
965 arguments: command.arguments.unwrap_or_default(),
1072 arguments: command.arguments.unwrap_or_default(),
@@ -968,6 +1075,6 @@ impl Client {
971− self.call::<lsp::request::ExecuteCommand>(params)
1078+ Some(self.call::<lsp::request::ExecuteCommand>(params))