capabilities.rs

 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}