1 //! Conversion lsp_types types to rust-analyzer specific ones.
2 use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16};
3 use ide_db::base_db::{FileId, FilePosition, FileRange};
4 use syntax::{TextRange, TextSize};
5 use vfs::AbsPathBuf;
6 
7 use crate::{
8     from_json,
9     global_state::GlobalStateSnapshot,
10     line_index::{LineIndex, OffsetEncoding},
11     lsp_ext,
12     lsp_utils::invalid_params_error,
13     Result,
14 };
15 
abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf>16 pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
17     let path = url.to_file_path().map_err(|()| "url is not a file")?;
18     Ok(AbsPathBuf::try_from(path).unwrap())
19 }
20 
vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath>21 pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
22     abs_path(url).map(vfs::VfsPath::from)
23 }
24 
offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize25 pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> TextSize {
26     let line_col = match line_index.encoding {
27         OffsetEncoding::Utf8 => {
28             LineCol { line: position.line as u32, col: position.character as u32 }
29         }
30         OffsetEncoding::Utf16 => {
31             let line_col =
32                 LineColUtf16 { line: position.line as u32, col: position.character as u32 };
33             line_index.index.to_utf8(line_col)
34         }
35     };
36     line_index.index.offset(line_col)
37 }
38 
text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange39 pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> TextRange {
40     let start = offset(line_index, range.start);
41     let end = offset(line_index, range.end);
42     TextRange::new(start, end)
43 }
44 
file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId>45 pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
46     snap.url_to_file_id(url)
47 }
48 
file_position( snap: &GlobalStateSnapshot, tdpp: lsp_types::TextDocumentPositionParams, ) -> Result<FilePosition>49 pub(crate) fn file_position(
50     snap: &GlobalStateSnapshot,
51     tdpp: lsp_types::TextDocumentPositionParams,
52 ) -> Result<FilePosition> {
53     let file_id = file_id(snap, &tdpp.text_document.uri)?;
54     let line_index = snap.file_line_index(file_id)?;
55     let offset = offset(&line_index, tdpp.position);
56     Ok(FilePosition { file_id, offset })
57 }
58 
file_range( snap: &GlobalStateSnapshot, text_document_identifier: lsp_types::TextDocumentIdentifier, range: lsp_types::Range, ) -> Result<FileRange>59 pub(crate) fn file_range(
60     snap: &GlobalStateSnapshot,
61     text_document_identifier: lsp_types::TextDocumentIdentifier,
62     range: lsp_types::Range,
63 ) -> Result<FileRange> {
64     let file_id = file_id(snap, &text_document_identifier.uri)?;
65     let line_index = snap.file_line_index(file_id)?;
66     let range = text_range(&line_index, range);
67     Ok(FileRange { file_id, range })
68 }
69 
assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind>70 pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
71     let assist_kind = match &kind {
72         k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None,
73         k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix,
74         k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor,
75         k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract,
76         k if k == &lsp_types::CodeActionKind::REFACTOR_INLINE => AssistKind::RefactorInline,
77         k if k == &lsp_types::CodeActionKind::REFACTOR_REWRITE => AssistKind::RefactorRewrite,
78         _ => return None,
79     };
80 
81     Some(assist_kind)
82 }
83 
annotation( snap: &GlobalStateSnapshot, code_lens: lsp_types::CodeLens, ) -> Result<Annotation>84 pub(crate) fn annotation(
85     snap: &GlobalStateSnapshot,
86     code_lens: lsp_types::CodeLens,
87 ) -> Result<Annotation> {
88     let data =
89         code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?;
90     let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", data)?;
91 
92     match resolve {
93         lsp_ext::CodeLensResolveData::Impls(params) => {
94             let file_id =
95                 snap.url_to_file_id(&params.text_document_position_params.text_document.uri)?;
96             let line_index = snap.file_line_index(file_id)?;
97 
98             Ok(Annotation {
99                 range: text_range(&line_index, code_lens.range),
100                 kind: AnnotationKind::HasImpls {
101                     position: file_position(snap, params.text_document_position_params)?,
102                     data: None,
103                 },
104             })
105         }
106         lsp_ext::CodeLensResolveData::References(params) => {
107             let file_id = snap.url_to_file_id(&params.text_document.uri)?;
108             let line_index = snap.file_line_index(file_id)?;
109 
110             Ok(Annotation {
111                 range: text_range(&line_index, code_lens.range),
112                 kind: AnnotationKind::HasReferences {
113                     position: file_position(snap, params)?,
114                     data: None,
115                 },
116             })
117         }
118     }
119 }
120