aboutsummaryrefslogtreecommitdiff
path: root/crates/rust-analyzer/src/from_proto.rs
blob: 712d5a9c277736e87205f3704d5647cc6f98c41d (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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Conversion lsp_types types to rust-analyzer specific ones.
use std::convert::TryFrom;

use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16};
use ide_db::base_db::{FileId, FilePosition, FileRange};
use syntax::{TextRange, TextSize};
use vfs::AbsPathBuf;

use crate::{
    from_json,
    global_state::GlobalStateSnapshot,
    line_index::{LineIndex, OffsetEncoding},
    lsp_ext, Result,
};

pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
    let path = url.to_file_path().map_err(|()| "url is not a file")?;
    Ok(AbsPathBuf::try_from(path).unwrap())
}

pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
    abs_path(url).map(vfs::VfsPath::from)
}

pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize {
    let line_col = match line_index.encoding {
        OffsetEncoding::Utf8 => {
            LineCol { line: position.line as u32, col: position.character as u32 }
        }
        OffsetEncoding::Utf16 => {
            let line_col =
                LineColUtf16 { line: position.line as u32, col: position.character as u32 };
            line_index.index.to_utf8(line_col)
        }
    };
    line_index.index.offset(line_col)
}

pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange {
    let start = offset(line_index, range.start);
    let end = offset(line_index, range.end);
    TextRange::new(start, end)
}

pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
    snap.url_to_file_id(url)
}

pub(crate) fn file_position(
    snap: &GlobalStateSnapshot,
    tdpp: lsp_types::TextDocumentPositionParams,
) -> Result<FilePosition> {
    let file_id = file_id(snap, &tdpp.text_document.uri)?;
    let line_index = snap.file_line_index(file_id)?;
    let offset = offset(&line_index, tdpp.position);
    Ok(FilePosition { file_id, offset })
}

pub(crate) fn file_range(
    snap: &GlobalStateSnapshot,
    text_document_identifier: lsp_types::TextDocumentIdentifier,
    range: lsp_types::Range,
) -> Result<FileRange> {
    let file_id = file_id(snap, &text_document_identifier.uri)?;
    let line_index = snap.file_line_index(file_id)?;
    let range = text_range(&line_index, range);
    Ok(FileRange { file_id, range })
}

pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
    let assist_kind = match &kind {
        k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None,
        k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor,
        k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract,
        k if k == &lsp_types::CodeActionKind::REFACTOR_INLINE => AssistKind::RefactorInline,
        k if k == &lsp_types::CodeActionKind::REFACTOR_REWRITE => AssistKind::RefactorRewrite,
        _ => return None,
    };

    Some(assist_kind)
}

pub(crate) fn annotation(
    snap: &GlobalStateSnapshot,
    code_lens: lsp_types::CodeLens,
) -> Result<Annotation> {
    let data = code_lens.data.unwrap();
    let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", data)?;

    match resolve {
        lsp_ext::CodeLensResolveData::Impls(params) => {
            let file_id =
                snap.url_to_file_id(&params.text_document_position_params.text_document.uri)?;
            let line_index = snap.file_line_index(file_id)?;

            Ok(Annotation {
                range: text_range(&line_index, code_lens.range),
                kind: AnnotationKind::HasImpls {
                    position: file_position(snap, params.text_document_position_params)?,
                    data: None,
                },
            })
        }
        lsp_ext::CodeLensResolveData::References(params) => {
            let file_id = snap.url_to_file_id(&params.text_document.uri)?;
            let line_index = snap.file_line_index(file_id)?;

            Ok(Annotation {
                range: text_range(&line_index, code_lens.range),
                kind: AnnotationKind::HasReferences {
                    position: file_position(snap, params)?,
                    data: None,
                },
            })
        }
    }
}