]> git.lizzy.rs Git - rust.git/blobdiff - crates/rust-analyzer/src/conv.rs
Merge #4161
[rust.git] / crates / rust-analyzer / src / conv.rs
index 5fcb46b6174b2d839588f007cc8100e9a6ab386e..7be5ebcdb5a0d13599cc5a8d628c48186cc46936 100644 (file)
@@ -3,21 +3,31 @@
 
 use lsp_types::{
     self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation,
-    Location, LocationLink, MarkupContent, MarkupKind, Position, Range, RenameFile, ResourceOp,
-    SemanticTokenModifier, SemanticTokenType, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
-    TextDocumentItem, TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier,
-    WorkspaceEdit,
+    Location, LocationLink, MarkupContent, MarkupKind, ParameterInformation, ParameterLabel,
+    Position, Range, RenameFile, ResourceOp, SemanticTokenModifier, SemanticTokenType,
+    SignatureInformation, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, TextDocumentItem,
+    TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, WorkspaceEdit,
 };
 use ra_ide::{
-    tags, translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition,
-    FileRange, FileSystemEdit, Fold, FoldKind, InsertTextFormat, LineCol, LineIndex,
-    NavigationTarget, RangeInfo, ReferenceAccess, Severity, SourceChange, SourceFileEdit,
+    translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition,
+    FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HighlightModifier, HighlightTag,
+    InlayHint, InlayKind, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo,
+    ReferenceAccess, Severity, SourceChange, SourceFileEdit,
 };
-use ra_syntax::{SyntaxKind, TextRange, TextUnit};
+use ra_syntax::{SyntaxKind, TextRange, TextSize};
 use ra_text_edit::{AtomTextEdit, TextEdit};
 use ra_vfs::LineEndings;
 
-use crate::{req, semantic_tokens, world::WorldSnapshot, Result};
+use crate::{
+    req,
+    semantic_tokens::{self, ModifierSet, CONSTANT, CONTROL_FLOW, MUTABLE, UNSAFE},
+    world::WorldSnapshot,
+    Result,
+};
+use semantic_tokens::{
+    ATTRIBUTE, BUILTIN_TYPE, ENUM_MEMBER, FORMAT_SPECIFIER, LIFETIME, TYPE_ALIAS, UNION,
+    UNRESOLVED_REFERENCE,
+};
 
 pub trait Conv {
     type Output;
@@ -50,7 +60,7 @@ fn conv(self) -> <Self as Conv>::Output {
             SyntaxKind::RECORD_FIELD_DEF => SymbolKind::Field,
             SyntaxKind::STATIC_DEF => SymbolKind::Constant,
             SyntaxKind::CONST_DEF => SymbolKind::Constant,
-            SyntaxKind::IMPL_BLOCK => SymbolKind::Object,
+            SyntaxKind::IMPL_DEF => SymbolKind::Object,
             _ => SymbolKind::Variable,
         }
     }
@@ -91,6 +101,7 @@ fn conv(self) -> <Self as Conv>::Output {
             CompletionItemKind::Method => Method,
             CompletionItemKind::TypeParam => TypeParameter,
             CompletionItemKind::Macro => Method,
+            CompletionItemKind::Attribute => EnumMember,
         }
     }
 }
