text document sync dynamic caps
This commit is contained in:
parent
7684bc265b
commit
0617098175
2 changed files with 75 additions and 33 deletions
|
@ -87,6 +87,7 @@ pub struct LanguageServer {
|
||||||
process_name: Arc<str>,
|
process_name: Arc<str>,
|
||||||
binary: LanguageServerBinary,
|
binary: LanguageServerBinary,
|
||||||
static_capabilities: RwLock<ServerCapabilities>,
|
static_capabilities: RwLock<ServerCapabilities>,
|
||||||
|
dynamic_capabilities: RwLock<DynamicCapabilities>,
|
||||||
/// Configuration sent to the server, stored for display in the language server logs
|
/// Configuration sent to the server, stored for display in the language server logs
|
||||||
/// buffer. This is represented as the message sent to the LSP in order to avoid cloning it (can
|
/// buffer. This is represented as the message sent to the LSP in order to avoid cloning it (can
|
||||||
/// be large in cases like sending schemas to the json server).
|
/// be large in cases like sending schemas to the json server).
|
||||||
|
@ -301,6 +302,12 @@ pub struct AdapterServerCapabilities {
|
||||||
pub code_action_kinds: Option<Vec<CodeActionKind>>,
|
pub code_action_kinds: Option<Vec<CodeActionKind>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct DynamicCapabilities {
|
||||||
|
pub text_document_sync_did_change: Option<HashMap<String, TextDocumentSyncKind>>,
|
||||||
|
pub text_document_sync_did_save: Option<HashMap<String, SaveOptions>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl LanguageServer {
|
impl LanguageServer {
|
||||||
/// Starts a language server process.
|
/// Starts a language server process.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -485,6 +492,7 @@ impl LanguageServer {
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
binary,
|
binary,
|
||||||
static_capabilities: Default::default(),
|
static_capabilities: Default::default(),
|
||||||
|
dynamic_capabilities: Default::default(),
|
||||||
configuration,
|
configuration,
|
||||||
code_action_kinds,
|
code_action_kinds,
|
||||||
next_id: Default::default(),
|
next_id: Default::default(),
|
||||||
|
@ -1133,6 +1141,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)) {
|
||||||
|
update(self.dynamic_capabilities.write().deref_mut());
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the reported capabilities of the running language server and
|
/// Get the reported capabilities of the running language server and
|
||||||
/// what we know on the client/adapter-side of its capabilities.
|
/// what we know on the client/adapter-side of its capabilities.
|
||||||
pub fn adapter_server_capabilities(&self) -> AdapterServerCapabilities {
|
pub fn adapter_server_capabilities(&self) -> AdapterServerCapabilities {
|
||||||
|
|
|
@ -7208,14 +7208,40 @@ impl LspStore {
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
let document_sync_kind = language_server
|
let document_sync_kind = {
|
||||||
.capabilities()
|
let dyn_caps = language_server.dynamic_capabilities();
|
||||||
.text_document_sync
|
let dynamic = dyn_caps
|
||||||
.as_ref()
|
.text_document_sync_did_change
|
||||||
.and_then(|sync| match sync {
|
.as_ref()
|
||||||
lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
|
.and_then(|m| {
|
||||||
lsp::TextDocumentSyncCapability::Options(options) => options.change,
|
if m.is_empty() {
|
||||||
});
|
None
|
||||||
|
} else {
|
||||||
|
let mut best: Option<lsp::TextDocumentSyncKind> = None;
|
||||||
|
for kind in m.values() {
|
||||||
|
best = Some(match (best, kind) {
|
||||||
|
(None, k) => *k,
|
||||||
|
(
|
||||||
|
Some(lsp::TextDocumentSyncKind::FULL),
|
||||||
|
lsp::TextDocumentSyncKind::INCREMENTAL,
|
||||||
|
) => lsp::TextDocumentSyncKind::INCREMENTAL,
|
||||||
|
(Some(curr), _) => curr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
best
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dynamic.or_else(|| {
|
||||||
|
language_server
|
||||||
|
.capabilities()
|
||||||
|
.text_document_sync
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|sync| match sync {
|
||||||
|
lsp::TextDocumentSyncCapability::Kind(kind) => Some(*kind),
|
||||||
|
lsp::TextDocumentSyncCapability::Options(options) => options.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) => {
|
||||||
|
@ -11843,12 +11869,11 @@ impl LspStore {
|
||||||
.map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
|
.map(serde_json::from_value::<lsp::TextDocumentSyncKind>)
|
||||||
.transpose()?
|
.transpose()?
|
||||||
{
|
{
|
||||||
server.update_capabilities(|capabilities| {
|
server.update_dynamic_capabilities(|dyn_caps| {
|
||||||
let mut sync_options =
|
let map = dyn_caps
|
||||||
Self::take_text_document_sync_options(capabilities);
|
.text_document_sync_did_change
|
||||||
sync_options.change = Some(sync_kind);
|
.get_or_insert_with(HashMap::default);
|
||||||
capabilities.text_document_sync =
|
map.insert(reg.id.clone(), sync_kind);
|
||||||
Some(lsp::TextDocumentSyncCapability::Options(sync_options));
|
|
||||||
});
|
});
|
||||||
notify_server_capabilities_updated(&server, cx);
|
notify_server_capabilities_updated(&server, cx);
|
||||||
}
|
}
|
||||||
|
@ -11869,15 +11894,11 @@ impl LspStore {
|
||||||
})
|
})
|
||||||
.transpose()?
|
.transpose()?
|
||||||
{
|
{
|
||||||
server.update_capabilities(|capabilities| {
|
server.update_dynamic_capabilities(|dyn_caps| {
|
||||||
let mut sync_options =
|
let map = dyn_caps
|
||||||
Self::take_text_document_sync_options(capabilities);
|
.text_document_sync_did_save
|
||||||
sync_options.save =
|
.get_or_insert_with(HashMap::default);
|
||||||
Some(TextDocumentSyncSaveOptions::SaveOptions(lsp::SaveOptions {
|
map.insert(reg.id.clone(), lsp::SaveOptions { include_text });
|
||||||
include_text,
|
|
||||||
}));
|
|
||||||
capabilities.text_document_sync =
|
|
||||||
Some(lsp::TextDocumentSyncCapability::Options(sync_options));
|
|
||||||
});
|
});
|
||||||
notify_server_capabilities_updated(&server, cx);
|
notify_server_capabilities_updated(&server, cx);
|
||||||
}
|
}
|
||||||
|
@ -12028,20 +12049,18 @@ impl LspStore {
|
||||||
notify_server_capabilities_updated(&server, cx);
|
notify_server_capabilities_updated(&server, cx);
|
||||||
}
|
}
|
||||||
"textDocument/didChange" => {
|
"textDocument/didChange" => {
|
||||||
server.update_capabilities(|capabilities| {
|
server.update_dynamic_capabilities(|dyn_caps| {
|
||||||
let mut sync_options = Self::take_text_document_sync_options(capabilities);
|
if let Some(map) = dyn_caps.text_document_sync_did_change.as_mut() {
|
||||||
sync_options.change = None;
|
map.remove(&unreg.id);
|
||||||
capabilities.text_document_sync =
|
}
|
||||||
Some(lsp::TextDocumentSyncCapability::Options(sync_options));
|
|
||||||
});
|
});
|
||||||
notify_server_capabilities_updated(&server, cx);
|
notify_server_capabilities_updated(&server, cx);
|
||||||
}
|
}
|
||||||
"textDocument/didSave" => {
|
"textDocument/didSave" => {
|
||||||
server.update_capabilities(|capabilities| {
|
server.update_dynamic_capabilities(|dyn_caps| {
|
||||||
let mut sync_options = Self::take_text_document_sync_options(capabilities);
|
if let Some(map) = dyn_caps.text_document_sync_did_save.as_mut() {
|
||||||
sync_options.save = None;
|
map.remove(&unreg.id);
|
||||||
capabilities.text_document_sync =
|
}
|
||||||
Some(lsp::TextDocumentSyncCapability::Options(sync_options));
|
|
||||||
});
|
});
|
||||||
notify_server_capabilities_updated(&server, cx);
|
notify_server_capabilities_updated(&server, cx);
|
||||||
}
|
}
|
||||||
|
@ -13266,6 +13285,13 @@ async fn populate_labels_for_symbols(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
|
fn include_text(server: &lsp::LanguageServer) -> Option<bool> {
|
||||||
|
let dyn_caps = server.dynamic_capabilities();
|
||||||
|
if let Some(map) = dyn_caps.text_document_sync_did_save.as_ref() {
|
||||||
|
if !map.is_empty() {
|
||||||
|
let any_true = map.values().any(|opts| opts.include_text.unwrap_or(false));
|
||||||
|
return Some(any_true);
|
||||||
|
}
|
||||||
|
}
|
||||||
match server.capabilities().text_document_sync.as_ref()? {
|
match server.capabilities().text_document_sync.as_ref()? {
|
||||||
lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
|
lsp::TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
|
||||||
// Server wants didSave but didn't specify includeText.
|
// Server wants didSave but didn't specify includeText.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue