]> git.lizzy.rs Git - rust.git/blobdiff - crates/rust-analyzer/src/to_proto.rs
clippy::redudant_borrow
[rust.git] / crates / rust-analyzer / src / to_proto.rs
index 1a1f65f3b846daa4af5d4d015fae364dd41ef733..e53cd3c7ba541b59440823d49f233713f8f78a69 100644 (file)
@@ -1,15 +1,16 @@
 //! Conversion of rust-analyzer specific types to lsp_types equivalents.
 use std::{
+    iter::once,
     path::{self, Path},
     sync::atomic::{AtomicU32, Ordering},
 };
 
 use ide::{
-    Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind,
-    CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind,
-    Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind,
-    InsertTextFormat, Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity,
-    SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
+    Annotation, AnnotationKind, Assist, AssistKind, CallInfo, Cancellable, CompletionItem,
+    CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
+    Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
+    InlayKind, InsertTextFormat, Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable,
+    Severity, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
 use itertools::Itertools;
 use serde_json::to_value;
@@ -174,6 +175,7 @@ pub(crate) fn snippet_text_edit(
         range: text_edit.range,
         new_text: text_edit.new_text,
         insert_text_format,
+        annotation_id: None,
     }
 }
 
@@ -268,9 +270,12 @@ fn set_score(res: &mut lsp_types::CompletionItem, relevance: CompletionRelevance
             set_score(&mut lsp_item_with_ref, relevance);
             lsp_item_with_ref.label =
                 format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
-            if let Some(lsp_types::CompletionTextEdit::Edit(it)) = &mut lsp_item_with_ref.text_edit
-            {
-                it.new_text = format!("&{}{}", mutability.as_keyword_for_ref(), it.new_text);
+            if let Some(it) = &mut lsp_item_with_ref.text_edit {
+                let new_text = match it {
+                    lsp_types::CompletionTextEdit::Edit(it) => &mut it.new_text,
+                    lsp_types::CompletionTextEdit::InsertAndReplace(it) => &mut it.new_text,
+                };
+                *new_text = format!("&{}{}", mutability.as_keyword_for_ref(), new_text);
             }
             vec![lsp_item_with_ref, lsp_item]
         }
@@ -379,6 +384,7 @@ pub(crate) fn semantic_tokens(
     text: &str,
     line_index: &LineIndex,
     highlights: Vec<HlRange>,
+    highlight_strings: bool,
 ) -> lsp_types::SemanticTokens {
     let id = TOKEN_RESULT_COUNTER.fetch_add(1, Ordering::SeqCst).to_string();
     let mut builder = semantic_tokens::SemanticTokensBuilder::new(id);
@@ -387,8 +393,11 @@ pub(crate) fn semantic_tokens(
         if highlight_range.highlight.is_empty() {
             continue;
         }
-        let (type_, mods) = semantic_token_type_and_modifiers(highlight_range.highlight);
-        let token_index = semantic_tokens::type_index(type_);
+        let (ty, mods) = semantic_token_type_and_modifiers(highlight_range.highlight);
+        if !highlight_strings && ty == lsp_types::SemanticTokenType::STRING {
+            continue;
+        }
+        let token_index = semantic_tokens::type_index(ty);
         let modifier_bitset = mods.0;
 
         for mut text_range in line_index.index.lines(highlight_range.range) {
@@ -396,7 +405,7 @@ pub(crate) fn semantic_tokens(
                 text_range =
                     TextRange::new(text_range.start(), text_range.end() - TextSize::of('\n'));
             }
-            let range = range(&line_index, text_range);
+            let range = range(line_index, text_range);
             builder.push(range, token_index, modifier_bitset);
         }
     }
@@ -420,7 +429,7 @@ fn semantic_token_type_and_modifiers(
     let type_ = match highlight.tag {
         HlTag::Symbol(symbol) => match symbol {
             SymbolKind::Module => lsp_types::SemanticTokenType::NAMESPACE,
-            SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE,
+            SymbolKind::Impl => semantic_tokens::TYPE_ALIAS,
             SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
             SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
             SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER,
@@ -457,7 +466,7 @@ fn semantic_token_type_and_modifiers(
         HlTag::BoolLiteral => semantic_tokens::BOOLEAN,
         HlTag::BuiltinType => semantic_tokens::BUILTIN_TYPE,
         HlTag::ByteLiteral | HlTag::NumericLiteral => lsp_types::SemanticTokenType::NUMBER,
-        HlTag::CharLiteral => semantic_tokens::CHAR_LITERAL,
+        HlTag::CharLiteral => semantic_tokens::CHAR,
         HlTag::Comment => lsp_types::SemanticTokenType::COMMENT,
         HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
         HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
@@ -467,7 +476,7 @@ fn semantic_token_type_and_modifiers(
             HlOperator::Bitwise => semantic_tokens::BITWISE,
             HlOperator::Arithmetic => semantic_tokens::ARITHMETIC,
             HlOperator::Logical => semantic_tokens::LOGICAL,
-            HlOperator::Comparision => semantic_tokens::COMPARISION,
+            HlOperator::Comparison => semantic_tokens::COMPARISON,
             HlOperator::Other => semantic_tokens::OPERATOR,
         },
         HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
@@ -494,6 +503,8 @@ fn semantic_token_type_and_modifiers(
             HlMod::ControlFlow => semantic_tokens::CONTROL_FLOW,
             HlMod::Mutable => semantic_tokens::MUTABLE,
             HlMod::Consuming => semantic_tokens::CONSUMING,
+            HlMod::Async => semantic_tokens::ASYNC,
+            HlMod::Library => semantic_tokens::LIBRARY,
             HlMod::Unsafe => semantic_tokens::UNSAFE,
             HlMod::Callable => semantic_tokens::CALLABLE,
             HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,
@@ -522,6 +533,8 @@ pub(crate) fn folding_range(
         | FoldKind::ArgList
         | FoldKind::Consts
         | FoldKind::Statics
+        | FoldKind::WhereClause
+        | FoldKind::ReturnType
         | FoldKind::Array => None,
     };
 
@@ -593,7 +606,7 @@ pub(crate) fn url_from_abs_path(path: &Path) -> lsp_types::Url {
     // Note: lowercasing the `path` itself doesn't help, the `Url::parse`
     // machinery *also* canonicalizes the drive letter. So, just massage the
     // string in place.
-    let mut url = url.into_string();
+    let mut url: String = url.into();
     url[driver_letter_range].make_ascii_lowercase();
     lsp_types::Url::parse(&url).unwrap()
 }
@@ -688,6 +701,10 @@ pub(crate) fn goto_definition_response(
     }
 }
 
+fn outside_workspace_annotation_id() -> String {
+    String::from("OutsideWorkspace")
+}
+
 pub(crate) fn snippet_text_document_edit(
     snap: &GlobalStateSnapshot,
     is_snippet: bool,
@@ -696,14 +713,21 @@ pub(crate) fn snippet_text_document_edit(
 ) -> Result<lsp_ext::SnippetTextDocumentEdit> {
     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| snippet_text_edit(&line_index, is_snippet, it)).collect();
+    let mut edits: Vec<_> =
+        edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect();
+
+    if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() {
+        for edit in &mut edits {
+            edit.annotation_id = Some(outside_workspace_annotation_id())
+        }
+    }
     Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits })
 }
 
 pub(crate) fn snippet_text_document_ops(
     snap: &GlobalStateSnapshot,
     file_system_edit: FileSystemEdit,
-) -> Vec<lsp_ext::SnippetDocumentChangeOperation> {
+) -> Cancellable<Vec<lsp_ext::SnippetDocumentChangeOperation>> {
     let mut ops = Vec::new();
     match file_system_edit {
         FileSystemEdit::CreateFile { dst, initial_contents } => {
@@ -721,6 +745,7 @@ pub(crate) fn snippet_text_document_ops(
                     range: lsp_types::Range::default(),
                     new_text: initial_contents,
                     insert_text_format: Some(lsp_types::InsertTextFormat::PlainText),
+                    annotation_id: None,
                 };
                 let edit_file =
                     lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] };
@@ -730,16 +755,19 @@ pub(crate) fn snippet_text_document_ops(
         FileSystemEdit::MoveFile { src, dst } => {
             let old_uri = snap.file_id_to_url(src);
             let new_uri = snap.anchored_path(&dst);
-            let rename_file = lsp_types::ResourceOp::Rename(lsp_types::RenameFile {
-                old_uri,
-                new_uri,
-                options: None,
-                annotation_id: None,
-            });
-            ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file))
+            let mut rename_file =
+                lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None };
+            if snap.analysis.is_library_file(src).ok() == Some(true)
+                && snap.config.change_annotation_support()
+            {
+                rename_file.annotation_id = Some(outside_workspace_annotation_id())
+            }
+            ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(lsp_types::ResourceOp::Rename(
+                rename_file,
+            )))
         }
     }
-    ops
+    Ok(ops)
 }
 
 pub(crate) fn snippet_workspace_edit(
@@ -747,16 +775,35 @@ pub(crate) fn snippet_workspace_edit(
     source_change: SourceChange,
 ) -> Result<lsp_ext::SnippetWorkspaceEdit> {
     let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
+
     for op in source_change.file_system_edits {
-        let ops = snippet_text_document_ops(snap, op);
+        let ops = snippet_text_document_ops(snap, op)?;
         document_changes.extend_from_slice(&ops);
     }
     for (file_id, edit) in source_change.source_file_edits {
-        let edit = snippet_text_document_edit(&snap, source_change.is_snippet, file_id, edit)?;
+        let edit = snippet_text_document_edit(snap, source_change.is_snippet, file_id, edit)?;
         document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit));
     }
