capabilities.rs

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