@ -4,7 +4,6 @@ use crate::{
Call , Error , OffsetEncoding , Result ,
Call , Error , OffsetEncoding , Result ,
} ;
} ;
use anyhow ::anyhow ;
use helix_core ::{ find_root , ChangeSet , Rope } ;
use helix_core ::{ find_root , ChangeSet , Rope } ;
use lsp_types as lsp ;
use lsp_types as lsp ;
use serde ::Deserialize ;
use serde ::Deserialize ;
@ -546,16 +545,17 @@ impl Client {
new_text : & Rope ,
new_text : & Rope ,
changes : & ChangeSet ,
changes : & ChangeSet ,
) -> Option < impl Future < Output = Result < ( ) > > > {
) -> Option < impl Future < Output = Result < ( ) > > > {
// figure out what kind of sync the server supports
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support document sync.
let sync_capabilities = match capabilities . text_document_sync {
let sync_capabilities = match capabilities . text_document_sync {
Some ( lsp ::TextDocumentSyncCapability ::Kind ( kind ) )
Some (
| Some ( lsp ::TextDocumentSyncCapability ::Options ( lsp ::TextDocumentSyncOptions {
lsp ::TextDocumentSyncCapability ::Kind ( kind )
change : Some ( kind ) ,
| lsp ::TextDocumentSyncCapability ::Options ( lsp ::TextDocumentSyncOptions {
..
change : Some ( kind ) ,
} ) ) = > kind ,
..
} ) ,
) = > kind ,
// None | SyncOptions { changes: None }
// None | SyncOptions { changes: None }
_ = > return None ,
_ = > return None ,
} ;
} ;
@ -631,8 +631,12 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
// ) -> Result<Vec<lsp::CompletionItem>> {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support completion.
capabilities . completion_provider . as_ref ( ) ? ;
let params = lsp ::CompletionParams {
let params = lsp ::CompletionParams {
text_document_position : lsp ::TextDocumentPositionParams {
text_document_position : lsp ::TextDocumentPositionParams {
text_document ,
text_document ,
@ -647,14 +651,25 @@ impl Client {
// lsp::CompletionContext { trigger_kind: , trigger_character: Some(), }
// lsp::CompletionContext { trigger_kind: , trigger_character: Some(), }
} ;
} ;
self . call ::< lsp ::request ::Completion > ( params )
Some ( self . call ::< lsp ::request ::Completion > ( params ) )
}
}
pub fn resolve_completion_item (
pub fn resolve_completion_item (
& self ,
& self ,
completion_item : lsp ::CompletionItem ,
completion_item : lsp ::CompletionItem ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
self . call ::< lsp ::request ::ResolveCompletionItem > ( completion_item )
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support resolving completion items.
match capabilities . completion_provider {
Some ( lsp ::CompletionOptions {
resolve_provider : Some ( true ) ,
..
} ) = > ( ) ,
_ = > return None ,
}
Some ( self . call ::< lsp ::request ::ResolveCompletionItem > ( completion_item ) )
}
}
pub fn text_document_signature_help (
pub fn text_document_signature_help (
@ -665,7 +680,7 @@ impl Client {
) -> Option < impl Future < Output = Result < Value > > > {
) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if signature help is not supported
// Return early if the server does not support signature help.
capabilities . signature_help_provider . as_ref ( ) ? ;
capabilities . signature_help_provider . as_ref ( ) ? ;
let params = lsp ::SignatureHelpParams {
let params = lsp ::SignatureHelpParams {
@ -686,7 +701,18 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support hover.
match capabilities . hover_provider {
Some (
lsp ::HoverProviderCapability ::Simple ( true )
| lsp ::HoverProviderCapability ::Options ( _ ) ,
) = > ( ) ,
_ = > return None ,
}
let params = lsp ::HoverParams {
let params = lsp ::HoverParams {
text_document_position_params : lsp ::TextDocumentPositionParams {
text_document_position_params : lsp ::TextDocumentPositionParams {
text_document ,
text_document ,
@ -696,7 +722,7 @@ impl Client {
// lsp::SignatureHelpContext
// lsp::SignatureHelpContext
} ;
} ;
self . call ::< lsp ::request ::HoverRequest > ( params )
Some ( self . call ::< lsp ::request ::HoverRequest > ( params ) )
}
}
// formatting
// formatting
@ -709,13 +735,11 @@ impl Client {
) -> Option < impl Future < Output = Result < Vec < lsp ::TextEdit > > > > {
) -> Option < impl Future < Output = Result < Vec < lsp ::TextEdit > > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// check if we're able to format
// Return early if the server does not support formatting.
match capabilities . document_formatting_provider {
match capabilities . document_formatting_provider {
Some ( lsp ::OneOf ::Left ( true ) ) | Some ( lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
Some ( lsp ::OneOf ::Left ( true ) | lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
// None | Some(false)
_ = > return None ,
_ = > return None ,
} ;
} ;
// TODO: return err::unavailable so we can fall back to tree sitter formatting
// merge FormattingOptions with 'config.format'
// merge FormattingOptions with 'config.format'
let config_format = self
let config_format = self
@ -750,22 +774,20 @@ impl Client {
} )
} )
}
}
pub async fn text_document_range_formatting (
pub fn text_document_range_formatting (
& self ,
& self ,
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
range : lsp ::Range ,
range : lsp ::Range ,
options : lsp ::FormattingOptions ,
options : lsp ::FormattingOptions ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> anyhow ::Result < Vec < lsp ::TextEdit > > {
) -> Option < impl Future < Output = Result < Vec < lsp ::TextEdit > > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// check if we're able to format
// Return early if the server does not support range formatting.
match capabilities . document_range_formatting_provider {
match capabilities . document_range_formatting_provider {
Some ( lsp ::OneOf ::Left ( true ) ) | Some ( lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
Some ( lsp ::OneOf ::Left ( true ) | lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
// None | Some(false)
_ = > return None ,
_ = > return Ok ( Vec ::new ( ) ) ,
} ;
} ;
// TODO: return err::unavailable so we can fall back to tree sitter formatting
let params = lsp ::DocumentRangeFormattingParams {
let params = lsp ::DocumentRangeFormattingParams {
text_document ,
text_document ,
@ -774,11 +796,13 @@ impl Client {
work_done_progress_params : lsp ::WorkDoneProgressParams { work_done_token } ,
work_done_progress_params : lsp ::WorkDoneProgressParams { work_done_token } ,
} ;
} ;
let response = self
let request = self . call ::< lsp ::request ::RangeFormatting > ( params ) ;
. request ::< lsp ::request ::RangeFormatting > ( params )
. await ? ;
Ok ( response . unwrap_or_default ( ) )
Some ( async move {
let json = request . await ? ;
let response : Option < Vec < lsp ::TextEdit > > = serde_json ::from_value ( json ) ? ;
Ok ( response . unwrap_or_default ( ) )
} )
}
}
pub fn text_document_document_highlight (
pub fn text_document_document_highlight (
@ -786,7 +810,15 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support document highlight.
match capabilities . document_highlight_provider {
Some ( lsp ::OneOf ::Left ( true ) | lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
_ = > return None ,
}
let params = lsp ::DocumentHighlightParams {
let params = lsp ::DocumentHighlightParams {
text_document_position_params : lsp ::TextDocumentPositionParams {
text_document_position_params : lsp ::TextDocumentPositionParams {
text_document ,
text_document ,
@ -798,7 +830,7 @@ impl Client {
} ,
} ,
} ;
} ;
self . call ::< lsp ::request ::DocumentHighlightRequest > ( params )
Some ( self . call ::< lsp ::request ::DocumentHighlightRequest > ( params ) )
}
}
fn goto_request <
fn goto_request <
@ -831,8 +863,20 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
self . goto_request ::< lsp ::request ::GotoDefinition > ( text_document , position , work_done_token )
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support goto-definition.
match capabilities . definition_provider {
Some ( lsp ::OneOf ::Left ( true ) | lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
_ = > return None ,
}
Some ( self . goto_request ::< lsp ::request ::GotoDefinition > (
text_document ,
position ,
work_done_token ,
) )
}
}
pub fn goto_type_definition (
pub fn goto_type_definition (
@ -840,12 +884,23 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
self . goto_request ::< lsp ::request ::GotoTypeDefinition > (
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support goto-type-definition.
match capabilities . type_definition_provider {
Some (
lsp ::TypeDefinitionProviderCapability ::Simple ( true )
| lsp ::TypeDefinitionProviderCapability ::Options ( _ ) ,
) = > ( ) ,
_ = > return None ,
}
Some ( self . goto_request ::< lsp ::request ::GotoTypeDefinition > (
text_document ,
text_document ,
position ,
position ,
work_done_token ,
work_done_token ,
)
) )
}
}
pub fn goto_implementation (
pub fn goto_implementation (
@ -853,12 +908,23 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
self . goto_request ::< lsp ::request ::GotoImplementation > (
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support goto-definition.
match capabilities . implementation_provider {
Some (
lsp ::ImplementationProviderCapability ::Simple ( true )
| lsp ::ImplementationProviderCapability ::Options ( _ ) ,
) = > ( ) ,
_ = > return None ,
}
Some ( self . goto_request ::< lsp ::request ::GotoImplementation > (
text_document ,
text_document ,
position ,
position ,
work_done_token ,
work_done_token ,
)
) )
}
}
pub fn goto_reference (
pub fn goto_reference (
@ -866,7 +932,15 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
work_done_token : Option < lsp ::ProgressToken > ,
work_done_token : Option < lsp ::ProgressToken > ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support goto-reference.
match capabilities . references_provider {
Some ( lsp ::OneOf ::Left ( true ) | lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
_ = > return None ,
}
let params = lsp ::ReferenceParams {
let params = lsp ::ReferenceParams {
text_document_position : lsp ::TextDocumentPositionParams {
text_document_position : lsp ::TextDocumentPositionParams {
text_document ,
text_document ,
@ -881,31 +955,47 @@ impl Client {
} ,
} ,
} ;
} ;
self . call ::< lsp ::request ::References > ( params )
Some ( self . call ::< lsp ::request ::References > ( params ) )
}
}
pub fn document_symbols (
pub fn document_symbols (
& self ,
& self ,
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support document symbols.
match capabilities . document_symbol_provider {
Some ( lsp ::OneOf ::Left ( true ) | lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
_ = > return None ,
}
let params = lsp ::DocumentSymbolParams {
let params = lsp ::DocumentSymbolParams {
text_document ,
text_document ,
work_done_progress_params : lsp ::WorkDoneProgressParams ::default ( ) ,
work_done_progress_params : lsp ::WorkDoneProgressParams ::default ( ) ,
partial_result_params : lsp ::PartialResultParams ::default ( ) ,
partial_result_params : lsp ::PartialResultParams ::default ( ) ,
} ;
} ;
self . call ::< lsp ::request ::DocumentSymbolRequest > ( params )
Some ( self . call ::< lsp ::request ::DocumentSymbolRequest > ( params ) )
}
}
// empty string to get all symbols
// empty string to get all symbols
pub fn workspace_symbols ( & self , query : String ) -> impl Future < Output = Result < Value > > {
pub fn workspace_symbols ( & self , query : String ) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support workspace symbols.
match capabilities . workspace_symbol_provider {
Some ( lsp ::OneOf ::Left ( true ) | lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
_ = > return None ,
}
let params = lsp ::WorkspaceSymbolParams {
let params = lsp ::WorkspaceSymbolParams {
query ,
query ,
work_done_progress_params : lsp ::WorkDoneProgressParams ::default ( ) ,
work_done_progress_params : lsp ::WorkDoneProgressParams ::default ( ) ,
partial_result_params : lsp ::PartialResultParams ::default ( ) ,
partial_result_params : lsp ::PartialResultParams ::default ( ) ,
} ;
} ;
self . call ::< lsp ::request ::WorkspaceSymbol > ( params )
Some ( self . call ::< lsp ::request ::WorkspaceSymbol > ( params ) )
}
}
pub fn code_actions (
pub fn code_actions (
@ -913,7 +1003,18 @@ impl Client {
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
range : lsp ::Range ,
range : lsp ::Range ,
context : lsp ::CodeActionContext ,
context : lsp ::CodeActionContext ,
) -> impl Future < Output = Result < Value > > {
) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the server does not support code actions.
match capabilities . code_action_provider {
Some (
lsp ::CodeActionProviderCapability ::Simple ( true )
| lsp ::CodeActionProviderCapability ::Options ( _ ) ,
) = > ( ) ,
_ = > return None ,
}
let params = lsp ::CodeActionParams {
let params = lsp ::CodeActionParams {
text_document ,
text_document ,
range ,
range ,
@ -922,26 +1023,22 @@ impl Client {
partial_result_params : lsp ::PartialResultParams ::default ( ) ,
partial_result_params : lsp ::PartialResultParams ::default ( ) ,
} ;
} ;
self . call ::< lsp ::request ::CodeActionRequest > ( params )
Some ( self . call ::< lsp ::request ::CodeActionRequest > ( params ) )
}
}
pub async fn rename_symbol (
pub fn rename_symbol (
& self ,
& self ,
text_document : lsp ::TextDocumentIdentifier ,
text_document : lsp ::TextDocumentIdentifier ,
position : lsp ::Position ,
position : lsp ::Position ,
new_name : String ,
new_name : String ,
) -> anyhow ::Result < lsp ::WorkspaceEdit > {
) -> Option < impl Future < Output = Result < lsp ::WorkspaceEdit > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// check if we're able to rename
// Return early if the language server does not support renaming.
match capabilities . rename_provider {
match capabilities . rename_provider {
Some ( lsp ::OneOf ::Left ( true ) ) | Some ( lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
Some ( lsp ::OneOf ::Left ( true ) ) | Some ( lsp ::OneOf ::Right ( _ ) ) = > ( ) ,
// None | Some(false)
// None | Some(false)
_ = > {
_ = > return None ,
log ::warn ! ( "rename_symbol failed: The server does not support rename" ) ;
let err = "The server does not support rename" ;
return Err ( anyhow ! ( err ) ) ;
}
} ;
} ;
let params = lsp ::RenameParams {
let params = lsp ::RenameParams {
@ -955,11 +1052,21 @@ impl Client {
} ,
} ,
} ;
} ;
let response = self . request ::< lsp ::request ::Rename > ( params ) . await ? ;
let request = self . call ::< lsp ::request ::Rename > ( params ) ;
Ok ( response . unwrap_or_default ( ) )
Some ( async move {
let json = request . await ? ;
let response : Option < lsp ::WorkspaceEdit > = serde_json ::from_value ( json ) ? ;
Ok ( response . unwrap_or_default ( ) )
} )
}
}
pub fn command ( & self , command : lsp ::Command ) -> impl Future < Output = Result < Value > > {
pub fn command ( & self , command : lsp ::Command ) -> Option < impl Future < Output = Result < Value > > > {
let capabilities = self . capabilities . get ( ) . unwrap ( ) ;
// Return early if the language server does not support executing commands.
capabilities . execute_command_provider . as_ref ( ) ? ;
let params = lsp ::ExecuteCommandParams {
let params = lsp ::ExecuteCommandParams {
command : command . command ,
command : command . command ,
arguments : command . arguments . unwrap_or_default ( ) ,
arguments : command . arguments . unwrap_or_default ( ) ,
@ -968,6 +1075,6 @@ impl Client {
} ,
} ,
} ;
} ;
self . call ::< lsp ::request ::ExecuteCommand > ( params )
Some ( self . call ::< lsp ::request ::ExecuteCommand > ( params ) )
}
}
}
}