-    let workspace_edit =
-        lsp_ext::SnippetWorkspaceEdit { changes: None, document_changes: Some(document_changes) };
+    let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit {
+        changes: None,
+        document_changes: Some(document_changes),
+        change_annotations: None,
+    };
+    if snap.config.change_annotation_support() {
+        workspace_edit.change_annotations = Some(
+            once((
+                outside_workspace_annotation_id(),
+                lsp_types::ChangeAnnotation {
+                    label: String::from("Edit outside of the workspace"),
+                    needs_confirmation: Some(true),
+                    description: Some(String::from(
+                        "This edit lies outside of the workspace and may affect dependencies",
+                    )),
+                },
+            ))
+            .collect(),
+        )
+    }
     Ok(workspace_edit)
 }
 
@@ -784,16 +831,7 @@ fn from(snippet_workspace_edit: lsp_ext::SnippetWorkspaceEdit) -> lsp_types::Wor
                                 lsp_types::DocumentChangeOperation::Edit(
                                     lsp_types::TextDocumentEdit {
                                         text_document: edit.text_document,
-                                        edits: edit
-                                            .edits
-                                            .into_iter()
-                                            .map(|edit| {
-                                                lsp_types::OneOf::Left(lsp_types::TextEdit {
-                                                    range: edit.range,
-                                                    new_text: edit.new_text,
-                                                })
-                                            })
-                                            .collect(),
+                                        edits: edit.edits.into_iter().map(From::from).collect(),
                                     },
                                 )
                             }
