1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::sync::Arc;

use crate::handler::SyncNotificationHandler;
use crate::model::Document;
use crate::session::State;
use crate::watcher::DocumentWatcher;

pub struct DidOpenTextDocumentHandler;

impl SyncNotificationHandler for DidOpenTextDocumentHandler {
    type Notification = lsp_types::notification::DidOpenTextDocument;

    fn handle(state: &mut State, params: lsp_types::DidOpenTextDocumentParams) {
        let text_document = params.text_document;

        let document = Arc::new(Document::new(text_document.version, text_document.text));

        state.syntax_watcher.did_open(&text_document.uri, &document);

        state
            .documents
            .insert(text_document.uri.to_string(), document);
    }
}

pub struct DidChangeTextDocumentHandler;

impl SyncNotificationHandler for DidChangeTextDocumentHandler {
    type Notification = lsp_types::notification::DidChangeTextDocument;

    fn handle(state: &mut State, params: lsp_types::DidChangeTextDocumentParams) {
        let lsp_types::DidChangeTextDocumentParams {
            text_document,
            content_changes,
        } = params;

        let orig_document =
            if let Some(document) = state.documents.remove(text_document.uri.as_str()) {
                document
            } else {
                eprintln!(
                    "Received change notification for unknown document {}",
                    text_document.uri
                );
                return;
            };

        let new_document =
            content_changes
                .into_iter()
                .fold(
                    orig_document,
                    |prev_document, content_change| match content_change.range {
                        Some(range) => {
                            match prev_document.with_range_edit(
                                text_document.version,
                                range,
                                &content_change.text,
                            ) {
                                Ok(new_document) => Arc::new(new_document),
                                Err(()) => {
                                    eprintln!(
                                        "Could not find range to replace in {}",
                                        text_document.uri
                                    );

                                    prev_document
                                }
                            }
                        }
                        None => Arc::new(Document::new(text_document.version, content_change.text)),
                    },
                );

        state
            .syntax_watcher
            .did_change(&text_document.uri, &new_document);

        state
            .documents
            .insert(text_document.uri.to_string(), new_document);
    }
}

pub struct DidCloseTextDocumentHandler;

impl SyncNotificationHandler for DidCloseTextDocumentHandler {
    type Notification = lsp_types::notification::DidCloseTextDocument;

    fn handle(state: &mut State, params: lsp_types::DidCloseTextDocumentParams) {
        let text_document = params.text_document;

        state.documents.remove(text_document.uri.as_str());
        state.syntax_watcher.did_close(&text_document.uri);
    }
}