move effective caps
This commit is contained in:
parent
3410652c71
commit
6f69765172
3 changed files with 106 additions and 84 deletions
90
crates/lsp/src/capabilities.rs
Normal file
90
crates/lsp/src/capabilities.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use super::DynamicCapabilities;
|
||||||
|
use lsp_types::{
|
||||||
|
ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
|
||||||
|
TextDocumentSyncSaveOptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod cap {
|
||||||
|
pub struct DidChangeTextDocument;
|
||||||
|
pub struct DidSaveTextDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait EffectiveCapability {
|
||||||
|
type Value;
|
||||||
|
fn compute(static_caps: &ServerCapabilities, dynamic_caps: &DynamicCapabilities)
|
||||||
|
-> Self::Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EffectiveCapability for cap::DidChangeTextDocument {
|
||||||
|
type Value = Option<TextDocumentSyncKind>;
|
||||||
|
|
||||||
|
fn compute(
|
||||||
|
static_caps: &ServerCapabilities,
|
||||||
|
dynamic_caps: &DynamicCapabilities,
|
||||||
|
) -> Self::Value {
|
||||||
|
dynamic_caps
|
||||||
|
.text_document_sync_did_change
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|id_to_sync_kind_map| {
|
||||||
|
if id_to_sync_kind_map.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut best: Option<TextDocumentSyncKind> = None;
|
||||||
|
for kind in id_to_sync_kind_map.values() {
|
||||||
|
best = Some(match (best, kind) {
|
||||||
|
(None, kind) => *kind,
|
||||||
|
(
|
||||||
|
Some(TextDocumentSyncKind::FULL),
|
||||||
|
&TextDocumentSyncKind::INCREMENTAL,
|
||||||
|
) => TextDocumentSyncKind::INCREMENTAL,
|
||||||
|
(Some(kind), _) => kind,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
best
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
static_caps
|
||||||
|
.text_document_sync
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|sync| match sync {
|
||||||
|
TextDocumentSyncCapability::Kind(kind) => Some(*kind),
|
||||||
|
TextDocumentSyncCapability::Options(opts) => opts.change,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EffectiveCapability for cap::DidSaveTextDocument {
|
||||||
|
type Value = Option<bool>;
|
||||||
|
|
||||||
|
fn compute(
|
||||||
|
static_caps: &ServerCapabilities,
|
||||||
|
dynamic_caps: &DynamicCapabilities,
|
||||||
|
) -> Self::Value {
|
||||||
|
dynamic_caps
|
||||||
|
.text_document_sync_did_save
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|id_to_save_options_map| {
|
||||||
|
if id_to_save_options_map.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
id_to_save_options_map
|
||||||
|
.values()
|
||||||
|
.any(|opts| opts.include_text.unwrap_or(false)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| match static_caps.text_document_sync.as_ref()? {
|
||||||
|
TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
|
||||||
|
TextDocumentSyncSaveOptions::Supported(true) => Some(false),
|
||||||
|
TextDocumentSyncSaveOptions::Supported(false) => None,
|
||||||
|
TextDocumentSyncSaveOptions::SaveOptions(save_opts) => {
|
||||||
|
Some(save_opts.include_text.unwrap_or(false))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TextDocumentSyncCapability::Kind(_) => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,8 @@
|
||||||
|
mod capabilities;
|
||||||
mod input_handler;
|
mod input_handler;
|
||||||
|
|
||||||
|
pub use capabilities::{EffectiveCapability, cap};
|
||||||
|
|
||||||
pub use lsp_types::request::*;
|
pub use lsp_types::request::*;
|
||||||
pub use lsp_types::*;
|
pub use lsp_types::*;
|
||||||
|
|
||||||
|
@ -308,15 +311,6 @@ pub struct DynamicCapabilities {
|
||||||
pub text_document_sync_did_save: Option<HashMap<String, SaveOptions>>,
|
pub text_document_sync_did_save: Option<HashMap<String, SaveOptions>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Effective text document synchronization behavior, merging static and dynamic capabilities.
|
|
||||||
#[derive(Debug, Default, Clone)]
|
|
||||||
pub struct EffectiveTextDocumentSync {
|
|
||||||
/// Effective change sync kind (FULL or INCREMENTAL), if any.
|
|
||||||
pub change: Option<TextDocumentSyncKind>,
|
|
||||||
/// Whether to include text on didSave, or None if didSave is not supported.
|
|
||||||
pub save_include_text: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LanguageServer {
|
impl LanguageServer {
|
||||||
/// Starts a language server process.
|
/// Starts a language server process.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -1150,74 +1144,14 @@ impl LanguageServer {
|
||||||
self.static_capabilities.read().clone()
|
self.static_capabilities.read().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dynamic_capabilities(&self) -> DynamicCapabilities {
|
|
||||||
self.dynamic_capabilities.read().clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_dynamic_capabilities(&self, update: impl FnOnce(&mut DynamicCapabilities)) {
|
pub fn update_dynamic_capabilities(&self, update: impl FnOnce(&mut DynamicCapabilities)) {
|
||||||
update(self.dynamic_capabilities.write().deref_mut());
|
update(self.dynamic_capabilities.write().deref_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn effective_text_document_sync(&self) -> EffectiveTextDocumentSync {
|
pub fn effective_capability<Cap: EffectiveCapability>(&self) -> Cap::Value {
|
||||||
let static_caps = self.capabilities();
|
let static_capabilities = self.capabilities();
|
||||||
let dyn_caps = self.dynamic_capabilities();
|
let dynamic_capabilities = self.dynamic_capabilities.read().clone();
|
||||||
|
Cap::compute(&static_capabilities, &dynamic_capabilities)
|
||||||
let change = dyn_caps
|
|
||||||
.text_document_sync_did_change
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|m| {
|
|
||||||
if m.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let mut best: Option<TextDocumentSyncKind> = None;
|
|
||||||
for kind in m.values() {
|
|
||||||
best = Some(match (best, kind) {
|
|
||||||
(None, k) => *k,
|
|
||||||
(
|
|
||||||
Some(TextDocumentSyncKind::FULL),
|
|
||||||
&TextDocumentSyncKind::INCREMENTAL,
|
|
||||||
) => TextDocumentSyncKind::INCREMENTAL,
|
|
||||||
(Some(curr), _) => curr,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
best
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
static_caps
|
|
||||||
.text_document_sync
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|sync| match sync {
|
|
||||||
TextDocumentSyncCapability::Kind(kind) => Some(*kind),
|
|
||||||
TextDocumentSyncCapability::Options(options) => options.change,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let save_include_text = dyn_caps
|
|
||||||
.text_document_sync_did_save
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|m| {
|
|
||||||
if m.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(m.values().any(|opts| opts.include_text.unwrap_or(false)))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_else(|| match static_caps.text_document_sync.as_ref()? {
|
|
||||||
TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
|
|
||||||
TextDocumentSyncSaveOptions::Supported(true) => Some(false),
|
|
||||||
TextDocumentSyncSaveOptions::Supported(false) => None,
|
|
||||||
TextDocumentSyncSaveOptions::SaveOptions(save_opts) => {
|
|
||||||
Some(save_opts.include_text.unwrap_or(false))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TextDocumentSyncCapability::Kind(_) => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
EffectiveTextDocumentSync {
|
|
||||||
change,
|
|
||||||
save_include_text,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the reported capabilities of the running language server and
|
/// Get the reported capabilities of the running language server and
|
||||||
|
|
|
@ -74,9 +74,8 @@ use lsp::{
|
||||||
FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
|
FileOperationPatternKind, FileOperationRegistrationOptions, FileRename, FileSystemWatcher,
|
||||||
LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
|
LSP_REQUEST_TIMEOUT, LanguageServer, LanguageServerBinary, LanguageServerBinaryOptions,
|
||||||
LanguageServerId, LanguageServerName, LanguageServerSelector, LspRequestFuture,
|
LanguageServerId, LanguageServerName, LanguageServerSelector, LspRequestFuture,
|
||||||
MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind,
|
MessageActionItem, MessageType, OneOf, RenameFilesParams, SymbolKind, TextEdit,
|
||||||
TextEdit, WillRenameFiles, WorkDoneProgressCancelParams,
|
WillRenameFiles, WorkDoneProgressCancelParams, WorkspaceFolder, notification::DidRenameFiles,
|
||||||
WorkspaceFolder, notification::DidRenameFiles,
|
|
||||||
};
|
};
|
||||||
use node_runtime::read_package_installed_version;
|
use node_runtime::read_package_installed_version;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
@ -7208,9 +7207,8 @@ impl LspStore {
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let document_sync_kind = language_server
|
let document_sync_kind =
|
||||||
.effective_text_document_sync()
|
language_server.effective_capability::<lsp::cap::DidChangeTextDocument>();
|
||||||
.change;
|
|
||||||
|
|
||||||
let content_changes: Vec<_> = match document_sync_kind {
|
let content_changes: Vec<_> = match document_sync_kind {
|
||||||
Some(lsp::TextDocumentSyncKind::FULL) => {
|
Some(lsp::TextDocumentSyncKind::FULL) => {
|
||||||
|
@ -7271,7 +7269,9 @@ impl LspStore {
|
||||||
let local = self.as_local()?;
|
let local = self.as_local()?;
|
||||||
|
|
||||||
for server in local.language_servers_for_worktree(worktree_id) {
|
for server in local.language_servers_for_worktree(worktree_id) {
|
||||||
if let Some(include_text) = server.effective_text_document_sync().save_include_text {
|
if let Some(include_text) =
|
||||||
|
server.effective_capability::<lsp::cap::DidSaveTextDocument>()
|
||||||
|
{
|
||||||
let text = if include_text {
|
let text = if include_text {
|
||||||
Some(buffer.read(cx).text())
|
Some(buffer.read(cx).text())
|
||||||
} else {
|
} else {
|
||||||
|
@ -11842,7 +11842,7 @@ impl LspStore {
|
||||||
let map = dyn_caps
|
let map = dyn_caps
|
||||||
.text_document_sync_did_change
|
.text_document_sync_did_change
|
||||||
.get_or_insert_with(HashMap::default);
|
.get_or_insert_with(HashMap::default);
|
||||||
map.insert(reg.id.clone(), sync_kind);
|
map.insert(reg.id, sync_kind);
|
||||||
});
|
});
|
||||||
notify_server_capabilities_updated(&server, cx);
|
notify_server_capabilities_updated(&server, cx);
|
||||||
}
|
}
|
||||||
|
@ -11867,7 +11867,7 @@ impl LspStore {
|
||||||
let map = dyn_caps
|
let map = dyn_caps
|
||||||
.text_document_sync_did_save
|
.text_document_sync_did_save
|
||||||
.get_or_insert_with(HashMap::default);
|
.get_or_insert_with(HashMap::default);
|
||||||
map.insert(reg.id.clone(), lsp::SaveOptions { include_text });
|
map.insert(reg.id, lsp::SaveOptions { include_text });
|
||||||
});
|
});
|
||||||
notify_server_capabilities_updated(&server, cx);
|
notify_server_capabilities_updated(&server, cx);
|
||||||
}
|
}
|
||||||
|
@ -13253,8 +13253,6 @@ async fn populate_labels_for_symbols(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// include_text logic moved into lsp::LanguageServer::effective_text_document_sync()
|
|
||||||
|
|
||||||
/// Completion items are displayed in a `UniformList`.
|
/// Completion items are displayed in a `UniformList`.
|
||||||
/// Usually, those items are single-line strings, but in LSP responses,
|
/// Usually, those items are single-line strings, but in LSP responses,
|
||||||
/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
|
/// completion items `label`, `detail` and `label_details.description` may contain newlines or long spaces.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue