1use lsp_types::{
2 ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
3 TextDocumentSyncSaveOptions,
4};
5
6use super::DynamicCapabilities;
7
8pub mod cap {
9 pub struct DidChangeTextDocument;
10 pub struct DidSaveTextDocument;
11}
12
13pub trait EffectiveCapability {
14 type Value;
15 fn compute(static_caps: &ServerCapabilities, dynamic_caps: &DynamicCapabilities)
16 -> Self::Value;
17}
18
19impl EffectiveCapability for cap::DidChangeTextDocument {
20 type Value = Option<TextDocumentSyncKind>;
21
22 fn compute(
23 static_caps: &ServerCapabilities,
24 dynamic_caps: &DynamicCapabilities,
25 ) -> Self::Value {
26 dynamic_caps
27 .text_document_sync_did_change
28 .as_ref()
29 .and_then(|id_to_sync_kind_map| {
30 if id_to_sync_kind_map.is_empty() {
31 return None;
32 }
33 let mut has_incremental = false;
34 for data in id_to_sync_kind_map.values() {
35 let sync_kind = match data.sync_kind {
36 0 => Some(TextDocumentSyncKind::NONE),
37 1 => Some(TextDocumentSyncKind::FULL),
38 2 => Some(TextDocumentSyncKind::INCREMENTAL),
39 _ => None,
40 };
41 if sync_kind == Some(TextDocumentSyncKind::FULL) {
42 return Some(TextDocumentSyncKind::FULL);
43 }
44 if sync_kind == Some(TextDocumentSyncKind::INCREMENTAL) {
45 has_incremental = true;
46 }
47 }
48 if has_incremental {
49 Some(TextDocumentSyncKind::INCREMENTAL)
50 } else {
51 None
52 }
53 })
54 .or_else(|| {
55 static_caps
56 .text_document_sync
57 .as_ref()
58 .and_then(|sync| match sync {
59 TextDocumentSyncCapability::Kind(kind) => Some(*kind),
60 TextDocumentSyncCapability::Options(opts) => opts.change,
61 })
62 })
63 }
64}
65
66impl EffectiveCapability for cap::DidSaveTextDocument {
67 type Value = Option<bool>;
68
69 fn compute(
70 static_caps: &ServerCapabilities,
71 dynamic_caps: &DynamicCapabilities,
72 ) -> Self::Value {
73 dynamic_caps
74 .text_document_sync_did_save
75 .as_ref()
76 .and_then(|id_to_save_options_map| {
77 if id_to_save_options_map.is_empty() {
78 None
79 } else {
80 Some(
81 id_to_save_options_map
82 .values()
83 .any(|data| data.include_text.unwrap_or(false)),
84 )
85 }
86 })
87 .or_else(|| match static_caps.text_document_sync.as_ref()? {
88 TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
89 TextDocumentSyncSaveOptions::Supported(true) => Some(false),
90 TextDocumentSyncSaveOptions::Supported(false) => None,
91 TextDocumentSyncSaveOptions::SaveOptions(save_opts) => {
92 Some(save_opts.include_text.unwrap_or(false))
93 }
94 },
95 TextDocumentSyncCapability::Kind(_) => None,
96 })
97 }
98}