@@ -801,7 +839,23 @@ fn from(snippet_workspace_edit: lsp_ext::SnippetWorkspaceEdit) -> lsp_types::Wor
                         .collect(),
                 )
             }),
-            change_annotations: None,
+            change_annotations: snippet_workspace_edit.change_annotations,
+        }
+    }
+}
+
+impl From<lsp_ext::SnippetTextEdit>
+    for lsp_types::OneOf<lsp_types::TextEdit, lsp_types::AnnotatedTextEdit>
+{
+    fn from(
+        lsp_ext::SnippetTextEdit { annotation_id, insert_text_format:_, new_text, range }: lsp_ext::SnippetTextEdit,
+    ) -> Self {
+        match annotation_id {
+            Some(annotation_id) => lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit {
+                text_edit: lsp_types::TextEdit { range, new_text },
+                annotation_id,
+            }),
+            None => lsp_types::OneOf::Left(lsp_types::TextEdit { range, new_text }),
         }
     }
 }
@@ -854,7 +908,7 @@ pub(crate) fn code_action(
         (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()),
+                id: format!("{}:{}:{}", assist.id.0, assist.id.1.name(), index),
                 code_action_params,
             });
         }
@@ -903,7 +957,7 @@ pub(crate) fn code_lens(
             let annotation_range = range(&line_index, annotation.range);
 
             let action = run.action();
-            let r = runnable(&snap, run)?;
+            let r = runnable(snap, run)?;
 
             let command = if debug {
                 command::debug_single(&r)
@@ -1096,7 +1150,7 @@ mod tests {
 
     use ide::Analysis;
     use ide_db::helpers::{
-        insert_use::{InsertUseConfig, PrefixKind},
+        insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
         SnippetCap,
     };
 
@@ -1124,12 +1178,14 @@ fn main() {
                 &ide::CompletionConfig {
                     enable_postfix_completions: true,
                     enable_imports_on_the_fly: true,
+                    enable_self_on_the_fly: true,
                     add_call_parenthesis: true,
                     add_call_argument_snippets: true,
                     snippet_cap: SnippetCap::new(true),
                     insert_use: InsertUseConfig {
-                        merge: None,
+                        granularity: ImportGranularity::Item,
                         prefix_kind: PrefixKind::Plain,
+                        enforce_granularity: true,
                         group: true,
                     },
                 },
@@ -1180,12 +1236,12 @@ fn main() {
         assert_eq!(folds.len(), 4);
 
         let line_index = LineIndex {
-            index: Arc::new(ide::LineIndex::new(&text)),
+            index: Arc::new(ide::LineIndex::new(text)),
             endings: LineEndings::Unix,
             encoding: OffsetEncoding::Utf16,
         };
         let converted: Vec<lsp_types::FoldingRange> =
-            folds.into_iter().map(|it| folding_range(&text, &line_index, true, it)).collect();
+            folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect();
 
         let expected_lines = [(0, 2), (4, 10), (5, 6), (7, 9)];
         assert_eq!(converted.len(), expected_lines.len());