diff --git a/crates/ra_ide/src/snapshots/highlight_doctest.html b/crates/ra_ide/src/snapshots/highlight_doctest.html index ac546806eb98..e8155def75eb 100644 --- a/crates/ra_ide/src/snapshots/highlight_doctest.html +++ b/crates/ra_ide/src/snapshots/highlight_doctest.html @@ -5,6 +5,8 @@ .lifetime { color: #DFAF8F; font-style: italic; } .comment { color: #7F9F7F; } +.documentation { color: #629755; } +.injected { opacity: 0.65 ; } .struct, .enum { color: #7CB8BB; } .enum_variant { color: #BDE0F3; } .string_literal { color: #CC9393; } @@ -33,7 +35,7 @@ .control { font-style: italic; }
/// ```
-/// let _ = "early doctests should not go boom";
+/// let _ = "early doctests should not go boom";
 /// ```
 struct Foo {
     bar: bool,
@@ -47,8 +49,8 @@
     /// # Examples
     ///
     /// ```
-    /// # #![allow(unused_mut)]
-    /// let mut foo: Foo = Foo::new();
+    /// # #![allow(unused_mut)]
+    /// let mut foo: Foo = Foo::new();
     /// ```
     pub const fn new() -> Foo {
         Foo { bar: true }
@@ -59,26 +61,26 @@
     /// # Examples
     ///
     /// ```
-    /// use x::y;
+    /// use x::y;
     ///
-    /// let foo = Foo::new();
+    /// let foo = Foo::new();
     ///
-    /// // calls bar on foo
-    /// assert!(foo.bar());
+    /// // calls bar on foo
+    /// assert!(foo.bar());
     ///
-    /// let bar = foo.bar || Foo::bar;
+    /// let bar = foo.bar || Foo::bar;
     ///
-    /// /* multi-line
-    ///        comment */
+    /// /* multi-line
+    ///        comment */
     ///
-    /// let multi_line_string = "Foo
-    ///   bar
-    ///          ";
+    /// let multi_line_string = "Foo
+    ///   bar
+    ///          ";
     ///
     /// ```
     ///
     /// ```rust,no_run
-    /// let foobar = Foo::new().bar();
+    /// let foobar = Foo::new().bar();
     /// ```
     ///
     /// ```sh
@@ -90,7 +92,7 @@
 }
 
 /// ```
-/// noop!(1);
+/// noop!(1);
 /// ```
 macro_rules! noop {
     ($expr:expr) => {
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html
index 47dbd7bc8a3d..1b0349bae2ee 100644
--- a/crates/ra_ide/src/snapshots/highlight_injection.html
+++ b/crates/ra_ide/src/snapshots/highlight_injection.html
@@ -5,6 +5,8 @@
 
 .lifetime           { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
 .string_literal     { color: #CC9393; }
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html
index b46fa44c6a47..d184b5691024 100644
--- a/crates/ra_ide/src/snapshots/highlight_strings.html
+++ b/crates/ra_ide/src/snapshots/highlight_strings.html
@@ -5,6 +5,8 @@
 
 .lifetime           { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
 .string_literal     { color: #CC9393; }
diff --git a/crates/ra_ide/src/snapshots/highlight_unsafe.html b/crates/ra_ide/src/snapshots/highlight_unsafe.html
index 73438fbb4c08..6936e949fe8e 100644
--- a/crates/ra_ide/src/snapshots/highlight_unsafe.html
+++ b/crates/ra_ide/src/snapshots/highlight_unsafe.html
@@ -5,6 +5,8 @@
 
 .lifetime           { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
 .string_literal     { color: #CC9393; }
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index 0c4f0a018769..8d0b38f958dc 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -5,6 +5,8 @@
 
 .lifetime           { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
 .string_literal     { color: #CC9393; }
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index a74a70069dd8..9516c7441040 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -5,6 +5,8 @@
 
 .lifetime           { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
 .string_literal     { color: #CC9393; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 448645bdc34f..028b559022cb 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -236,7 +236,7 @@ pub(crate) fn highlight(
                             });
                         }
                     }
-                    stack.pop_and_inject(false);
+                    stack.pop_and_inject(None);
                 }
             } else if let Some(string) =
                 element_to_highlight.as_token().cloned().and_then(ast::RawString::cast)
@@ -324,16 +324,27 @@ impl HighlightedRangeStack {
         cloned
     }
 
+    /// Remove the `HighlightRange` of `parent` that's currently covered by `child`.
+    fn intersect_partial(parent: &mut HighlightedRange, child: &HighlightedRange) {
+        assert!(
+            parent.range.start() <= child.range.start()
+                && parent.range.end() >= child.range.start()
+                && child.range.end() > parent.range.end()
+        );
+
+        parent.range = TextRange::new(parent.range.start(), child.range.start());
+    }
+
     /// Similar to `pop`, but can modify arbitrary prior ranges (where `pop`)
     /// can only modify the last range currently on the stack.
     /// Can be used to do injections that span multiple ranges, like the
     /// doctest injection below.
-    /// If `delete` is set to true, the parent range is deleted instead of
-    /// intersected.
+    /// If `overwrite_parent` is non-optional, the highlighting of the parent range
+    /// is overwritten with the argument.
     ///
     /// Note that `pop` can be simulated by `pop_and_inject(false)` but the
     /// latter is computationally more expensive.
-    fn pop_and_inject(&mut self, delete: bool) {
+    fn pop_and_inject(&mut self, overwrite_parent: Option) {
         let mut children = self.stack.pop().unwrap();
         let prev = self.stack.last_mut().unwrap();
         children.sort_by_key(|range| range.range.start());
@@ -343,26 +354,45 @@ impl HighlightedRangeStack {
             if let Some(idx) =
                 prev.iter().position(|parent| parent.range.contains_range(child.range))
             {
+                if let Some(tag) = overwrite_parent {
+                    prev[idx].highlight = tag;
+                }
+
                 let cloned = Self::intersect(&mut prev[idx], &child);
-                let insert_idx = if delete || prev[idx].range.is_empty() {
+                let insert_idx = if prev[idx].range.is_empty() {
                     prev.remove(idx);
                     idx
                 } else {
                     idx + 1
                 };
                 prev.insert(insert_idx, child);
-                if !delete && !cloned.range.is_empty() {
+                if !cloned.range.is_empty() {
                     prev.insert(insert_idx + 1, cloned);
                 }
-            } else if let Some(_idx) =
-                prev.iter().position(|parent| parent.range.contains(child.range.start()))
-            {
-                unreachable!("child range should be completely contained in parent range");
             } else {
-                let idx = prev
-                    .binary_search_by_key(&child.range.start(), |range| range.range.start())
-                    .unwrap_or_else(|x| x);
-                prev.insert(idx, child);
+                let maybe_idx =
+                    prev.iter().position(|parent| parent.range.contains(child.range.start()));
+                match (overwrite_parent, maybe_idx) {
+                    (Some(_), Some(idx)) => {
+                        Self::intersect_partial(&mut prev[idx], &child);
+                        let insert_idx = if prev[idx].range.is_empty() {
+                            prev.remove(idx);
+                            idx
+                        } else {
+                            idx + 1
+                        };
+                        prev.insert(insert_idx, child);
+                    }
+                    (_, None) => {
+                        let idx = prev
+                            .binary_search_by_key(&child.range.start(), |range| range.range.start())
+                            .unwrap_or_else(|x| x);
+                        prev.insert(idx, child);
+                    }
+                    _ => {
+                        unreachable!("child range should be completely contained in parent range");
+                    }
+                }
             }
         }
     }
@@ -516,11 +546,9 @@ fn highlight_element(
             let ty = sema.type_of_expr(&expr)?;
             if !ty.is_raw_ptr() {
                 return None;
+            } else {
+                HighlightTag::Operator | HighlightModifier::Unsafe
             }
-
-            let mut h = Highlight::new(HighlightTag::Operator);
-            h |= HighlightModifier::Unsafe;
-            h
         }
         T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
             Highlight::new(HighlightTag::Macro)
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs
index 99b6b25ab9ca..0c74f7370158 100644
--- a/crates/ra_ide/src/syntax_highlighting/html.rs
+++ b/crates/ra_ide/src/syntax_highlighting/html.rs
@@ -64,6 +64,8 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 .lifetime           { color: #DFAF8F; font-style: italic; }
 .comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.injected           { opacity: 0.65 ; }
 .struct, .enum      { color: #7CB8BB; }
 .enum_variant       { color: #BDE0F3; }
 .string_literal     { color: #CC9393; }
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs
index 9d82b400951a..181c21256e01 100644
--- a/crates/ra_ide/src/syntax_highlighting/injection.rs
+++ b/crates/ra_ide/src/syntax_highlighting/injection.rs
@@ -8,8 +8,8 @@ use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize};
 use stdx::SepBy;
 
 use crate::{
-    call_info::ActiveParameter, Analysis, HighlightModifier, HighlightTag, HighlightedRange,
-    RootDatabase,
+    call_info::ActiveParameter, Analysis, Highlight, HighlightModifier, HighlightTag,
+    HighlightedRange, RootDatabase,
 };
 
 use super::HighlightedRangeStack;
@@ -172,6 +172,7 @@ pub(super) fn highlight_doc_comment(
                 h.range.end() + end_offset.unwrap_or(start_offset) - h.range.start(),
             );
 
+            h.highlight |= HighlightModifier::Injected;
             stack.add(h);
         }
     }
@@ -181,6 +182,7 @@ pub(super) fn highlight_doc_comment(
     for comment in new_comments {
         stack.add(comment);
     }
-    stack.pop_and_inject(false);
-    stack.pop_and_inject(true);
+    stack.pop_and_inject(None);
+    stack
+        .pop_and_inject(Some(Highlight::from(HighlightTag::Generic) | HighlightModifier::Injected));
 }
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs
index 93bbb4b4dc44..e8e251cfc000 100644
--- a/crates/ra_ide/src/syntax_highlighting/tags.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tags.rs
@@ -27,6 +27,7 @@ pub enum HighlightTag {
     Field,
     FormatSpecifier,
     Function,
+    Generic,
     Keyword,
     Lifetime,
     Macro,
@@ -57,6 +58,7 @@ pub enum HighlightModifier {
     /// not.
     Definition,
     Documentation,
+    Injected,
     Mutable,
     Unsafe,
 }
@@ -77,6 +79,7 @@ impl HighlightTag {
             HighlightTag::Field => "field",
             HighlightTag::FormatSpecifier => "format_specifier",
             HighlightTag::Function => "function",
+            HighlightTag::Generic => "generic",
             HighlightTag::Keyword => "keyword",
             HighlightTag::Lifetime => "lifetime",
             HighlightTag::Macro => "macro",
@@ -110,6 +113,7 @@ impl HighlightModifier {
         HighlightModifier::ControlFlow,
         HighlightModifier::Definition,
         HighlightModifier::Documentation,
+        HighlightModifier::Injected,
         HighlightModifier::Mutable,
         HighlightModifier::Unsafe,
     ];
@@ -120,6 +124,7 @@ impl HighlightModifier {
             HighlightModifier::ControlFlow => "control",
             HighlightModifier::Definition => "declaration",
             HighlightModifier::Documentation => "documentation",
+            HighlightModifier::Injected => "injected",
             HighlightModifier::Mutable => "mutable",
             HighlightModifier::Unsafe => "unsafe",
         }
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 2ea63d33b152..10fe40cb5072 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -39,13 +39,14 @@ define_semantic_token_types![
     (BOOLEAN, "boolean"),
     (BUILTIN_TYPE, "builtinType"),
     (ENUM_MEMBER, "enumMember"),
+    (ESCAPE_SEQUENCE, "escapeSequence"),
+    (FORMAT_SPECIFIER, "formatSpecifier"),
+    (GENERIC, "generic"),
     (LIFETIME, "lifetime"),
     (SELF_KEYWORD, "selfKeyword"),
     (TYPE_ALIAS, "typeAlias"),
     (UNION, "union"),
     (UNRESOLVED_REFERENCE, "unresolvedReference"),
-    (FORMAT_SPECIFIER, "formatSpecifier"),
-    (ESCAPE_SEQUENCE, "escapeSequence"),
 ];
 
 macro_rules! define_semantic_token_modifiers {
@@ -68,6 +69,7 @@ macro_rules! define_semantic_token_modifiers {
 define_semantic_token_modifiers![
     (CONSTANT, "constant"),
     (CONTROL_FLOW, "controlFlow"),
+    (INJECTED, "injected"),
     (MUTABLE, "mutable"),
     (UNSAFE, "unsafe"),
     (ATTRIBUTE_MODIFIER, "attribute"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 7b45b169d6dc..da9887a9a316 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -295,6 +295,7 @@ fn semantic_token_type_and_modifiers(
         HighlightTag::SelfType => lsp_types::SemanticTokenType::TYPE,
         HighlightTag::Field => lsp_types::SemanticTokenType::PROPERTY,
         HighlightTag::Function => lsp_types::SemanticTokenType::FUNCTION,
+        HighlightTag::Generic => semantic_tokens::GENERIC,
         HighlightTag::Module => lsp_types::SemanticTokenType::NAMESPACE,
         HighlightTag::Constant => {
             mods |= semantic_tokens::CONSTANT;
@@ -331,6 +332,7 @@ fn semantic_token_type_and_modifiers(
             HighlightModifier::Attribute => semantic_tokens::ATTRIBUTE_MODIFIER,
             HighlightModifier::Definition => lsp_types::SemanticTokenModifier::DECLARATION,
             HighlightModifier::Documentation => lsp_types::SemanticTokenModifier::DOCUMENTATION,
+            HighlightModifier::Injected => semantic_tokens::INJECTED,
             HighlightModifier::ControlFlow => semantic_tokens::CONTROL_FLOW,
             HighlightModifier::Mutable => semantic_tokens::MUTABLE,
             HighlightModifier::Unsafe => semantic_tokens::UNSAFE,