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                    None
31                } else {
32                    let mut best: Option<TextDocumentSyncKind> = None;
33                    for kind in id_to_sync_kind_map.values() {
34                        best = Some(match (best, kind) {
35                            (None, kind) => *kind,
36                            (
37                                Some(TextDocumentSyncKind::FULL),
38                                &TextDocumentSyncKind::INCREMENTAL,
39                            ) => TextDocumentSyncKind::INCREMENTAL,
40                            (Some(kind), _) => kind,
41                        });
42                    }
43                    best
44                }
45            })
46            .or_else(|| {
47                static_caps
48                    .text_document_sync
49                    .as_ref()
50                    .and_then(|sync| match sync {
51                        TextDocumentSyncCapability::Kind(kind) => Some(*kind),
52                        TextDocumentSyncCapability::Options(opts) => opts.change,
53                    })
54            })
55    }
56}
57
58impl EffectiveCapability for cap::DidSaveTextDocument {
59    type Value = Option<bool>;
60
61    fn compute(
62        static_caps: &ServerCapabilities,
63        dynamic_caps: &DynamicCapabilities,
64    ) -> Self::Value {
65        dynamic_caps
66            .text_document_sync_did_save
67            .as_ref()
68            .and_then(|id_to_save_options_map| {
69                if id_to_save_options_map.is_empty() {
70                    None
71                } else {
72                    Some(
73                        id_to_save_options_map
74                            .values()
75                            .any(|opts| opts.include_text.unwrap_or(false)),
76                    )
77                }
78            })
79            .or_else(|| match static_caps.text_document_sync.as_ref()? {
80                TextDocumentSyncCapability::Options(opts) => match opts.save.as_ref()? {
81                    TextDocumentSyncSaveOptions::Supported(true) => Some(false),
82                    TextDocumentSyncSaveOptions::Supported(false) => None,
83                    TextDocumentSyncSaveOptions::SaveOptions(save_opts) => {
84                        Some(save_opts.include_text.unwrap_or(false))
85                    }
86                },
87                TextDocumentSyncCapability::Kind(_) => None,
88            })
89    }
90}