@@ -114,22 +125,22 @@ fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> ::lsp_types::CompletionIte
         // LSP does not allow arbitrary edits in completion, so we have to do a
         // non-trivial mapping here.
         for atom_edit in self.text_edit().as_atoms() {
-            if self.source_range().is_subrange(&atom_edit.delete) {
+            if atom_edit.delete.contains_range(self.source_range()) {
                 text_edit = Some(if atom_edit.delete == self.source_range() {
-                    atom_edit.conv_with(ctx)
+                    atom_edit.conv_with((ctx.0, ctx.1))
                 } else {
                     assert!(self.source_range().end() == atom_edit.delete.end());
                     let range1 =
-                        TextRange::from_to(atom_edit.delete.start(), self.source_range().start());
+                        TextRange::new(atom_edit.delete.start(), self.source_range().start());
                     let range2 = self.source_range();
                     let edit1 = AtomTextEdit::replace(range1, String::new());
                     let edit2 = AtomTextEdit::replace(range2, atom_edit.insert.clone());
-                    additional_text_edits.push(edit1.conv_with(ctx));
-                    edit2.conv_with(ctx)
+                    additional_text_edits.push(edit1.conv_with((ctx.0, ctx.1)));
+                    edit2.conv_with((ctx.0, ctx.1))
                 })
             } else {
-                assert!(self.source_range().intersection(&atom_edit.delete).is_none());
-                additional_text_edits.push(atom_edit.conv_with(ctx));
+                assert!(self.source_range().intersect(atom_edit.delete).is_none());
+                additional_text_edits.push(atom_edit.conv_with((ctx.0, ctx.1)));
             }
         }
         let text_edit = text_edit.unwrap();
@@ -139,13 +150,27 @@ fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> ::lsp_types::CompletionIte
             detail: self.detail().map(|it| it.to_string()),
             filter_text: Some(self.lookup().to_string()),
             kind: self.kind().map(|it| it.conv()),
-            text_edit: Some(text_edit),
+            text_edit: Some(text_edit.into()),
             additional_text_edits: Some(additional_text_edits),
             documentation: self.documentation().map(|it| it.conv()),
             deprecated: Some(self.deprecated()),
+            command: if self.trigger_call_info() {
+                let cmd = lsp_types::Command {
+                    title: "triggerParameterHints".into(),
+                    command: "editor.action.triggerParameterHints".into(),
+                    arguments: None,
+                };
+                Some(cmd)
+            } else {
+                None
+            },
             ..Default::default()
         };
 
+        if self.score().is_some() {
+            res.preselect = Some(true)
+        }
+
         if self.deprecated() {
             res.tags = Some(vec![lsp_types::CompletionItemTag::Deprecated])
         }
