Repository: brendanzab/codespan (rust)

Issue:
Highlight text pointed to by labels
I noticed that codespan-reporting 0.9 is no longer highlighting the file characters pointed to by labels. For my use case I think I found that the highlighted way was preferable. Is this something that you would be open to bringing back as an option?

<br>

### codespan-reporting 0.8.0:

![Screenshot from 2020-03-18 15-00-30](https://user-images.githubusercontent.com/1940490/77011536-517ddc80-6929-11ea-99b2-445031ed702f.png)

### codespan-reporting 0.9.0:

![Screenshot from 2020-03-18 14-58-02](https://user-images.githubusercontent.com/1940490/77011535-50e54600-6929-11ea-8033-2d44965b423c.png)

Pull request description:
Restore highlighted source for primary labels
This renders the source text marked by primary labels. 

For example:

<img width="653" alt="Screen Shot 2020-06-23 at 1 32 33 pm" src="https://user-images.githubusercontent.com/695077/85358021-07bf1680-b556-11ea-9fc6-b8d09bc2c616.png">

Notice how `num` is now coloured in red! 🎉 

Closes #206.

Patch:
diff --git a/codespan-reporting/assets/readme_preview.svg b/codespan-reporting/assets/readme_preview.svg
index 859b7dc..5fd415e 100644
--- a/codespan-reporting/assets/readme_preview.svg
+++ b/codespan-reporting/assets/readme_preview.svg
@@ -55,17 +55,17 @@
    <span class="fg blue">┌─</span> FizzBuzz.fun:10:15
    <span class="fg blue">│</span>  
 <span class="fg blue">10</span> <span class="fg blue">│</span>   fizz₂ : Nat → String
-   <span class="fg blue">│</span>                 <span class="fg blue">------ expected type `String` found here</span>
+   <span class="fg blue">│</span>                 <span class="fg blue">------</span> <span class="fg blue">expected type `String` found here</span>
 <span class="fg blue">11</span> <span class="fg blue">│</span>   fizz₂ num =
 <span class="fg blue">12</span> <span class="fg blue">│</span> <span class="fg blue">╭</span>     case (mod num 5) (mod num 3) of
 <span class="fg blue">13</span> <span class="fg blue">│</span> <span class="fg blue">│</span>         0 0 =&gt; "FizzBuzz"
-   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg blue">---------- this is found to be of type `String`</span>
+   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg blue">----------</span> <span class="fg blue">this is found to be of type `String`</span>
 <span class="fg blue">14</span> <span class="fg blue">│</span> <span class="fg blue">│</span>         0 _ =&gt; "Fizz"
-   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg blue">------ this is found to be of type `String`</span>
+   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg blue">------</span> <span class="fg blue">this is found to be of type `String`</span>
 <span class="fg blue">15</span> <span class="fg blue">│</span> <span class="fg blue">│</span>         _ 0 =&gt; "Buzz"
-   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg blue">------ this is found to be of type `String`</span>
-<span class="fg blue">16</span> <span class="fg blue">│</span> <span class="fg blue">│</span>         _ _ =&gt; num
-   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg red">^^^ expected `String`, found `Nat`</span>
+   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg blue">------</span> <span class="fg blue">this is found to be of type `String`</span>
+<span class="fg blue">16</span> <span class="fg blue">│</span> <span class="fg blue">│</span>         _ _ =&gt; <span class="fg red">num</span>
+   <span class="fg blue">│</span> <span class="fg blue">│</span>                <span class="fg red">^^^</span> <span class="fg red">expected `String`, found `Nat`</span>
    <span class="fg blue">│</span> <span class="fg blue">╰</span><span class="fg blue">──────────────────' `case` clauses have incompatible types</span>
    <span class="fg blue">│</span>  
    <span class="fg blue">=</span> expected type `String`
diff --git a/codespan-reporting/src/term/renderer.rs b/codespan-reporting/src/term/renderer.rs
index c288955..ab5656e 100644
--- a/codespan-reporting/src/term/renderer.rs
+++ b/codespan-reporting/src/term/renderer.rs
@@ -30,25 +30,25 @@ pub enum MultiLabel<'diagnostic> {
     /// ```text
     /// ╭
     /// ```
-    TopLeft(LabelStyle),
+    TopLeft,
     /// Multi-line label top.
     ///
     /// ```text
     /// ╭────────────^
     /// ```
-    Top(LabelStyle, RangeTo<usize>),
+    Top(RangeTo<usize>),
     /// Left vertical labels for multi-line labels.
     ///
     /// ```text
     /// │
     /// ```
-    Left(LabelStyle),
+    Left,
     /// Multi-line label bottom, with an optional message.
     ///
     /// ```text
     /// ╰────────────^ blah blah
     /// ```
-    Bottom(LabelStyle, RangeTo<usize>, &'diagnostic str),
+    Bottom(RangeTo<usize>, &'diagnostic str),
 }
 
 #[derive(Copy, Clone)]
@@ -228,7 +228,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
         severity: Severity,
         single_labels: &[SingleLabel<'_>],
         num_multi_labels: usize,
-        multi_labels: &[(usize, MultiLabel<'_>)],
+        multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
     ) -> io::Result<()> {
         // Trim trailing newlines, linefeeds, and null chars from source, if they exist.
         // FIXME: Use the number of trimmed placeholders when rendering single line carets
@@ -248,30 +248,57 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
             let mut multi_labels_iter = multi_labels.iter().peekable();
             for label_column in 0..num_multi_labels {
                 match multi_labels_iter.peek() {
-                    Some((label_index, label)) if *label_index == label_column => {
+                    Some((label_index, label_style, label)) if *label_index == label_column => {
                         match label {
-                            MultiLabel::TopLeft(label_style) => {
+                            MultiLabel::TopLeft => {
                                 self.label_multi_top_left(severity, *label_style)?;
                             }
                             MultiLabel::Top(..) => self.inner_gutter_space()?,
-                            MultiLabel::Left(label_style) | MultiLabel::Bottom(label_style, ..) => {
+                            MultiLabel::Left | MultiLabel::Bottom(..) => {
                                 self.label_multi_left(severity, *label_style, None)?;
                             }
                         }
                         multi_labels_iter.next();
                     }
-                    Some((_, _)) | None => self.inner_gutter_space()?,
+                    Some((_, _, _)) | None => self.inner_gutter_space()?,
                 }
             }
 
             // Write source text
             write!(self, " ")?;
+            let mut in_primary = false;
             for (metrics, ch) in self.char_metrics(source.char_indices()) {
+                let column_range = metrics.byte_index..(metrics.byte_index + ch.len_utf8());
+
+                // Check if we are overlapping a primary label
+                let is_primary = single_labels.iter().any(|(ls, range, _)| {
+                    *ls == LabelStyle::Primary && is_overlapping(range, &column_range)
+                }) || multi_labels.iter().any(|(_, ls, label)| {
+                    *ls == LabelStyle::Primary
+                        && match label {
+                            MultiLabel::Top(range) => column_range.start >= range.end,
+                            MultiLabel::TopLeft | MultiLabel::Left => true,
+                            MultiLabel::Bottom(range, _) => column_range.end <= range.end,
+                        }
+                });
+
+                // Set the source color if we are in a primary label
+                if is_primary && !in_primary {
+                    self.set_color(self.styles().label(severity, LabelStyle::Primary))?;
+                    in_primary = true;
+                } else if !is_primary && in_primary {
+                    self.reset()?;
+                    in_primary = false;
+                }
+
                 match ch {
                     '\t' => (0..metrics.unicode_width).try_for_each(|_| write!(self, " "))?,
                     _ => write!(self, "{}", ch)?,
                 }
             }
+            if in_primary {
+                self.reset()?;
+            }
             write!(self, "\n")?;
         }
 
@@ -412,10 +439,8 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
                     None => None,
                 };
                 if let Some(caret_ch) = caret_ch {
-                    // FIXME: improve rendering for carets that occurring within character boundaries
-                    for _ in 0..metrics.unicode_width {
-                        write!(self, "{}", caret_ch)?;
-                    }
+                    // FIXME: improve rendering of carets between character boundaries
+                    (0..metrics.unicode_width).try_for_each(|_| write!(self, "{}", caret_ch))?;
                 }
 
                 previous_label_style = current_label_style;
@@ -497,11 +522,11 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
         //     │ ╰───│──────────────────^ woops
         //     │   ╭─│─────────^
         // ```
-        for (multi_label_index, (_, label)) in multi_labels.iter().enumerate() {
+        for (multi_label_index, (_, label_style, label)) in multi_labels.iter().enumerate() {
             let (label_style, range, bottom_message) = match label {
-                MultiLabel::TopLeft(_) | MultiLabel::Left(_) => continue, // no label caret needed
-                MultiLabel::Top(ls, range) => (*ls, range, None),
-                MultiLabel::Bottom(ls, range, message) => (*ls, range, Some(message)),
+                MultiLabel::TopLeft | MultiLabel::Left => continue, // no label caret needed
+                MultiLabel::Top(range) => (*label_style, range, None),
+                MultiLabel::Bottom(range, message) => (*label_style, range, Some(message)),
             };
 
             self.outer_gutter(outer_padding)?;
@@ -516,22 +541,22 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
             let mut multi_labels_iter = multi_labels.iter().enumerate().peekable();
             for label_column in 0..num_multi_labels {
                 match multi_labels_iter.peek() {
-                    Some((i, (label_index, label))) if *label_index == label_column => {
+                    Some((i, (label_index, ls, label))) if *label_index == label_column => {
                         match label {
-                            MultiLabel::TopLeft(ls) | MultiLabel::Left(ls) => {
+                            MultiLabel::TopLeft | MultiLabel::Left => {
                                 self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?;
                             }
-                            MultiLabel::Top(ls, ..) if multi_label_index > *i => {
+                            MultiLabel::Top(..) if multi_label_index > *i => {
                                 self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?;
                             }
-                            MultiLabel::Bottom(ls, ..) if multi_label_index < *i => {
+                            MultiLabel::Bottom(..) if multi_label_index < *i => {
                                 self.label_multi_left(severity, *ls, underline.map(|(s, _)| s))?;
                             }
-                            MultiLabel::Top(ls, ..) if multi_label_index == *i => {
+                            MultiLabel::Top(..) if multi_label_index == *i => {
                                 underline = Some((*ls, VerticalBound::Top));
                                 self.label_multi_top_left(severity, label_style)?
                             }
-                            MultiLabel::Bottom(ls, ..) if multi_label_index == *i => {
+                            MultiLabel::Bottom(..) if multi_label_index == *i => {
                                 underline = Some((*ls, VerticalBound::Bottom));
                                 self.label_multi_bottom_left(severity, label_style)?;
                             }
@@ -568,7 +593,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
         outer_padding: usize,
         severity: Severity,
         num_multi_labels: usize,
-        multi_labels: &[(usize, MultiLabel<'_>)],
+        multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
     ) -> io::Result<()> {
         self.outer_gutter(outer_padding)?;
         self.border_left()?;
@@ -587,7 +612,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
         outer_padding: usize,
         severity: Severity,
         num_multi_labels: usize,
-        multi_labels: &[(usize, MultiLabel<'_>)],
+        multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
     ) -> io::Result<()> {
         self.outer_gutter(outer_padding)?;
         self.border_left_break()?;
@@ -808,10 +833,9 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
             .char_metrics(source.char_indices())
             .take_while(|(metrics, _)| metrics.byte_index < range.end + 1)
         {
-            // FIXME: improve rendering for carets that occurring within character boundaries
-            for _ in 0..metrics.unicode_width {
-                write!(self, "{}", self.chars().multi_top)?;
-            }
+            // FIXME: improve rendering of carets between character boundaries
+            (0..metrics.unicode_width)
+                .try_for_each(|_| write!(self, "{}", self.chars().multi_top))?;
         }
 
         let caret_start = match label_style {
@@ -843,10 +867,9 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
             .char_metrics(source.char_indices())
             .take_while(|(metrics, _)| metrics.byte_index < range.end)
         {
-            // FIXME: improve rendering for carets that occurring within character boundaries
-            for _ in 0..metrics.unicode_width {
-                write!(self, "{}", self.chars().multi_bottom)?;
-            }
+            // FIXME: improve rendering of carets between character boundaries
+            (0..metrics.unicode_width)
+                .try_for_each(|_| write!(self, "{}", self.chars().multi_bottom))?;
         }
 
         let caret_end = match label_style {
@@ -893,16 +916,14 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
         &mut self,
         severity: Severity,
         num_multi_labels: usize,
-        multi_labels: &[(usize, MultiLabel<'_>)],
+        multi_labels: &[(usize, LabelStyle, MultiLabel<'_>)],
     ) -> io::Result<()> {
         let mut multi_labels_iter = multi_labels.iter().peekable();
         for label_column in 0..num_multi_labels {
             match multi_labels_iter.peek() {
-                Some((label_index, label)) if *label_index == label_column => match label {
-                    MultiLabel::TopLeft(label_style)
-                    | MultiLabel::Left(label_style)
-                    | MultiLabel::Bottom(label_style, ..) => {
-                        self.label_multi_left(severity, *label_style, None)?;
+                Some((label_index, ls, label)) if *label_index == label_column => match label {
+                    MultiLabel::TopLeft | MultiLabel::Left | MultiLabel::Bottom(..) => {
+                        self.label_multi_left(severity, *ls, None)?;
                         multi_labels_iter.next();
                     }
                     MultiLabel::Top(..) => {
@@ -910,7 +931,7 @@ impl<'writer, 'config> Renderer<'writer, 'config> {
                         multi_labels_iter.next();
                     }
                 },
-                Some((_, _)) | None => self.inner_gutter_space()?,
+                Some((_, _, _)) | None => self.inner_gutter_space()?,
             }
         }
 
diff --git a/codespan-reporting/src/term/views.rs b/codespan-reporting/src/term/views.rs
index 8422ede..aa79914 100644
--- a/codespan-reporting/src/term/views.rs
+++ b/codespan-reporting/src/term/views.rs
@@ -68,7 +68,7 @@ where
             range: std::ops::Range<usize>,
             // TODO: How do we reuse these allocations?
             single_labels: Vec<SingleLabel<'diagnostic>>,
-            multi_labels: Vec<(usize, MultiLabel<'diagnostic>)>,
+            multi_labels: Vec<(usize, LabelStyle, MultiLabel<'diagnostic>)>,
         }
 
         // TODO: Make this data structure external, to allow for allocation reuse
@@ -189,7 +189,7 @@ where
                         // ```text
                         // 4 │ ╭     case (mod num 5) (mod num 3) of
                         // ```
-                        "" => (label_index, MultiLabel::TopLeft(label.style)),
+                        "" => (label_index, label.style, MultiLabel::TopLeft),
                         // There's source code in the prefix, so run a label
                         // underneath it to get to the start of the range.
                         //
@@ -197,7 +197,7 @@ where
                         // 4 │   fizz₁ num = case (mod num 5) (mod num 3) of
                         //   │ ╭─────────────^
                         // ```
-                        _ => (label_index, MultiLabel::Top(label.style, ..label_start)),
+                        _ => (label_index, label.style, MultiLabel::Top(..label_start)),
                     });
 
                 // Marked lines
@@ -217,7 +217,7 @@ where
                     labeled_file
                         .get_or_insert_line(line_index, line_range, line_number)
                         .multi_labels
-                        .push((label_index, MultiLabel::Left(label.style)));
+                        .push((label_index, label.style, MultiLabel::Left));
                 }
 
                 // Last labeled line
@@ -233,7 +233,8 @@ where
                     .multi_labels
                     .push((
                         label_index,
-                        MultiLabel::Bottom(label.style, ..label_end, &label.message),
+                        label.style,
+                        MultiLabel::Bottom(..label_end, &label.message),
                     ));
             }
         }


Test patch:
diff --git a/codespan-reporting/tests/snapshots/term__empty_ranges__rich_color.snap b/codespan-reporting/tests/snapshots/term__empty_ranges__rich_color.snap
index b467854..89bb2c0 100644
--- a/codespan-reporting/tests/snapshots/term__empty_ranges__rich_color.snap
+++ b/codespan-reporting/tests/snapshots/term__empty_ranges__rich_color.snap
@@ -5,7 +5,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Green bold bright}note{bold bright}: middle{/}
   {fg:Blue}┌─{/} hello:1:7
   {fg:Blue}│{/}
-{fg:Blue}1{/} {fg:Blue}│{/} Hello world!
+{fg:Blue}1{/} {fg:Blue}│{/} Hello {fg:Green}w{/}orld!
   {fg:Blue}│{/}       {fg:Green}^{/} {fg:Green}middle{/}
 
 {fg:Green bold bright}note{bold bright}: end of line{/}
diff --git a/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_color.snap b/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_color.snap
index 11f9f68..a051eef 100644
--- a/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_color.snap
+++ b/codespan-reporting/tests/snapshots/term__fizz_buzz__rich_color.snap
@@ -12,7 +12,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Blue}5{/} {fg:Blue}│{/} {fg:Blue}│{/}     0 0 => "FizzBuzz"
 {fg:Blue}6{/} {fg:Blue}│{/} {fg:Blue}│{/}     0 _ => "Fizz"
 {fg:Blue}7{/} {fg:Blue}│{/} {fg:Blue}│{/}     _ 0 => "Buzz"
-{fg:Blue}8{/} {fg:Blue}│{/} {fg:Blue}│{/}     _ _ => num
+{fg:Blue}8{/} {fg:Blue}│{/} {fg:Blue}│{/}     _ _ => {fg:Red}num{/}
   {fg:Blue}│{/} {fg:Blue}│{/}            {fg:Red}^^^{/} {fg:Red}expected `String`, found `Nat`{/}
   {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────────────' `case` clauses have incompatible types{/}
   {fg:Blue}│{/}  
@@ -32,7 +32,7 @@ expression: TEST_DATA.emit_color(&config)
    {fg:Blue}│{/} {fg:Blue}│{/}                {fg:Blue}------{/} {fg:Blue}this is found to be of type `String`{/}
 {fg:Blue}15{/} {fg:Blue}│{/} {fg:Blue}│{/}         _ 0 => "Buzz"
    {fg:Blue}│{/} {fg:Blue}│{/}                {fg:Blue}------{/} {fg:Blue}this is found to be of type `String`{/}
-{fg:Blue}16{/} {fg:Blue}│{/} {fg:Blue}│{/}         _ _ => num
+{fg:Blue}16{/} {fg:Blue}│{/} {fg:Blue}│{/}         _ _ => {fg:Red}num{/}
    {fg:Blue}│{/} {fg:Blue}│{/}                {fg:Red}^^^{/} {fg:Red}expected `String`, found `Nat`{/}
    {fg:Blue}│{/} {fg:Blue}╰{/}{fg:Blue}──────────────────' `case` clauses have incompatible types{/}
    {fg:Blue}│{/}  
diff --git a/codespan-reporting/tests/snapshots/term__multifile__rich_color.snap b/codespan-reporting/tests/snapshots/term__multifile__rich_color.snap
index 53ede26..514be49 100644
--- a/codespan-reporting/tests/snapshots/term__multifile__rich_color.snap
+++ b/codespan-reporting/tests/snapshots/term__multifile__rich_color.snap
@@ -5,7 +5,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error{bold bright}: unknown builtin: `NATRAL`{/}
   {fg:Blue}┌─{/} Data/Nat.fun:7:13
   {fg:Blue}│{/}
-{fg:Blue}7{/} {fg:Blue}│{/} {-# BUILTIN NATRAL Nat #-}
+{fg:Blue}7{/} {fg:Blue}│{/} {-# BUILTIN {fg:Red}NATRAL{/} Nat #-}
   {fg:Blue}│{/}             {fg:Red}^^^^^^{/} {fg:Red}unknown builtin{/}
   {fg:Blue}│{/}
   {fg:Blue}={/} there is a builtin with a similar name: `NATURAL`
@@ -13,7 +13,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Yellow bold bright}warning{bold bright}: unused parameter pattern: `n₂`{/}
    {fg:Blue}┌─{/} Data/Nat.fun:17:16
    {fg:Blue}│{/}
-{fg:Blue}17{/} {fg:Blue}│{/} zero    - succ n₂ = zero
+{fg:Blue}17{/} {fg:Blue}│{/} zero    - succ {fg:Yellow}n₂{/} = zero
    {fg:Blue}│{/}                {fg:Yellow}^^{/} {fg:Yellow}unused parameter{/}
    {fg:Blue}│{/}
    {fg:Blue}={/} consider using a wildcard pattern: `_`
@@ -21,7 +21,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error[E0001]{bold bright}: unexpected type in application of `_+_`{/}
    {fg:Blue}┌─{/} Test.fun:4:11
    {fg:Blue}│{/}
-{fg:Blue} 4{/} {fg:Blue}│{/} _ = 123 + "hello"
+{fg:Blue} 4{/} {fg:Blue}│{/} _ = 123 + {fg:Red}"hello"{/}
    {fg:Blue}│{/}           {fg:Red}^^^^^^^{/} {fg:Red}expected `Nat`, found `String`{/}
    {fg:Blue}│{/}
    {fg:Blue}┌─{/} Data/Nat.fun:11:1
diff --git a/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_color.snap b/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_color.snap
index c927246..fee20e1 100644
--- a/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_color.snap
+++ b/codespan-reporting/tests/snapshots/term__multiline_overlapping__rich_color.snap
@@ -10,11 +10,11 @@ expression: TEST_DATA.emit_color(&config)
   {fg:Blue}│{/}   {fg:Blue}│{/}                               {fg:Blue}---------------------------------------------{/} {fg:Blue}this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`{/}
 {fg:Blue}3{/} {fg:Blue}│{/}   {fg:Blue}│{/}             Ordering::Equal => Ok(self.source_span().end()),
   {fg:Blue}│{/}   {fg:Blue}│{/}                                {fg:Blue}----------------------------{/} {fg:Blue}this is found to be of type `Result<ByteIndex, LineIndexOutOfBoundsError>`{/}
-{fg:Blue}4{/} {fg:Blue}│{/}   {fg:Blue}│{/}             Ordering::Greater => LineIndexOutOfBoundsError {
+{fg:Blue}4{/} {fg:Blue}│{/}   {fg:Blue}│{/}             Ordering::Greater => {fg:Red}LineIndexOutOfBoundsError {{/}
   {fg:Blue}│{/} {fg:Red}╭{/}{fg:Red}─{/}{fg:Blue}│{/}{fg:Red}──────────────────────────────────^{/}
-{fg:Blue}5{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/}                 given: line_index,
-{fg:Blue}6{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/}                 max: self.last_line_index(),
-{fg:Blue}7{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/}             },
+{fg:Blue}5{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red}                given: line_index,{/}
+{fg:Blue}6{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red}                max: self.last_line_index(),{/}
+{fg:Blue}7{/} {fg:Blue}│{/} {fg:Red}│{/} {fg:Blue}│{/} {fg:Red}            }{/},
   {fg:Blue}│{/} {fg:Red}╰{/}{fg:Red}─{/}{fg:Blue}│{/}{fg:Red}─────────────^ expected enum `Result`, found struct `LineIndexOutOfBoundsError`{/}
 {fg:Blue}8{/} {fg:Blue}│{/}   {fg:Blue}│{/}         }
   {fg:Blue}│{/}   {fg:Blue}╰{/}{fg:Blue}─────────' `match` arms have incompatible types{/}
diff --git a/codespan-reporting/tests/snapshots/term__overlapping__rich_color.snap b/codespan-reporting/tests/snapshots/term__overlapping__rich_color.snap
index 029a674..92f061f 100644
--- a/codespan-reporting/tests/snapshots/term__overlapping__rich_color.snap
+++ b/codespan-reporting/tests/snapshots/term__overlapping__rich_color.snap
@@ -5,7 +5,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error[E0666]{bold bright}: nested `impl Trait` is not allowed{/}
   {fg:Blue}┌─{/} nested_impl_trait.rs:5:46
   {fg:Blue}│{/}
-{fg:Blue}5{/} {fg:Blue}│{/} fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
+{fg:Blue}5{/} {fg:Blue}│{/} fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<{fg:Red}impl Debug{/}> { x }
   {fg:Blue}│{/}                                              {fg:Blue}----------{fg:Red}^^^^^^^^^^{fg:Blue}-{/}
   {fg:Blue}│{/}                                              {fg:Blue}│{/}         {fg:Red}│{/}
   {fg:Blue}│{/}                                              {fg:Blue}│{/}         {fg:Red}nested `impl Trait` here{/}
@@ -14,7 +14,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/}
   {fg:Blue}┌─{/} typeck_type_placeholder_item.rs:1:18
   {fg:Blue}│{/}
-{fg:Blue}1{/} {fg:Blue}│{/} fn fn_test1() -> _ { 5 }
+{fg:Blue}1{/} {fg:Blue}│{/} fn fn_test1() -> {fg:Red}_{/} { 5 }
   {fg:Blue}│{/}                  {fg:Red}^{/}
   {fg:Blue}│{/}                  {fg:Red}│{/}
   {fg:Blue}│{/}                  {fg:Red}not allowed in type signatures{/}
@@ -23,7 +23,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error[E0121]{bold bright}: the type placeholder `_` is not allowed within types on item signatures{/}
   {fg:Blue}┌─{/} typeck_type_placeholder_item.rs:2:24
   {fg:Blue}│{/}
-{fg:Blue}2{/} {fg:Blue}│{/} fn fn_test2(x: i32) -> (_, _) { (x, x) }
+{fg:Blue}2{/} {fg:Blue}│{/} fn fn_test2(x: i32) -> ({fg:Red}_{/}, {fg:Red}_{/}) { (x, x) }
   {fg:Blue}│{/}                        {fg:Blue}-{fg:Red}^{fg:Blue}--{fg:Red}^{fg:Blue}-{/}
   {fg:Blue}│{/}                        {fg:Blue}│{/}{fg:Red}│{/}  {fg:Red}│{/}
   {fg:Blue}│{/}                        {fg:Blue}│{/}{fg:Red}│{/}  {fg:Red}not allowed in type signatures{/}
@@ -33,7 +33,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error[E0277]{bold bright}: `std::rc::Rc<()>` cannot be sent between threads safely{/}
    {fg:Blue}┌─{/} no_send_res_ports.rs:25:5
    {fg:Blue}│{/}  
-{fg:Blue}25{/} {fg:Blue}│{/}       thread::spawn(move|| {
+{fg:Blue}25{/} {fg:Blue}│{/}       {fg:Red}thread::spawn{/}(move|| {
    {fg:Blue}│{/}       {fg:Red}^^^^^^^^^^^^^{/} {fg:Red}`std::rc::Rc<()>` cannot be sent between threads safely{/}
    {fg:Blue}│{/} {fg:Blue}╭{/}{fg:Blue}───────────────────'{/}
 {fg:Blue}26{/} {fg:Blue}│{/} {fg:Blue}│{/}         let y = x;
diff --git a/codespan-reporting/tests/snapshots/term__same_line__rich_color.snap b/codespan-reporting/tests/snapshots/term__same_line__rich_color.snap
index ad82cdf..59bd616 100644
--- a/codespan-reporting/tests/snapshots/term__same_line__rich_color.snap
+++ b/codespan-reporting/tests/snapshots/term__same_line__rich_color.snap
@@ -5,7 +5,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error[E0499]{bold bright}: cannot borrow `v` as mutable more than once at a time{/}
   {fg:Blue}┌─{/} one_line.rs:3:5
   {fg:Blue}│{/}
-{fg:Blue}3{/} {fg:Blue}│{/}     v.push(v.pop().unwrap());
+{fg:Blue}3{/} {fg:Blue}│{/}     v.push({fg:Red}v{/}.pop().unwrap());
   {fg:Blue}│{/}     {fg:Blue}-{/} {fg:Blue}----{/} {fg:Red}^{/} {fg:Red}second mutable borrow occurs here{/}
   {fg:Blue}│{/}     {fg:Blue}│{/} {fg:Blue}│{/}     
   {fg:Blue}│{/}     {fg:Blue}│{/} {fg:Blue}first mutable borrow occurs here{/}
diff --git a/codespan-reporting/tests/snapshots/term__same_ranges__rich_color.snap b/codespan-reporting/tests/snapshots/term__same_ranges__rich_color.snap
index 49d3c86..e6ec885 100644
--- a/codespan-reporting/tests/snapshots/term__same_ranges__rich_color.snap
+++ b/codespan-reporting/tests/snapshots/term__same_ranges__rich_color.snap
@@ -5,7 +5,7 @@ expression: TEST_DATA.emit_color(&config)
 {fg:Red bold bright}error{bold bright}: Unexpected token{/}
   {fg:Blue}┌─{/} same_range:1:5
   {fg:Blue}│{/}
-{fg:Blue}1{/} {fg:Blue}│{/} ::S { }
+{fg:Blue}1{/} {fg:Blue}│{/} ::S {fg:Red}{{/} }
   {fg:Blue}│{/}     {fg:Red}^{/}
   {fg:Blue}│{/}     {fg:Red}│{/}
   {fg:Blue}│{/}     {fg:Red}Unexpected '{'{/}