From 2b12c040948ccf9920a6c67448940a8a9b41e799 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sun, 12 Jul 2020 22:21:43 +0200 Subject: [PATCH 1/5] add test --- .../term__highlight__rich_color.snap | 36 ++++++++++++++ codespan-reporting/tests/term.rs | 48 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 codespan-reporting/tests/snapshots/term__highlight__rich_color.snap diff --git a/codespan-reporting/tests/snapshots/term__highlight__rich_color.snap b/codespan-reporting/tests/snapshots/term__highlight__rich_color.snap new file mode 100644 index 00000000..b375f47c --- /dev/null +++ b/codespan-reporting/tests/snapshots/term__highlight__rich_color.snap @@ -0,0 +1,36 @@ +--- +source: codespan-reporting/tests/term.rs +expression: TEST_DATA.emit_color(&config) +--- +{fg:Green bold bright}note{bold bright}: not highlighted{/} + {fg:Blue}┌─{/} test.txt:1:1 + {fg:Blue}│{/} +{fg:Blue}1{/} {fg:Blue}│{/} This is some text. + {fg:Blue}│{/} {fg:Green}^^^^^^^^^^^^^^^^^^{/} +{fg:Blue}2{/} {fg:Blue}│{/} This is some indented text. + {fg:Blue}│{/} {fg:Green}^^^^^^^^^^^^^^^^^^^^^^^^^^^{/} +{fg:Blue}3{/} {fg:Blue}│{/} This is some indented text with trailing whitespace. + {fg:Blue}│{/} {fg:Green}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^{/} + +{fg:Green bold bright}note{bold bright}: also not highlighted{/} + {fg:Blue}┌─{/} test.txt:2:1 + {fg:Blue}│{/} +{fg:Blue}2{/} {fg:Blue}│{/} This is some indented text. + {fg:Blue}│{/} {fg:Green}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^{/} +{fg:Blue}3{/} {fg:Blue}│{/} This is some indented text with trailing whitespace. + {fg:Blue}│{/} {fg:Green}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^{/} + +{fg:Green bold bright}note{bold bright}: highlighted{/} + {fg:Blue}┌─{/} test.txt:1:1 + {fg:Blue}│{/} +{fg:Blue}1{/} {fg:Blue}│{/} {fg:Green}This is some text{/}. + {fg:Blue}│{/} {fg:Green}^^^^^^^^^^^^^^^^^{/} +{fg:Blue}2{/} {fg:Blue}│{/} T{fg:Green}his is some indented text.{/} + {fg:Blue}│{/} {fg:Green}^^^^^^^^^^^^^^^^^^^^^^^^^^{/} +{fg:Blue}3{/} {fg:Blue}│{/} {fg:Green}This{/} is some indented text with trailing whitespace. + {fg:Blue}│{/} {fg:Green}^^^^{/} +{fg:Blue}4{/} {fg:Blue}│{/} {fg:Green}╭{/} This is some multiline text. +{fg:Blue}5{/} {fg:Blue}│{/} {fg:Green}│{/} This is some more multiline text. + {fg:Blue}│{/} {fg:Green}╰{/}{fg:Green}─────────────────────────────────^{/} + + diff --git a/codespan-reporting/tests/term.rs b/codespan-reporting/tests/term.rs index df1b263b..727e414c 100644 --- a/codespan-reporting/tests/term.rs +++ b/codespan-reporting/tests/term.rs @@ -845,6 +845,54 @@ mod unicode_spans { test_emit!(short_no_color); } +mod highlight { + use super::*; + + lazy_static::lazy_static! { + static ref TEST_DATA: TestData<'static, SimpleFile<&'static str, String>> = { + let file = SimpleFile::new( + "test.txt", + [ + "This is some text.", + "\tThis is some indented text.", + "\tThis is some indented text with trailing whitespace. \t", + "This is some multiline text.", + "This is some more multiline text.", + ] + .join("\n"), + ); + + let diagnostics = vec![ + Diagnostic::note() + .with_message("not highlighted") + .with_labels(vec![ + Label::primary((), 0..18), + Label::primary((), 20..47), + Label::primary((), 49..101), + ]), + Diagnostic::note() + .with_message("also not highlighted") + .with_labels(vec![ + Label::primary((), 19..47), + Label::primary((), 48..103), + ]), + Diagnostic::note() + .with_message("highlighted") + .with_labels(vec![ + Label::primary((), 0..17), + Label::primary((), 21..47), + Label::primary((), 49..53), + Label::primary((), 104..166), + ]), + ]; + + TestData{files: file, diagnostics } + }; + } + + test_emit!(rich_color); +} + mod multiline_omit { use super::*; From 05a2559adb4e963d976241259b17768674e69f97 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sun, 12 Jul 2020 23:25:40 +0200 Subject: [PATCH 2/5] better highlighting --- codespan-reporting/src/term/renderer.rs | 57 ++++++++++++++++++------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/codespan-reporting/src/term/renderer.rs b/codespan-reporting/src/term/renderer.rs index 80b4f515..8c9bc039 100644 --- a/codespan-reporting/src/term/renderer.rs +++ b/codespan-reporting/src/term/renderer.rs @@ -244,6 +244,27 @@ impl<'writer, 'config> Renderer<'writer, 'config> { // FIXME: Use the number of trimmed placeholders when rendering single line carets let source = source.trim_end_matches(['\n', '\r', '\0'].as_ref()); + // count the number of whitespace characters + let text_start = source.chars().take_while(|c| c.is_whitespace()).count(); + + // get the byte index of the first non-whitespace character + let text_start = source + .char_indices() + .nth(text_start) + .map(|(index, _)| index) + .unwrap_or(0); + + // get the byte index of the first trailing whitespace character + let text_end = source + .char_indices() + .rev() + .take_while(|(_, c)| c.is_whitespace()) + .last() + .map(|(index, _)| index) + .unwrap_or_else(|| source.len()); + + let text_range = text_start..text_end; + // Write source line // // ```text @@ -276,37 +297,43 @@ impl<'writer, 'config> Renderer<'writer, 'config> { // Write source text write!(self, " ")?; - let mut in_primary = false; + let mut highlighted = false; + + // iterate over all characters of source code 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)| { + /* + A character should be highlighted only if it is part of a primary single label which does not span the whole line + A label already spans the whole line if it does not cover leading/trailing whitespace. + */ + let should_highlight = single_labels.iter().any(|(ls, range, _)| { *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, - } + // is this at the current position + && is_overlapping(range, &column_range) + // is this not a whole line label + && !( + range.start <= text_range.start + && range.end >= text_range.end + ) }); // Set the source color if we are in a primary label - if is_primary && !in_primary { + if should_highlight && !highlighted { self.set_color(self.styles().label(severity, LabelStyle::Primary))?; - in_primary = true; - } else if !is_primary && in_primary { + highlighted = true; + } else if !should_highlight && highlighted { self.reset()?; - in_primary = false; + highlighted = false; } + // actually write the character match ch { '\t' => (0..metrics.unicode_width).try_for_each(|_| write!(self, " "))?, _ => write!(self, "{}", ch)?, } } - if in_primary { + if highlighted { self.reset()?; } write!(self, "\n")?; From 09c2bbe5d3856cc5b3261b09a9a4a1ae29d36c37 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Sun, 12 Jul 2020 23:36:10 +0200 Subject: [PATCH 3/5] update test multiline labels are not highlighted any more --- .../term__multiline_overlapping__rich_color.snap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 fee20e10..c9272461 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`{/} {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`{/} -{fg:Blue}4{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Greater => {fg:Red}LineIndexOutOfBoundsError {{/} +{fg:Blue}4{/} {fg:Blue}│{/} {fg:Blue}│{/} Ordering::Greater => LineIndexOutOfBoundsError { {fg:Blue}│{/} {fg:Red}╭{/}{fg:Red}─{/}{fg:Blue}│{/}{fg:Red}──────────────────────────────────^{/} -{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}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}│{/} {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{/} From 23313c2c04c01e22ae7b9ad1e8a78e7e12040620 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Mon, 13 Jul 2020 18:08:49 +0200 Subject: [PATCH 4/5] fix formatting --- codespan-reporting/tests/term.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/codespan-reporting/tests/term.rs b/codespan-reporting/tests/term.rs index b9b948c9..ccadd1da 100644 --- a/codespan-reporting/tests/term.rs +++ b/codespan-reporting/tests/term.rs @@ -879,7 +879,6 @@ mod position_indicator { test_emit!(rich_no_color); test_emit!(short_no_color); - } mod multiline_omit { @@ -1003,4 +1002,4 @@ mod highlight { } test_emit!(rich_color); -} \ No newline at end of file +} From fc8b8946f00075f399ea11d3cad2383e62b20451 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Fri, 29 Jan 2021 17:12:32 +0100 Subject: [PATCH 5/5] simplify getting the first non-whitespace char --- codespan-reporting/src/term/renderer.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/codespan-reporting/src/term/renderer.rs b/codespan-reporting/src/term/renderer.rs index 3e249cec..0baff60e 100644 --- a/codespan-reporting/src/term/renderer.rs +++ b/codespan-reporting/src/term/renderer.rs @@ -240,15 +240,8 @@ impl<'writer, 'config> Renderer<'writer, 'config> { // FIXME: Use the number of trimmed placeholders when rendering single line carets let source = source.trim_end_matches(['\n', '\r', '\0'].as_ref()); - // count the number of whitespace characters - let text_start = source.chars().take_while(|c| c.is_whitespace()).count(); - // get the byte index of the first non-whitespace character - let text_start = source - .char_indices() - .nth(text_start) - .map(|(index, _)| index) - .unwrap_or(0); + let text_start = source.find(|c| !char::is_whitespace(c)).unwrap_or(0); // get the byte index of the first trailing whitespace character let text_end = source