@@ -160,15 +185,15 @@ fn conv_with(self, ctx: (&LineIndex, LineEndings)) -> ::lsp_types::CompletionIte
 }
 
 impl ConvWith<&LineIndex> for Position {
-    type Output = TextUnit;
+    type Output = TextSize;
 
-    fn conv_with(self, line_index: &LineIndex) -> TextUnit {
+    fn conv_with(self, line_index: &LineIndex) -> TextSize {
         let line_col = LineCol { line: self.line as u32, col_utf16: self.character as u32 };
         line_index.offset(line_col)
     }
 }
 
-impl ConvWith<&LineIndex> for TextUnit {
+impl ConvWith<&LineIndex> for TextSize {
     type Output = Position;
 
     fn conv_with(self, line_index: &LineIndex) -> Position {
@@ -189,7 +214,7 @@ impl ConvWith<&LineIndex> for Range {
     type Output = TextRange;
 
     fn conv_with(self, line_index: &LineIndex) -> TextRange {
-        TextRange::from_to(self.start.conv_with(line_index), self.end.conv_with(line_index))
+        TextRange::new(self.start.conv_with(line_index), self.end.conv_with(line_index))
     }
 }
 
@@ -203,17 +228,20 @@ fn conv(self) -> Documentation {
     }
 }
 
-impl Conv for ra_ide::FunctionSignature {
+impl ConvWith<bool> for ra_ide::FunctionSignature {
     type Output = lsp_types::SignatureInformation;
-    fn conv(self) -> Self::Output {
-        use lsp_types::{ParameterInformation, ParameterLabel, SignatureInformation};
-
-        let label = self.to_string();
-
-        let documentation = self.doc.map(|it| it.conv());
+    fn conv_with(self, concise: bool) -> Self::Output {
+        let (label, documentation, params) = if concise {
+            let mut params = self.parameters;
+            if self.has_self_param {
+                params.remove(0);
+            }
+            (params.join(", "), None, params)
+        } else {
+            (self.to_string(), self.doc.map(|it| it.conv()), self.parameters)
+        };
 
-        let parameters: Vec<ParameterInformation> = self
-            .parameters
+        let parameters: Vec<ParameterInformation> = params
             .into_iter()
             .map(|param| ParameterInformation {
                 label: ParameterLabel::Simple(param),
@@ -273,7 +301,7 @@ fn conv_with(self, ctx: &FoldConvCtx) -> lsp_types::FoldingRange {
             // range.end.line from the folding region if there is more text after range.end
             // on the same line.
             let has_more_text_on_end_line = ctx.text
-                [TextRange::from_to(self.range.end(), TextUnit::of_str(ctx.text))]
+                [TextRange::new(self.range.end(), TextSize::of(ctx.text))]
             .chars()
             .take_while(|it| *it != '\n')
             .any(|it| !it.is_whitespace());
@@ -303,73 +331,71 @@ fn conv_with(self, ctx: &FoldConvCtx) -> lsp_types::FoldingRange {
     }
 }
 
-impl Conv for &'static str {
-    type Output = (SemanticTokenType, Vec<SemanticTokenModifier>);
-
-    fn conv(self) -> (SemanticTokenType, Vec<SemanticTokenModifier>) {
-        let token_type: SemanticTokenType = match self {
-            tags::FIELD => SemanticTokenType::MEMBER,
-            tags::FUNCTION => SemanticTokenType::FUNCTION,
-            tags::MODULE => SemanticTokenType::NAMESPACE,
-            tags::CONSTANT => {
-                return (
-                    SemanticTokenType::VARIABLE,
-                    vec![SemanticTokenModifier::STATIC, SemanticTokenModifier::READONLY],
-                )
-            }
-            tags::MACRO => SemanticTokenType::MACRO,
-
-            tags::VARIABLE => {
-                return (SemanticTokenType::VARIABLE, vec![SemanticTokenModifier::READONLY])
-            }
-            tags::VARIABLE_MUT => SemanticTokenType::VARIABLE,
-
-            tags::TYPE => SemanticTokenType::TYPE,
-            tags::TYPE_BUILTIN => SemanticTokenType::TYPE,
-            tags::TYPE_SELF => {
-                return (SemanticTokenType::TYPE, vec![SemanticTokenModifier::REFERENCE])
-            }
-            tags::TYPE_PARAM => SemanticTokenType::TYPE_PARAMETER,
-            tags::TYPE_LIFETIME => {
-                return (SemanticTokenType::LABEL, vec![SemanticTokenModifier::REFERENCE])
-            }
-
-            tags::LITERAL_BYTE => SemanticTokenType::NUMBER,
-            tags::LITERAL_NUMERIC => SemanticTokenType::NUMBER,
-            tags::LITERAL_CHAR => SemanticTokenType::NUMBER,
-
-            tags::LITERAL_COMMENT => {
-                return (SemanticTokenType::COMMENT, vec![SemanticTokenModifier::DOCUMENTATION])
-            }
-
-            tags::LITERAL_STRING => SemanticTokenType::STRING,
-            tags::LITERAL_ATTRIBUTE => SemanticTokenType::KEYWORD,
-
-            tags::KEYWORD => SemanticTokenType::KEYWORD,
-            tags::KEYWORD_UNSAFE => SemanticTokenType::KEYWORD,
-            tags::KEYWORD_CONTROL => SemanticTokenType::KEYWORD,
-            unknown => panic!("Unknown semantic token: {}", unknown),
-        };
-
-        (token_type, vec![])
+impl ConvWith<&LineIndex> for InlayHint {
+    type Output = req::InlayHint;
+    fn conv_with(self, line_index: &LineIndex) -> Self::Output {
+        req::InlayHint {
+            label: self.label.to_string(),
+            range: self.range.conv_with(line_index),
+            kind: match self.kind {
+                InlayKind::ParameterHint => req::InlayKind::ParameterHint,
+                InlayKind::TypeHint => req::InlayKind::TypeHint,
+                InlayKind::ChainingHint => req::InlayKind::ChainingHint,
+            },
+        }
     }
 }
 
-impl Conv for (SemanticTokenType, Vec<SemanticTokenModifier>) {
+impl Conv for Highlight {
     type Output = (u32, u32);
 
     fn conv(self) -> Self::Output {
-        let token_index =
-            semantic_tokens::supported_token_types().iter().position(|it| *it == self.0).unwrap();
-        let mut token_modifier_bitset = 0;
-        for modifier in self.1.iter() {
-            token_modifier_bitset |= semantic_tokens::supported_token_modifiers()
-                .iter()
-                .position(|it| it == modifier)
-                .unwrap();
+        let mut mods = ModifierSet::default();
+        let type_ = match self.tag {
+            HighlightTag::Struct => SemanticTokenType::STRUCT,
+            HighlightTag::Enum => SemanticTokenType::ENUM,
+            HighlightTag::Union => UNION,
+            HighlightTag::TypeAlias => TYPE_ALIAS,
+            HighlightTag::Trait => SemanticTokenType::INTERFACE,
+            HighlightTag::BuiltinType => BUILTIN_TYPE,
+            HighlightTag::SelfType => SemanticTokenType::TYPE,
+            HighlightTag::Field => SemanticTokenType::MEMBER,
+            HighlightTag::Function => SemanticTokenType::FUNCTION,
+            HighlightTag::Module => SemanticTokenType::NAMESPACE,
+            HighlightTag::Constant => {
+                mods |= CONSTANT;
+                mods |= SemanticTokenModifier::STATIC;
+                SemanticTokenType::VARIABLE
+            }
+            HighlightTag::Static => {
+                mods |= SemanticTokenModifier::STATIC;
+                SemanticTokenType::VARIABLE
+            }
+            HighlightTag::EnumVariant => ENUM_MEMBER,
+            HighlightTag::Macro => SemanticTokenType::MACRO,
+            HighlightTag::Local => SemanticTokenType::VARIABLE,
+            HighlightTag::TypeParam => SemanticTokenType::TYPE_PARAMETER,
+            HighlightTag::Lifetime => LIFETIME,
+            HighlightTag::ByteLiteral | HighlightTag::NumericLiteral => SemanticTokenType::NUMBER,
+            HighlightTag::CharLiteral | HighlightTag::StringLiteral => SemanticTokenType::STRING,
+            HighlightTag::Comment => SemanticTokenType::COMMENT,
+            HighlightTag::Attribute => ATTRIBUTE,
+            HighlightTag::Keyword => SemanticTokenType::KEYWORD,
+            HighlightTag::UnresolvedReference => UNRESOLVED_REFERENCE,
+            HighlightTag::FormatSpecifier => FORMAT_SPECIFIER,
+        };
+
+        for modifier in self.modifiers.iter() {
+            let modifier = match modifier {
+                HighlightModifier::Definition => SemanticTokenModifier::DECLARATION,
+                HighlightModifier::ControlFlow => CONTROL_FLOW,
+                HighlightModifier::Mutable => MUTABLE,
+                HighlightModifier::Unsafe => UNSAFE,
+            };
+            mods |= modifier;
         }
 
-        (token_index as u32, token_modifier_bitset as u32)
+        (semantic_tokens::type_index(type_), mods.0)
     }
 }
 
@@ -563,7 +589,7 @@ fn try_conv_with(self, world: &WorldSnapshot) -> Result<req::GotoTypeDefinitionR
             .into_iter()
             .map(|nav| (file_id, RangeInfo::new(range, nav)))
             .try_conv_with_to_vec(world)?;
-        if world.options.supports_location_link {
+        if world.config.client_caps.location_link {
             Ok(links.into())
         } else {
             let locations: Vec<Location> = links