mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Auto merge of #17527 - Veykril:caps-config, r=Veykril
internal: Move capability querying out of the config module
This commit is contained in:
commit
8c2adec32c
493
crates/rust-analyzer/src/capabilities.rs
Normal file
493
crates/rust-analyzer/src/capabilities.rs
Normal file
@ -0,0 +1,493 @@
|
||||
//! Advertises the capabilities of the LSP Server.
|
||||
use ide_db::{line_index::WideEncoding, FxHashSet};
|
||||
use lsp_types::{
|
||||
CallHierarchyServerCapability, CodeActionKind, CodeActionOptions, CodeActionProviderCapability,
|
||||
CodeLensOptions, CompletionOptions, CompletionOptionsCompletionItem, DeclarationCapability,
|
||||
DocumentOnTypeFormattingOptions, FileOperationFilter, FileOperationPattern,
|
||||
FileOperationPatternKind, FileOperationRegistrationOptions, FoldingRangeProviderCapability,
|
||||
HoverProviderCapability, ImplementationProviderCapability, InlayHintOptions,
|
||||
InlayHintServerCapabilities, OneOf, PositionEncodingKind, RenameOptions, SaveOptions,
|
||||
SelectionRangeProviderCapability, SemanticTokensFullOptions, SemanticTokensLegend,
|
||||
SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability,
|
||||
TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability,
|
||||
WorkDoneProgressOptions, WorkspaceFileOperationsServerCapabilities,
|
||||
WorkspaceFoldersServerCapabilities, WorkspaceServerCapabilities,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
config::{Config, RustfmtConfig},
|
||||
line_index::PositionEncoding,
|
||||
lsp::{ext, semantic_tokens},
|
||||
};
|
||||
|
||||
pub fn server_capabilities(config: &Config) -> ServerCapabilities {
|
||||
ServerCapabilities {
|
||||
position_encoding: match config.caps().negotiated_encoding() {
|
||||
PositionEncoding::Utf8 => Some(PositionEncodingKind::UTF8),
|
||||
PositionEncoding::Wide(wide) => match wide {
|
||||
WideEncoding::Utf16 => Some(PositionEncodingKind::UTF16),
|
||||
WideEncoding::Utf32 => Some(PositionEncodingKind::UTF32),
|
||||
_ => None,
|
||||
},
|
||||
},
|
||||
text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
|
||||
open_close: Some(true),
|
||||
change: Some(TextDocumentSyncKind::INCREMENTAL),
|
||||
will_save: None,
|
||||
will_save_wait_until: None,
|
||||
save: Some(SaveOptions::default().into()),
|
||||
})),
|
||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
||||
completion_provider: Some(CompletionOptions {
|
||||
resolve_provider: config.caps().completions_resolve_provider(),
|
||||
trigger_characters: Some(vec![
|
||||
":".to_owned(),
|
||||
".".to_owned(),
|
||||
"'".to_owned(),
|
||||
"(".to_owned(),
|
||||
]),
|
||||
all_commit_characters: None,
|
||||
completion_item: config.caps().completion_item(),
|
||||
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
||||
}),
|
||||
signature_help_provider: Some(SignatureHelpOptions {
|
||||
trigger_characters: Some(vec!["(".to_owned(), ",".to_owned(), "<".to_owned()]),
|
||||
retrigger_characters: None,
|
||||
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
||||
}),
|
||||
declaration_provider: Some(DeclarationCapability::Simple(true)),
|
||||
definition_provider: Some(OneOf::Left(true)),
|
||||
type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
|
||||
implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
|
||||
references_provider: Some(OneOf::Left(true)),
|
||||
document_highlight_provider: Some(OneOf::Left(true)),
|
||||
document_symbol_provider: Some(OneOf::Left(true)),
|
||||
workspace_symbol_provider: Some(OneOf::Left(true)),
|
||||
code_action_provider: Some(config.caps().code_action_capabilities()),
|
||||
code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
|
||||
document_formatting_provider: Some(OneOf::Left(true)),
|
||||
document_range_formatting_provider: match config.rustfmt() {
|
||||
RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)),
|
||||
_ => Some(OneOf::Left(false)),
|
||||
},
|
||||
document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
|
||||
first_trigger_character: "=".to_owned(),
|
||||
more_trigger_character: Some(more_trigger_character(config)),
|
||||
}),
|
||||
selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
|
||||
folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
|
||||
rename_provider: Some(OneOf::Right(RenameOptions {
|
||||
prepare_provider: Some(true),
|
||||
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
||||
})),
|
||||
linked_editing_range_provider: None,
|
||||
document_link_provider: None,
|
||||
color_provider: None,
|
||||
execute_command_provider: None,
|
||||
workspace: Some(WorkspaceServerCapabilities {
|
||||
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
|
||||
supported: Some(true),
|
||||
change_notifications: Some(OneOf::Left(true)),
|
||||
}),
|
||||
file_operations: Some(WorkspaceFileOperationsServerCapabilities {
|
||||
did_create: None,
|
||||
will_create: None,
|
||||
did_rename: None,
|
||||
will_rename: Some(FileOperationRegistrationOptions {
|
||||
filters: vec![
|
||||
FileOperationFilter {
|
||||
scheme: Some(String::from("file")),
|
||||
pattern: FileOperationPattern {
|
||||
glob: String::from("**/*.rs"),
|
||||
matches: Some(FileOperationPatternKind::File),
|
||||
options: None,
|
||||
},
|
||||
},
|
||||
FileOperationFilter {
|
||||
scheme: Some(String::from("file")),
|
||||
pattern: FileOperationPattern {
|
||||
glob: String::from("**"),
|
||||
matches: Some(FileOperationPatternKind::Folder),
|
||||
options: None,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
did_delete: None,
|
||||
will_delete: None,
|
||||
}),
|
||||
}),
|
||||
call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)),
|
||||
semantic_tokens_provider: Some(
|
||||
SemanticTokensOptions {
|
||||
legend: SemanticTokensLegend {
|
||||
token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(),
|
||||
token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(),
|
||||
},
|
||||
|
||||
full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }),
|
||||
range: Some(true),
|
||||
work_done_progress_options: Default::default(),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
moniker_provider: None,
|
||||
inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options(
|
||||
InlayHintOptions {
|
||||
work_done_progress_options: Default::default(),
|
||||
resolve_provider: Some(true),
|
||||
},
|
||||
))),
|
||||
inline_value_provider: None,
|
||||
experimental: Some(json!({
|
||||
"externalDocs": true,
|
||||
"hoverRange": true,
|
||||
"joinLines": true,
|
||||
"matchingBrace": true,
|
||||
"moveItem": true,
|
||||
"onEnter": true,
|
||||
"openCargoToml": true,
|
||||
"parentModule": true,
|
||||
"runnables": {
|
||||
"kinds": [ "cargo" ],
|
||||
},
|
||||
"ssr": true,
|
||||
"workspaceSymbolScopeKindFiltering": true,
|
||||
})),
|
||||
diagnostic_provider: None,
|
||||
inline_completion_provider: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub struct ClientCapabilities(lsp_types::ClientCapabilities);
|
||||
|
||||
impl ClientCapabilities {
|
||||
pub fn new(caps: lsp_types::ClientCapabilities) -> Self {
|
||||
Self(caps)
|
||||
}
|
||||
|
||||
fn completions_resolve_provider(&self) -> Option<bool> {
|
||||
self.completion_item_edit_resolve().then_some(true)
|
||||
}
|
||||
|
||||
fn experimental_bool(&self, index: &'static str) -> bool {
|
||||
|| -> _ { self.0.experimental.as_ref()?.get(index)?.as_bool() }().unwrap_or_default()
|
||||
}
|
||||
|
||||
fn experimental<T: serde::de::DeserializeOwned>(&self, index: &'static str) -> Option<T> {
|
||||
serde_json::from_value(self.0.experimental.as_ref()?.get(index)?.clone()).ok()
|
||||
}
|
||||
|
||||
/// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports.
|
||||
pub fn completion_item_edit_resolve(&self) -> bool {
|
||||
(|| {
|
||||
Some(
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.resolve_support
|
||||
.as_ref()?
|
||||
.properties
|
||||
.iter()
|
||||
.any(|cap_string| cap_string.as_str() == "additionalTextEdits"),
|
||||
)
|
||||
})() == Some(true)
|
||||
}
|
||||
|
||||
pub fn completion_label_details_support(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.label_details_support
|
||||
.as_ref()
|
||||
})()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
fn completion_item(&self) -> Option<CompletionOptionsCompletionItem> {
|
||||
Some(CompletionOptionsCompletionItem {
|
||||
label_details_support: Some(self.completion_label_details_support()),
|
||||
})
|
||||
}
|
||||
|
||||
fn code_action_capabilities(&self) -> CodeActionProviderCapability {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()
|
||||
.and_then(|it| it.code_action.as_ref())
|
||||
.and_then(|it| it.code_action_literal_support.as_ref())
|
||||
.map_or(CodeActionProviderCapability::Simple(true), |_| {
|
||||
CodeActionProviderCapability::Options(CodeActionOptions {
|
||||
// Advertise support for all built-in CodeActionKinds.
|
||||
// Ideally we would base this off of the client capabilities
|
||||
// but the client is supposed to fall back gracefully for unknown values.
|
||||
code_action_kinds: Some(vec![
|
||||
CodeActionKind::EMPTY,
|
||||
CodeActionKind::QUICKFIX,
|
||||
CodeActionKind::REFACTOR,
|
||||
CodeActionKind::REFACTOR_EXTRACT,
|
||||
CodeActionKind::REFACTOR_INLINE,
|
||||
CodeActionKind::REFACTOR_REWRITE,
|
||||
]),
|
||||
resolve_provider: Some(true),
|
||||
work_done_progress_options: Default::default(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn negotiated_encoding(&self) -> PositionEncoding {
|
||||
let client_encodings = match &self.0.general {
|
||||
Some(general) => general.position_encodings.as_deref().unwrap_or_default(),
|
||||
None => &[],
|
||||
};
|
||||
|
||||
for enc in client_encodings {
|
||||
if enc == &PositionEncodingKind::UTF8 {
|
||||
return PositionEncoding::Utf8;
|
||||
} else if enc == &PositionEncodingKind::UTF32 {
|
||||
return PositionEncoding::Wide(WideEncoding::Utf32);
|
||||
}
|
||||
// NB: intentionally prefer just about anything else to utf-16.
|
||||
}
|
||||
|
||||
PositionEncoding::Wide(WideEncoding::Utf16)
|
||||
}
|
||||
|
||||
pub fn workspace_edit_resource_operations(
|
||||
&self,
|
||||
) -> Option<&[lsp_types::ResourceOperationKind]> {
|
||||
self.0.workspace.as_ref()?.workspace_edit.as_ref()?.resource_operations.as_deref()
|
||||
}
|
||||
|
||||
pub fn semantics_tokens_augments_syntax_tokens(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0.text_document.as_ref()?.semantic_tokens.as_ref()?.augments_syntax_tokens
|
||||
})()
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn did_save_text_document_dynamic_registration(&self) -> bool {
|
||||
let caps = (|| -> _ { self.0.text_document.as_ref()?.synchronization.clone() })()
|
||||
.unwrap_or_default();
|
||||
caps.did_save == Some(true) && caps.dynamic_registration == Some(true)
|
||||
}
|
||||
|
||||
pub fn did_change_watched_files_dynamic_registration(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn did_change_watched_files_relative_pattern_support(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0.workspace.as_ref()?.did_change_watched_files.as_ref()?.relative_pattern_support
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn location_link(&self) -> bool {
|
||||
(|| -> _ { self.0.text_document.as_ref()?.definition?.link_support })().unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn line_folding_only(&self) -> bool {
|
||||
(|| -> _ { self.0.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only })()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn hierarchical_symbols(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.document_symbol
|
||||
.as_ref()?
|
||||
.hierarchical_document_symbol_support
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn code_action_literals(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.code_action
|
||||
.as_ref()?
|
||||
.code_action_literal_support
|
||||
.as_ref()
|
||||
})()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn work_done_progress(&self) -> bool {
|
||||
(|| -> _ { self.0.window.as_ref()?.work_done_progress })().unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn will_rename(&self) -> bool {
|
||||
(|| -> _ { self.0.workspace.as_ref()?.file_operations.as_ref()?.will_rename })()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn change_annotation_support(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0.workspace.as_ref()?.workspace_edit.as_ref()?.change_annotation_support.as_ref()
|
||||
})()
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn code_action_resolve(&self) -> bool {
|
||||
(|| -> _ {
|
||||
Some(
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.code_action
|
||||
.as_ref()?
|
||||
.resolve_support
|
||||
.as_ref()?
|
||||
.properties
|
||||
.as_slice(),
|
||||
)
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.any(|it| it == "edit")
|
||||
}
|
||||
|
||||
pub fn signature_help_label_offsets(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.signature_help
|
||||
.as_ref()?
|
||||
.signature_information
|
||||
.as_ref()?
|
||||
.parameter_information
|
||||
.as_ref()?
|
||||
.label_offset_support
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn code_action_group(&self) -> bool {
|
||||
self.experimental_bool("codeActionGroup")
|
||||
}
|
||||
|
||||
pub fn commands(&self) -> Option<ext::ClientCommandOptions> {
|
||||
self.experimental("commands")
|
||||
}
|
||||
|
||||
pub fn local_docs(&self) -> bool {
|
||||
self.experimental_bool("localDocs")
|
||||
}
|
||||
|
||||
pub fn open_server_logs(&self) -> bool {
|
||||
self.experimental_bool("openServerLogs")
|
||||
}
|
||||
|
||||
pub fn server_status_notification(&self) -> bool {
|
||||
self.experimental_bool("serverStatusNotification")
|
||||
}
|
||||
|
||||
pub fn snippet_text_edit(&self) -> bool {
|
||||
self.experimental_bool("snippetTextEdit")
|
||||
}
|
||||
|
||||
pub fn hover_actions(&self) -> bool {
|
||||
self.experimental_bool("hoverActions")
|
||||
}
|
||||
|
||||
/// Whether the client supports colored output for full diagnostics from `checkOnSave`.
|
||||
pub fn color_diagnostic_output(&self) -> bool {
|
||||
self.experimental_bool("colorDiagnosticOutput")
|
||||
}
|
||||
|
||||
pub fn test_explorer(&self) -> bool {
|
||||
self.experimental_bool("testExplorer")
|
||||
}
|
||||
|
||||
pub fn completion_snippet(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.snippet_support
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn semantic_tokens_refresh(&self) -> bool {
|
||||
(|| -> _ { self.0.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support })()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn code_lens_refresh(&self) -> bool {
|
||||
(|| -> _ { self.0.workspace.as_ref()?.code_lens.as_ref()?.refresh_support })()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn inlay_hints_refresh(&self) -> bool {
|
||||
(|| -> _ { self.0.workspace.as_ref()?.inlay_hint.as_ref()?.refresh_support })()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet<String> {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()
|
||||
.and_then(|text| text.inlay_hint.as_ref())
|
||||
.and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref())
|
||||
.map(|inlay_resolve| inlay_resolve.properties.iter())
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.cloned()
|
||||
.collect::<FxHashSet<_>>()
|
||||
}
|
||||
|
||||
pub fn hover_markdown_support(&self) -> bool {
|
||||
(|| -> _ {
|
||||
Some(self.0.text_document.as_ref()?.hover.as_ref()?.content_format.as_ref()?.as_slice())
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
.contains(&lsp_types::MarkupKind::Markdown)
|
||||
}
|
||||
|
||||
pub fn insert_replace_support(&self) -> bool {
|
||||
(|| -> _ {
|
||||
self.0
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.insert_replace_support
|
||||
})()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
fn more_trigger_character(config: &Config) -> Vec<String> {
|
||||
let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()];
|
||||
if config.snippet_cap().is_some() {
|
||||
res.push("<".to_owned());
|
||||
}
|
||||
res
|
||||
}
|
@ -1,230 +0,0 @@
|
||||
//! Advertises the capabilities of the LSP Server.
|
||||
use ide_db::line_index::WideEncoding;
|
||||
use lsp_types::{
|
||||
CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions,
|
||||
CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
|
||||
CompletionOptionsCompletionItem, DeclarationCapability, DocumentOnTypeFormattingOptions,
|
||||
FileOperationFilter, FileOperationPattern, FileOperationPatternKind,
|
||||
FileOperationRegistrationOptions, FoldingRangeProviderCapability, HoverProviderCapability,
|
||||
ImplementationProviderCapability, InlayHintOptions, InlayHintServerCapabilities, OneOf,
|
||||
PositionEncodingKind, RenameOptions, SaveOptions, SelectionRangeProviderCapability,
|
||||
SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities,
|
||||
SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
|
||||
TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions,
|
||||
WorkspaceFileOperationsServerCapabilities, WorkspaceFoldersServerCapabilities,
|
||||
WorkspaceServerCapabilities,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{
|
||||
config::{Config, RustfmtConfig},
|
||||
line_index::PositionEncoding,
|
||||
lsp::semantic_tokens,
|
||||
lsp_ext::negotiated_encoding,
|
||||
};
|
||||
|
||||
pub fn server_capabilities(config: &Config) -> ServerCapabilities {
|
||||
ServerCapabilities {
|
||||
position_encoding: match negotiated_encoding(config.caps()) {
|
||||
PositionEncoding::Utf8 => Some(PositionEncodingKind::UTF8),
|
||||
PositionEncoding::Wide(wide) => match wide {
|
||||
WideEncoding::Utf16 => Some(PositionEncodingKind::UTF16),
|
||||
WideEncoding::Utf32 => Some(PositionEncodingKind::UTF32),
|
||||
_ => None,
|
||||
},
|
||||
},
|
||||
text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
|
||||
open_close: Some(true),
|
||||
change: Some(TextDocumentSyncKind::INCREMENTAL),
|
||||
will_save: None,
|
||||
will_save_wait_until: None,
|
||||
save: Some(SaveOptions::default().into()),
|
||||
})),
|
||||
hover_provider: Some(HoverProviderCapability::Simple(true)),
|
||||
completion_provider: Some(CompletionOptions {
|
||||
resolve_provider: completions_resolve_provider(config.caps()),
|
||||
trigger_characters: Some(vec![
|
||||
":".to_owned(),
|
||||
".".to_owned(),
|
||||
"'".to_owned(),
|
||||
"(".to_owned(),
|
||||
]),
|
||||
all_commit_characters: None,
|
||||
completion_item: completion_item(config),
|
||||
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
||||
}),
|
||||
signature_help_provider: Some(SignatureHelpOptions {
|
||||
trigger_characters: Some(vec!["(".to_owned(), ",".to_owned(), "<".to_owned()]),
|
||||
retrigger_characters: None,
|
||||
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
||||
}),
|
||||
declaration_provider: Some(DeclarationCapability::Simple(true)),
|
||||
definition_provider: Some(OneOf::Left(true)),
|
||||
type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
|
||||
implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
|
||||
references_provider: Some(OneOf::Left(true)),
|
||||
document_highlight_provider: Some(OneOf::Left(true)),
|
||||
document_symbol_provider: Some(OneOf::Left(true)),
|
||||
workspace_symbol_provider: Some(OneOf::Left(true)),
|
||||
code_action_provider: Some(code_action_capabilities(config.caps())),
|
||||
code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
|
||||
document_formatting_provider: Some(OneOf::Left(true)),
|
||||
document_range_formatting_provider: match config.rustfmt() {
|
||||
RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)),
|
||||
_ => Some(OneOf::Left(false)),
|
||||
},
|
||||
document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
|
||||
first_trigger_character: "=".to_owned(),
|
||||
more_trigger_character: Some(more_trigger_character(config)),
|
||||
}),
|
||||
selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
|
||||
folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
|
||||
rename_provider: Some(OneOf::Right(RenameOptions {
|
||||
prepare_provider: Some(true),
|
||||
work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
|
||||
})),
|
||||
linked_editing_range_provider: None,
|
||||
document_link_provider: None,
|
||||
color_provider: None,
|
||||
execute_command_provider: None,
|
||||
workspace: Some(WorkspaceServerCapabilities {
|
||||
workspace_folders: Some(WorkspaceFoldersServerCapabilities {
|
||||
supported: Some(true),
|
||||
change_notifications: Some(OneOf::Left(true)),
|
||||
}),
|
||||
file_operations: Some(WorkspaceFileOperationsServerCapabilities {
|
||||
did_create: None,
|
||||
will_create: None,
|
||||
did_rename: None,
|
||||
will_rename: Some(FileOperationRegistrationOptions {
|
||||
filters: vec![
|
||||
FileOperationFilter {
|
||||
scheme: Some(String::from("file")),
|
||||
pattern: FileOperationPattern {
|
||||
glob: String::from("**/*.rs"),
|
||||
matches: Some(FileOperationPatternKind::File),
|
||||
options: None,
|
||||
},
|
||||
},
|
||||
FileOperationFilter {
|
||||
scheme: Some(String::from("file")),
|
||||
pattern: FileOperationPattern {
|
||||
glob: String::from("**"),
|
||||
matches: Some(FileOperationPatternKind::Folder),
|
||||
options: None,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
did_delete: None,
|
||||
will_delete: None,
|
||||
}),
|
||||
}),
|
||||
call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)),
|
||||
semantic_tokens_provider: Some(
|
||||
SemanticTokensOptions {
|
||||
legend: SemanticTokensLegend {
|
||||
token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(),
|
||||
token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(),
|
||||
},
|
||||
|
||||
full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }),
|
||||
range: Some(true),
|
||||
work_done_progress_options: Default::default(),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
moniker_provider: None,
|
||||
inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options(
|
||||
InlayHintOptions {
|
||||
work_done_progress_options: Default::default(),
|
||||
resolve_provider: Some(true),
|
||||
},
|
||||
))),
|
||||
inline_value_provider: None,
|
||||
experimental: Some(json!({
|
||||
"externalDocs": true,
|
||||
"hoverRange": true,
|
||||
"joinLines": true,
|
||||
"matchingBrace": true,
|
||||
"moveItem": true,
|
||||
"onEnter": true,
|
||||
"openCargoToml": true,
|
||||
"parentModule": true,
|
||||
"runnables": {
|
||||
"kinds": [ "cargo" ],
|
||||
},
|
||||
"ssr": true,
|
||||
"workspaceSymbolScopeKindFiltering": true,
|
||||
})),
|
||||
diagnostic_provider: None,
|
||||
inline_completion_provider: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option<bool> {
|
||||
if completion_item_edit_resolve(client_caps) {
|
||||
Some(true)
|
||||
} else {
|
||||
tracing::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports.
|
||||
pub(crate) fn completion_item_edit_resolve(caps: &ClientCapabilities) -> bool {
|
||||
(|| {
|
||||
Some(
|
||||
caps.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.resolve_support
|
||||
.as_ref()?
|
||||
.properties
|
||||
.iter()
|
||||
.any(|cap_string| cap_string.as_str() == "additionalTextEdits"),
|
||||
)
|
||||
})() == Some(true)
|
||||
}
|
||||
|
||||
fn completion_item(config: &Config) -> Option<CompletionOptionsCompletionItem> {
|
||||
Some(CompletionOptionsCompletionItem {
|
||||
label_details_support: Some(config.completion_label_details_support()),
|
||||
})
|
||||
}
|
||||
|
||||
fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability {
|
||||
client_caps
|
||||
.text_document
|
||||
.as_ref()
|
||||
.and_then(|it| it.code_action.as_ref())
|
||||
.and_then(|it| it.code_action_literal_support.as_ref())
|
||||
.map_or(CodeActionProviderCapability::Simple(true), |_| {
|
||||
CodeActionProviderCapability::Options(CodeActionOptions {
|
||||
// Advertise support for all built-in CodeActionKinds.
|
||||
// Ideally we would base this off of the client capabilities
|
||||
// but the client is supposed to fall back gracefully for unknown values.
|
||||
code_action_kinds: Some(vec![
|
||||
CodeActionKind::EMPTY,
|
||||
CodeActionKind::QUICKFIX,
|
||||
CodeActionKind::REFACTOR,
|
||||
CodeActionKind::REFACTOR_EXTRACT,
|
||||
CodeActionKind::REFACTOR_INLINE,
|
||||
CodeActionKind::REFACTOR_REWRITE,
|
||||
]),
|
||||
resolve_provider: Some(true),
|
||||
work_done_progress_options: Default::default(),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn more_trigger_character(config: &Config) -> Vec<String> {
|
||||
let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()];
|
||||
if config.snippet_cap().is_some() {
|
||||
res.push("<".to_owned());
|
||||
}
|
||||
res
|
||||
}
|
@ -19,7 +19,6 @@ use ide_db::{
|
||||
SnippetCap,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use lsp_types::{ClientCapabilities, MarkupKind};
|
||||
use paths::{Utf8Path, Utf8PathBuf};
|
||||
use project_model::{
|
||||
CargoConfig, CargoFeatures, ProjectJson, ProjectJsonData, ProjectManifest, RustLibSource,
|
||||
@ -35,10 +34,9 @@ use triomphe::Arc;
|
||||
use vfs::{AbsPath, AbsPathBuf, VfsPath};
|
||||
|
||||
use crate::{
|
||||
caps::completion_item_edit_resolve,
|
||||
capabilities::ClientCapabilities,
|
||||
diagnostics::DiagnosticsMapConfig,
|
||||
line_index::PositionEncoding,
|
||||
lsp_ext::{self, negotiated_encoding, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope},
|
||||
lsp_ext::{WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope},
|
||||
};
|
||||
|
||||
mod patch_old_style;
|
||||
@ -659,7 +657,7 @@ pub struct Config {
|
||||
discovered_projects: Vec<ProjectManifest>,
|
||||
/// The workspace roots as registered by the LSP client
|
||||
workspace_roots: Vec<AbsPathBuf>,
|
||||
caps: lsp_types::ClientCapabilities,
|
||||
caps: ClientCapabilities,
|
||||
root_path: AbsPathBuf,
|
||||
snippets: Vec<Snippet>,
|
||||
visual_studio_code_version: Option<Version>,
|
||||
@ -698,6 +696,15 @@ pub struct Config {
|
||||
detached_files: Vec<AbsPathBuf>,
|
||||
}
|
||||
|
||||
// Delegate capability fetching methods
|
||||
impl std::ops::Deref for Config {
|
||||
type Target = ClientCapabilities;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.caps
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn user_config_path(&self) -> &VfsPath {
|
||||
&self.user_config_path
|
||||
@ -954,23 +961,6 @@ impl ConfigChange {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! try_ {
|
||||
($expr:expr) => {
|
||||
|| -> _ { Some($expr) }()
|
||||
};
|
||||
}
|
||||
macro_rules! try_or {
|
||||
($expr:expr, $or:expr) => {
|
||||
try_!($expr).unwrap_or($or)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! try_or_def {
|
||||
($expr:expr) => {
|
||||
try_!($expr).unwrap_or_default()
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum LinkedProject {
|
||||
ProjectManifest(ProjectManifest),
|
||||
@ -1177,7 +1167,7 @@ impl std::error::Error for ConfigErrors {}
|
||||
impl Config {
|
||||
pub fn new(
|
||||
root_path: AbsPathBuf,
|
||||
caps: ClientCapabilities,
|
||||
caps: lsp_types::ClientCapabilities,
|
||||
workspace_roots: Vec<AbsPathBuf>,
|
||||
visual_studio_code_version: Option<Version>,
|
||||
user_config_path: Option<Utf8PathBuf>,
|
||||
@ -1205,7 +1195,7 @@ impl Config {
|
||||
};
|
||||
|
||||
Config {
|
||||
caps,
|
||||
caps: ClientCapabilities::new(caps),
|
||||
discovered_projects: Vec::new(),
|
||||
root_path,
|
||||
snippets: Default::default(),
|
||||
@ -1266,7 +1256,7 @@ impl Config {
|
||||
&self.root_ratoml_path
|
||||
}
|
||||
|
||||
pub fn caps(&self) -> &lsp_types::ClientCapabilities {
|
||||
pub fn caps(&self) -> &ClientCapabilities {
|
||||
&self.caps
|
||||
}
|
||||
}
|
||||
@ -1289,7 +1279,7 @@ impl Config {
|
||||
CompletionConfig {
|
||||
enable_postfix_completions: self.completion_postfix_enable().to_owned(),
|
||||
enable_imports_on_the_fly: self.completion_autoimport_enable().to_owned()
|
||||
&& completion_item_edit_resolve(&self.caps),
|
||||
&& self.caps.completion_item_edit_resolve(),
|
||||
enable_self_on_the_fly: self.completion_autoself_enable().to_owned(),
|
||||
enable_private_editable: self.completion_privateEditable_enable().to_owned(),
|
||||
full_function_signatures: self.completion_fullFunctionSignatures_enable().to_owned(),
|
||||
@ -1298,16 +1288,7 @@ impl Config {
|
||||
CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses),
|
||||
CallableCompletionDef::None => None,
|
||||
},
|
||||
snippet_cap: SnippetCap::new(try_or_def!(
|
||||
self.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.snippet_support?
|
||||
)),
|
||||
snippet_cap: SnippetCap::new(self.completion_snippet()),
|
||||
insert_use: self.insert_use_config(source_root),
|
||||
prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
|
||||
prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
|
||||
@ -1359,7 +1340,7 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn hover_actions(&self) -> HoverActionsConfig {
|
||||
let enable = self.experimental("hoverActions") && self.hover_actions_enable().to_owned();
|
||||
let enable = self.caps.hover_actions() && self.hover_actions_enable().to_owned();
|
||||
HoverActionsConfig {
|
||||
implementations: enable && self.hover_actions_implementations_enable().to_owned(),
|
||||
references: enable && self.hover_actions_references_enable().to_owned(),
|
||||
@ -1385,17 +1366,7 @@ impl Config {
|
||||
}),
|
||||
documentation: self.hover_documentation_enable().to_owned(),
|
||||
format: {
|
||||
let is_markdown = try_or_def!(self
|
||||
.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.hover
|
||||
.as_ref()?
|
||||
.content_format
|
||||
.as_ref()?
|
||||
.as_slice())
|
||||
.contains(&MarkupKind::Markdown);
|
||||
if is_markdown {
|
||||
if self.caps.hover_markdown_support() {
|
||||
HoverDocFormat::Markdown
|
||||
} else {
|
||||
HoverDocFormat::PlainText
|
||||
@ -1409,17 +1380,7 @@ impl Config {
|
||||
}
|
||||
|
||||
pub fn inlay_hints(&self) -> InlayHintsConfig {
|
||||
let client_capability_fields = self
|
||||
.caps
|
||||
.text_document
|
||||
.as_ref()
|
||||
.and_then(|text| text.inlay_hint.as_ref())
|
||||
.and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref())
|
||||
.map(|inlay_resolve| inlay_resolve.properties.iter())
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.cloned()
|
||||
.collect::<FxHashSet<_>>();
|
||||
let client_capability_fields = self.inlay_hint_resolve_support_properties();
|
||||
|
||||
InlayHintsConfig {
|
||||
render_colons: self.inlayHints_renderColons().to_owned(),
|
||||
@ -1590,165 +1551,10 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn did_save_text_document_dynamic_registration(&self) -> bool {
|
||||
let caps = try_or_def!(self.caps.text_document.as_ref()?.synchronization.clone()?);
|
||||
caps.did_save == Some(true) && caps.dynamic_registration == Some(true)
|
||||
}
|
||||
|
||||
pub fn did_change_watched_files_dynamic_registration(&self) -> bool {
|
||||
try_or_def!(
|
||||
self.caps.workspace.as_ref()?.did_change_watched_files.as_ref()?.dynamic_registration?
|
||||
)
|
||||
}
|
||||
|
||||
pub fn did_change_watched_files_relative_pattern_support(&self) -> bool {
|
||||
try_or_def!(
|
||||
self.caps
|
||||
.workspace
|
||||
.as_ref()?
|
||||
.did_change_watched_files
|
||||
.as_ref()?
|
||||
.relative_pattern_support?
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prefill_caches(&self) -> bool {
|
||||
self.cachePriming_enable().to_owned()
|
||||
}
|
||||
|
||||
pub fn location_link(&self) -> bool {
|
||||
try_or_def!(self.caps.text_document.as_ref()?.definition?.link_support?)
|
||||
}
|
||||
|
||||
pub fn line_folding_only(&self) -> bool {
|
||||
try_or_def!(self.caps.text_document.as_ref()?.folding_range.as_ref()?.line_folding_only?)
|
||||
}
|
||||
|
||||
pub fn hierarchical_symbols(&self) -> bool {
|
||||
try_or_def!(
|
||||
self.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.document_symbol
|
||||
.as_ref()?
|
||||
.hierarchical_document_symbol_support?
|
||||
)
|
||||
}
|
||||
|
||||
pub fn code_action_literals(&self) -> bool {
|
||||
try_!(self
|
||||
.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.code_action
|
||||
.as_ref()?
|
||||
.code_action_literal_support
|
||||
.as_ref()?)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn work_done_progress(&self) -> bool {
|
||||
try_or_def!(self.caps.window.as_ref()?.work_done_progress?)
|
||||
}
|
||||
|
||||
pub fn will_rename(&self) -> bool {
|
||||
try_or_def!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?)
|
||||
}
|
||||
|
||||
pub fn change_annotation_support(&self) -> bool {
|
||||
try_!(self
|
||||
.caps
|
||||
.workspace
|
||||
.as_ref()?
|
||||
.workspace_edit
|
||||
.as_ref()?
|
||||
.change_annotation_support
|
||||
.as_ref()?)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn code_action_resolve(&self) -> bool {
|
||||
try_or_def!(self
|
||||
.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.code_action
|
||||
.as_ref()?
|
||||
.resolve_support
|
||||
.as_ref()?
|
||||
.properties
|
||||
.as_slice())
|
||||
.iter()
|
||||
.any(|it| it == "edit")
|
||||
}
|
||||
|
||||
pub fn signature_help_label_offsets(&self) -> bool {
|
||||
try_or_def!(
|
||||
self.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.signature_help
|
||||
.as_ref()?
|
||||
.signature_information
|
||||
.as_ref()?
|
||||
.parameter_information
|
||||
.as_ref()?
|
||||
.label_offset_support?
|
||||
)
|
||||
}
|
||||
|
||||
pub fn completion_label_details_support(&self) -> bool {
|
||||
try_!(self
|
||||
.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.label_details_support
|
||||
.as_ref()?)
|
||||
.is_some()
|
||||
}
|
||||
|
||||
pub fn semantics_tokens_augments_syntax_tokens(&self) -> bool {
|
||||
try_!(self.caps.text_document.as_ref()?.semantic_tokens.as_ref()?.augments_syntax_tokens?)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn position_encoding(&self) -> PositionEncoding {
|
||||
negotiated_encoding(&self.caps)
|
||||
}
|
||||
|
||||
fn experimental(&self, index: &'static str) -> bool {
|
||||
try_or_def!(self.caps.experimental.as_ref()?.get(index)?.as_bool()?)
|
||||
}
|
||||
|
||||
pub fn code_action_group(&self) -> bool {
|
||||
self.experimental("codeActionGroup")
|
||||
}
|
||||
|
||||
pub fn local_docs(&self) -> bool {
|
||||
self.experimental("localDocs")
|
||||
}
|
||||
|
||||
pub fn open_server_logs(&self) -> bool {
|
||||
self.experimental("openServerLogs")
|
||||
}
|
||||
|
||||
pub fn server_status_notification(&self) -> bool {
|
||||
self.experimental("serverStatusNotification")
|
||||
}
|
||||
|
||||
/// Whether the client supports colored output for full diagnostics from `checkOnSave`.
|
||||
pub fn color_diagnostic_output(&self) -> bool {
|
||||
self.experimental("colorDiagnosticOutput")
|
||||
}
|
||||
|
||||
pub fn test_explorer(&self) -> bool {
|
||||
self.experimental("testExplorer")
|
||||
}
|
||||
|
||||
pub fn publish_diagnostics(&self) -> bool {
|
||||
self.diagnostics_enable().to_owned()
|
||||
}
|
||||
@ -2026,7 +1832,7 @@ impl Config {
|
||||
pub fn snippet_cap(&self) -> Option<SnippetCap> {
|
||||
// FIXME: Also detect the proposed lsp version at caps.workspace.workspaceEdit.snippetEditSupport
|
||||
// once lsp-types has it.
|
||||
SnippetCap::new(self.experimental("snippetTextEdit"))
|
||||
SnippetCap::new(self.snippet_text_edit())
|
||||
}
|
||||
|
||||
pub fn call_info(&self) -> CallInfoConfig {
|
||||
@ -2066,36 +1872,8 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn semantic_tokens_refresh(&self) -> bool {
|
||||
try_or_def!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?)
|
||||
}
|
||||
|
||||
pub fn code_lens_refresh(&self) -> bool {
|
||||
try_or_def!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?)
|
||||
}
|
||||
|
||||
pub fn inlay_hints_refresh(&self) -> bool {
|
||||
try_or_def!(self.caps.workspace.as_ref()?.inlay_hint.as_ref()?.refresh_support?)
|
||||
}
|
||||
|
||||
pub fn insert_replace_support(&self) -> bool {
|
||||
try_or_def!(
|
||||
self.caps
|
||||
.text_document
|
||||
.as_ref()?
|
||||
.completion
|
||||
.as_ref()?
|
||||
.completion_item
|
||||
.as_ref()?
|
||||
.insert_replace_support?
|
||||
)
|
||||
}
|
||||
|
||||
pub fn client_commands(&self) -> ClientCommandsConfig {
|
||||
let commands =
|
||||
try_or!(self.caps.experimental.as_ref()?.get("commands")?, &serde_json::Value::Null);
|
||||
let commands: Option<lsp_ext::ClientCommandOptions> =
|
||||
serde_json::from_value(commands.clone()).ok();
|
||||
let commands = self.commands();
|
||||
let force = commands.is_none() && *self.lens_forceCustomCommands();
|
||||
let commands = commands.map(|it| it.commands).unwrap_or_default();
|
||||
|
||||
|
@ -66,7 +66,7 @@ fn location(
|
||||
let uri = url_from_abs_path(&file_name);
|
||||
|
||||
let range = {
|
||||
let position_encoding = snap.config.position_encoding();
|
||||
let position_encoding = snap.config.negotiated_encoding();
|
||||
lsp_types::Range::new(
|
||||
position(
|
||||
&position_encoding,
|
||||
|
@ -529,7 +529,7 @@ impl GlobalStateSnapshot {
|
||||
pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
|
||||
let endings = self.vfs.read().1[&file_id];
|
||||
let index = self.analysis.file_line_index(file_id)?;
|
||||
let res = LineIndex { index, endings, encoding: self.config.position_encoding() };
|
||||
let res = LineIndex { index, endings, encoding: self.config.caps().negotiated_encoding() };
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
|
@ -100,7 +100,7 @@ pub(crate) fn handle_did_change_text_document(
|
||||
*version = params.text_document.version;
|
||||
|
||||
let new_contents = apply_document_changes(
|
||||
state.config.position_encoding(),
|
||||
state.config.negotiated_encoding(),
|
||||
std::str::from_utf8(data).unwrap(),
|
||||
params.content_changes,
|
||||
)
|
||||
|
@ -2294,19 +2294,8 @@ fn to_url(path: VfsPath) -> Option<Url> {
|
||||
}
|
||||
|
||||
fn resource_ops_supported(config: &Config, kind: ResourceOperationKind) -> anyhow::Result<()> {
|
||||
#[rustfmt::skip]
|
||||
let resops = (|| {
|
||||
config
|
||||
.caps()
|
||||
.workspace
|
||||
.as_ref()?
|
||||
.workspace_edit
|
||||
.as_ref()?
|
||||
.resource_operations
|
||||
.as_ref()
|
||||
})();
|
||||
|
||||
if !matches!(resops, Some(resops) if resops.contains(&kind)) {
|
||||
if !matches!(config.workspace_edit_resource_operations(), Some(resops) if resops.contains(&kind))
|
||||
{
|
||||
return Err(LspError::new(
|
||||
ErrorCode::RequestFailed as i32,
|
||||
format!(
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
pub mod cli;
|
||||
|
||||
mod caps;
|
||||
mod capabilities;
|
||||
mod diagnostics;
|
||||
mod diff;
|
||||
mod dispatch;
|
||||
@ -47,7 +47,8 @@ mod integrated_benchmarks;
|
||||
use serde::de::DeserializeOwned;
|
||||
|
||||
pub use crate::{
|
||||
caps::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph, version::version,
|
||||
capabilities::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph,
|
||||
version::version,
|
||||
};
|
||||
|
||||
pub fn from_json<T: DeserializeOwned>(
|
||||
|
@ -4,19 +4,16 @@
|
||||
|
||||
use std::ops;
|
||||
|
||||
use ide_db::line_index::WideEncoding;
|
||||
use lsp_types::request::Request;
|
||||
use lsp_types::Url;
|
||||
use lsp_types::{
|
||||
notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams,
|
||||
PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
|
||||
};
|
||||
use lsp_types::{PositionEncodingKind, Url};
|
||||
use paths::Utf8PathBuf;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::line_index::PositionEncoding;
|
||||
|
||||
pub enum InternalTestingFetchConfig {}
|
||||
|
||||
impl Request for InternalTestingFetchConfig {
|
||||
@ -737,24 +734,6 @@ pub enum CodeLensResolveDataKind {
|
||||
References(lsp_types::TextDocumentPositionParams),
|
||||
}
|
||||
|
||||
pub fn negotiated_encoding(caps: &lsp_types::ClientCapabilities) -> PositionEncoding {
|
||||
let client_encodings = match &caps.general {
|
||||
Some(general) => general.position_encodings.as_deref().unwrap_or_default(),
|
||||
None => &[],
|
||||
};
|
||||
|
||||
for enc in client_encodings {
|
||||
if enc == &PositionEncodingKind::UTF8 {
|
||||
return PositionEncoding::Utf8;
|
||||
} else if enc == &PositionEncodingKind::UTF32 {
|
||||
return PositionEncoding::Wide(WideEncoding::Utf32);
|
||||
}
|
||||
// NB: intentionally prefer just about anything else to utf-16.
|
||||
}
|
||||
|
||||
PositionEncoding::Wide(WideEncoding::Utf16)
|
||||
}
|
||||
|
||||
pub enum MoveItem {}
|
||||
|
||||
impl Request for MoveItem {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!---
|
||||
lsp/ext.rs hash: a0867710490bf8da
|
||||
lsp/ext.rs hash: 39b47906286ad9c
|
||||
|
||||
If you need to change the above hash to make the test pass, please check if you
|
||||
need to adjust this doc as well and ping this issue:
|
||||
|
Loading…
x
Reference in New Issue
Block a user