]> git.lizzy.rs Git - rust.git/blobdiff - crates/rust-analyzer/src/to_proto.rs
Merge #8432
[rust.git] / crates / rust-analyzer / src / to_proto.rs
index 9ca0915b99d0aa5ab78f6a96e32b624799666206..8d7cb9b74cec565188d3342b4f6ac7ca0f83a5a9 100644 (file)
@@ -7,11 +7,10 @@
 use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind,
     CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind,
-    Highlight, HlMod, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat,
-    Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity, SourceChange,
-    TextEdit, TextRange, TextSize,
+    Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind,
+    InsertTextFormat, Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity,
+    SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
-use ide_db::SymbolKind;
 use itertools::Itertools;
 use serde_json::to_value;
 
@@ -63,6 +62,13 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
     }
 }
 
+pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolKind {
+    match kind {
+        StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol),
+        StructureNodeKind::Region => lsp_types::SymbolKind::Namespace,
+    }
+}
+
 pub(crate) fn document_highlight_kind(
     reference_access: ReferenceAccess,
 ) -> lsp_types::DocumentHighlightKind {
@@ -139,6 +145,23 @@ pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::Text
     lsp_types::TextEdit { range, new_text }
 }
 
+pub(crate) fn completion_text_edit(
+    line_index: &LineIndex,
+    insert_replace_support: Option<lsp_types::Position>,
+    indel: Indel,
+) -> lsp_types::CompletionTextEdit {
+    let text_edit = text_edit(line_index, indel);
+    match insert_replace_support {
+        Some(cursor_pos) => lsp_types::InsertReplaceEdit {
+            new_text: text_edit.new_text,
+            insert: lsp_types::Range { start: text_edit.range.start, end: cursor_pos },
+            replace: text_edit.range,
+        }
+        .into(),
+        None => text_edit.into(),
+    }
+}
+
 pub(crate) fn snippet_text_edit(
     line_index: &LineIndex,
     is_snippet: bool,
@@ -173,6 +196,7 @@ pub(crate) fn snippet_text_edit_vec(
 }
 
 pub(crate) fn completion_item(
+    insert_replace_support: Option<lsp_types::Position>,
     line_index: &LineIndex,
     item: CompletionItem,
 ) -> Vec<lsp_types::CompletionItem> {
@@ -184,7 +208,7 @@ pub(crate) fn completion_item(
     for indel in item.text_edit().iter() {
         if indel.delete.contains_range(source_range) {
             text_edit = Some(if indel.delete == source_range {
-                self::text_edit(line_index, indel.clone())
+                self::completion_text_edit(line_index, insert_replace_support, indel.clone())
             } else {
                 assert!(source_range.end() == indel.delete.end());
                 let range1 = TextRange::new(indel.delete.start(), source_range.start());
@@ -192,7 +216,7 @@ pub(crate) fn completion_item(
                 let indel1 = Indel::replace(range1, String::new());
                 let indel2 = Indel::replace(range2, indel.insert.clone());
                 additional_text_edits.push(self::text_edit(line_index, indel1));
-                self::text_edit(line_index, indel2)
+                self::completion_text_edit(line_index, insert_replace_support, indel2)
             })
         } else {
             assert!(source_range.intersect(indel.delete).is_none());
@@ -207,7 +231,7 @@ pub(crate) fn completion_item(
         detail: item.detail().map(|it| it.to_string()),
         filter_text: Some(item.lookup().to_string()),
         kind: item.kind().map(completion_item_kind),
-        text_edit: Some(text_edit.into()),
+        text_edit: Some(text_edit),
         additional_text_edits: Some(additional_text_edits),
         documentation: item.documentation().map(documentation),
         deprecated: Some(item.deprecated()),
@@ -281,7 +305,7 @@ pub(crate) fn signature_help(
             let params = call_info
                 .parameter_ranges()
                 .iter()
-                .map(|it| [u32::from(it.start()).into(), u32::from(it.end()).into()])
+                .map(|it| [u32::from(it.start()), u32::from(it.end())])
                 .map(|label_offsets| lsp_types::ParameterInformation {
                     label: lsp_types::ParameterLabel::LabelOffsets(label_offsets),
                     documentation: None,
@@ -429,19 +453,25 @@ fn semantic_token_type_and_modifiers(
             SymbolKind::Trait => lsp_types::SemanticTokenType::INTERFACE,
             SymbolKind::Macro => lsp_types::SemanticTokenType::MACRO,
         },
+        HlTag::Attribute => semantic_tokens::ATTRIBUTE,
+        HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
         HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
-        HlTag::None => semantic_tokens::GENERIC,
         HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER,
-        HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
-        HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
         HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL,
         HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
-        HlTag::Attribute => semantic_tokens::ATTRIBUTE,
+        HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
+        HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
         HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
+        HlTag::None => semantic_tokens::GENERIC,
+        HlTag::Operator(op) => match op {
+            HlOperator::Bitwise => semantic_tokens::BITWISE,
+            HlOperator::Arithmetic => semantic_tokens::ARITHMETIC,
+            HlOperator::Logical => semantic_tokens::LOGICAL,
+            HlOperator::Comparision => semantic_tokens::COMPARISION,
+            HlOperator::Other => semantic_tokens::OPERATOR,
+        },
+        HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
         HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
-        HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
-        HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR,
-        HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
         HlTag::Punctuation(punct) => match punct {
             HlPunct::Bracket => semantic_tokens::BRACKET,
             HlPunct::Brace => semantic_tokens::BRACE,
@@ -467,6 +497,8 @@ fn semantic_token_type_and_modifiers(
             HlMod::Unsafe => semantic_tokens::UNSAFE,
             HlMod::Callable => semantic_tokens::CALLABLE,
             HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,
+            HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
+            HlMod::Trait => semantic_tokens::TRAIT_MODIFIER,
             HlMod::Associated => continue,
         };
         mods |= modifier;
@@ -484,7 +516,13 @@ pub(crate) fn folding_range(
     let kind = match fold.kind {
         FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
         FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
-        FoldKind::Mods | FoldKind::Block | FoldKind::ArgList | FoldKind::Region => None,
+        FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region),
+        FoldKind::Mods
+        | FoldKind::Block
+        | FoldKind::ArgList
+        | FoldKind::Consts
+        | FoldKind::Statics
+        | FoldKind::Array => None,
     };
 
     let range = range(line_index, fold.range);
@@ -650,6 +688,18 @@ pub(crate) fn goto_definition_response(
     }
 }
 
+pub(crate) fn text_document_edit(
+    snap: &GlobalStateSnapshot,
+    file_id: FileId,
+    edit: TextEdit,
+) -> Result<lsp_types::TextDocumentEdit> {
+    let text_document = optional_versioned_text_document_identifier(snap, file_id);
+    let line_index = snap.file_line_index(file_id)?;
+    let edits =
+        edit.into_iter().map(|it| lsp_types::OneOf::Left(text_edit(&line_index, it))).collect();
+    Ok(lsp_types::TextDocumentEdit { text_document, edits })
+}
+
 pub(crate) fn snippet_text_document_edit(
     snap: &GlobalStateSnapshot,
     is_snippet: bool,
@@ -799,40 +849,31 @@ pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind {
     }
 }
 
-pub(crate) fn unresolved_code_action(
+pub(crate) fn code_action(
     snap: &GlobalStateSnapshot,
-    code_action_params: lsp_types::CodeActionParams,
     assist: Assist,
-    index: usize,
+    resolve_data: Option<(usize, lsp_types::CodeActionParams)>,
 ) -> Result<lsp_ext::CodeAction> {
-    assert!(assist.source_change.is_none());
-    let res = lsp_ext::CodeAction {
+    let mut res = lsp_ext::CodeAction {
         title: assist.label.to_string(),
         group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
         kind: Some(code_action_kind(assist.id.1)),
         edit: None,
         is_preferred: None,
-        data: Some(lsp_ext::CodeActionData {
-            id: format!("{}:{}", assist.id.0, index.to_string()),
-            code_action_params,
-        }),
-    };
-    Ok(res)
-}
-
-pub(crate) fn resolved_code_action(
-    snap: &GlobalStateSnapshot,
-    assist: Assist,
-) -> Result<lsp_ext::CodeAction> {
-    let change = assist.source_change.unwrap();
-    let res = lsp_ext::CodeAction {
-        edit: Some(snippet_workspace_edit(snap, change)?),
-        title: assist.label.to_string(),
-        group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
-        kind: Some(code_action_kind(assist.id.1)),
-        is_preferred: None,
         data: None,
     };
+    match (assist.source_change, resolve_data) {
+        (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
+        (None, Some((index, code_action_params))) => {
+            res.data = Some(lsp_ext::CodeActionData {
+                id: format!("{}:{}", assist.id.0, index.to_string()),
+                code_action_params,
+            });
+        }
+        (None, None) => {
+            stdx::never!("assist should always be resolved if client can't do lazy resolving")
+        }
+    };
     Ok(res)
 }
 
@@ -1065,9 +1106,11 @@ pub(crate) fn rename_error(err: RenameError) -> crate::LspError {
 mod tests {
     use std::sync::Arc;
 
-    use hir::PrefixKind;
     use ide::Analysis;
-    use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
+    use ide_db::helpers::{
+        insert_use::{InsertUseConfig, PrefixKind},
+        SnippetCap,
+    };
 
     use super::*;
 
@@ -1108,7 +1151,7 @@ fn main() {
             .unwrap()
             .into_iter()
             .filter(|c| c.label().ends_with("arg"))
-            .map(|c| completion_item(&line_index, c))
+            .map(|c| completion_item(None, &line_index, c))
             .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text)))
             .collect();
         expect_test::expect![[r#"
@@ -1116,13 +1159,13 @@ fn main() {
                 (
                     "&arg",
                     Some(
-                        "fffffffd",
+                        "fffffff9",
                     ),
                 ),
                 (
                     "arg",
                     Some(
-                        "fffffffe",
+                        "fffffffd",
                     ),
                 ),
             ]