aboutsummaryrefslogtreecommitdiff
path: root/crates/server/src/handlers.rs
blob: 8b7e00c9280b17ddc86c2b2760dc6071b99182c9 (plain)
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
use url::Url;
use languageserver_types::{Range, Position, Diagnostic, DiagnosticSeverity};
use libanalysis::World;
use libeditor::{self, LineIndex, LineCol, TextRange, TextUnit};

use ::{
    req::{self, Decoration}, Result,
    util::FilePath,
};

pub fn handle_syntax_tree(
    world: World,
    params: req::SyntaxTreeParams,
) -> Result<String> {
    let path = params.text_document.file_path()?;
    let file = world.file_syntax(&path)?;
    Ok(libeditor::syntax_tree(&file))
}

pub fn handle_extend_selection(
    world: World,
    params: req::ExtendSelectionParams,
) -> Result<req::ExtendSelectionResult> {
    let path = params.text_document.file_path()?;
    let file = world.file_syntax(&path)?;
    let line_index = world.file_line_index(&path)?;
    let selections = params.selections.into_iter()
        .map(|r| {
            let r = to_text_range(&line_index, r);
            let r = libeditor::extend_selection(&file, r).unwrap_or(r);
            to_vs_range(&line_index, r)
        })
        .collect();
    Ok(req::ExtendSelectionResult { selections })
}

pub fn publish_diagnostics(world: World, uri: Url) -> Result<req::PublishDiagnosticsParams> {
    let path = uri.file_path()?;
    let file = world.file_syntax(&path)?;
    let line_index = world.file_line_index(&path)?;
    let diagnostics = libeditor::diagnostics(&file)
        .into_iter()
        .map(|d| Diagnostic {
            range: to_vs_range(&line_index, d.range),
            severity: Some(DiagnosticSeverity::Error),
            code: None,
            source: Some("libsyntax2".to_string()),
            message: d.msg,
            related_information: None,
        }).collect();
    Ok(req::PublishDiagnosticsParams { uri, diagnostics })
}

pub fn publish_decorations(world: World, uri: Url) -> Result<req::PublishDecorationsParams> {
    let path = uri.file_path()?;
    let file = world.file_syntax(&path)?;
    let line_index = world.file_line_index(&path)?;
    let decorations = libeditor::highlight(&file)
        .into_iter()
        .map(|h| Decoration {
            range: to_vs_range(&line_index, h.range),
            tag: h.tag,
        }).collect();
    Ok(req::PublishDecorationsParams { uri, decorations })
}

fn to_text_range(line_index: &LineIndex, range: Range) -> TextRange {
    TextRange::from_to(
        to_text_unit(line_index, range.start),
        to_text_unit(line_index, range.end),
    )
}

fn to_text_unit(line_index: &LineIndex, position: Position) -> TextUnit {
    // TODO: UTF-16
    let line_col = LineCol {
        line: position.line as u32,
        col: (position.character as u32).into(),
    };
    line_index.offset(line_col)
}


fn to_vs_range(line_index: &LineIndex, range: TextRange) -> Range {
    Range::new(
        to_vs_position(line_index, range.start()),
        to_vs_position(line_index, range.end()),
    )
}

fn to_vs_position(line_index: &LineIndex, offset: TextUnit) -> Position {
    let line_col = line_index.line_col(offset);
    // TODO: UTF-16
    Position::new(line_col.line as u64, u32::from(line_col.col) as u64)
}