From f459375f4873d601b6a0e2c3c5d29be569b3e067 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 7 Jan 2021 18:21:00 +0300 Subject: Better fixture highlight --- crates/assists/src/handlers/flip_comma.rs | 6 +-- crates/base_db/src/fixture.rs | 16 +++++-- crates/ide/src/join_lines.rs | 12 ++--- crates/ide/src/syntax_highlighting/injection.rs | 56 ++++++++++++++++++++-- .../syntax_highlighting/test_data/injection.html | 48 +++++++++++++++++++ crates/ide/src/syntax_highlighting/tests.rs | 19 ++++++++ crates/test_utils/src/lib.rs | 1 + 7 files changed, 140 insertions(+), 18 deletions(-) create mode 100644 crates/ide/src/syntax_highlighting/test_data/injection.html diff --git a/crates/assists/src/handlers/flip_comma.rs b/crates/assists/src/handlers/flip_comma.rs index a48b0e450..18cf64a34 100644 --- a/crates/assists/src/handlers/flip_comma.rs +++ b/crates/assists/src/handlers/flip_comma.rs @@ -49,14 +49,14 @@ mod tests { fn flip_comma_works_for_function_parameters() { check_assist( flip_comma, - "fn foo(x: i32,$0 y: Result<(), ()>) {}", - "fn foo(y: Result<(), ()>, x: i32) {}", + r#"fn foo(x: i32,$0 y: Result<(), ()>) {}"#, + r#"fn foo(y: Result<(), ()>, x: i32) {}"#, ) } #[test] fn flip_comma_target() { - check_assist_target(flip_comma, "fn foo(x: i32,$0 y: Result<(), ()>) {}", ",") + check_assist_target(flip_comma, r#"fn foo(x: i32,$0 y: Result<(), ()>) {}"#, ",") } #[test] diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index 66e6443cb..98acd61b1 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs @@ -61,7 +61,9 @@ use std::{str::FromStr, sync::Arc}; use cfg::CfgOptions; use rustc_hash::FxHashMap; -use test_utils::{extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER}; +use test_utils::{ + extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER, +}; use vfs::{file_set::FileSet, VfsPath}; use crate::{ @@ -142,10 +144,14 @@ impl ChangeFixture { for entry in fixture { let text = if entry.text.contains(CURSOR_MARKER) { - let (range_or_offset, text) = extract_range_or_offset(&entry.text); - assert!(file_position.is_none()); - file_position = Some((file_id, range_or_offset)); - text.to_string() + if entry.text.contains(ESCAPED_CURSOR_MARKER) { + entry.text.replace(ESCAPED_CURSOR_MARKER, CURSOR_MARKER) + } else { + let (range_or_offset, text) = extract_range_or_offset(&entry.text); + assert!(file_position.is_none()); + file_position = Some((file_id, range_or_offset)); + text.to_string() + } } else { entry.text.clone() }; diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 296893d2f..05380f2a1 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs @@ -198,8 +198,8 @@ mod tests { use super::*; - fn check_join_lines(before: &str, after: &str) { - let (before_cursor_pos, before) = extract_offset(before); + fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) { + let (before_cursor_pos, before) = extract_offset(ra_fixture_before); let file = SourceFile::parse(&before).ok().unwrap(); let range = TextRange::empty(before_cursor_pos); @@ -214,7 +214,7 @@ mod tests { .apply_to_offset(before_cursor_pos) .expect("cursor position is affected by the edit"); let actual = add_cursor(&actual, actual_cursor_pos); - assert_eq_text!(after, &actual); + assert_eq_text!(ra_fixture_after, &actual); } #[test] @@ -604,8 +604,8 @@ fn foo() { ); } - fn check_join_lines_sel(before: &str, after: &str) { - let (sel, before) = extract_range(before); + fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) { + let (sel, before) = extract_range(ra_fixture_before); let parse = SourceFile::parse(&before); let result = join_lines(&parse.tree(), sel); let actual = { @@ -613,7 +613,7 @@ fn foo() { result.apply(&mut actual); actual }; - assert_eq_text!(after, &actual); + assert_eq_text!(ra_fixture_after, &actual); } #[test] diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs index 6cbd683c6..d6be9708d 100644 --- a/crates/ide/src/syntax_highlighting/injection.rs +++ b/crates/ide/src/syntax_highlighting/injection.rs @@ -22,7 +22,8 @@ pub(super) fn highlight_injection( return None; } let value = literal.value()?; - let (analysis, tmp_file_id) = Analysis::from_single_file(value.into_owned()); + let marker_info = MarkerInfo::new(&*value); + let (analysis, tmp_file_id) = Analysis::from_single_file(marker_info.cleaned_text.clone()); if let Some(range) = literal.open_quote_text_range() { acc.add(HighlightedRange { @@ -33,9 +34,10 @@ pub(super) fn highlight_injection( } for mut h in analysis.highlight(tmp_file_id).unwrap() { - if let Some(r) = literal.map_range_up(h.range) { - h.range = r; - acc.add(h) + let range = marker_info.map_range_up(h.range); + if let Some(range) = literal.map_range_up(range) { + h.range = range; + acc.add(h); } } @@ -50,6 +52,52 @@ pub(super) fn highlight_injection( Some(()) } +/// Data to remove `$0` from string and map ranges +#[derive(Default, Debug)] +struct MarkerInfo { + cleaned_text: String, + markers: Vec, +} + +impl MarkerInfo { + fn new(mut text: &str) -> Self { + let marker = "$0"; + + let mut res = MarkerInfo::default(); + let mut offset: TextSize = 0.into(); + while !text.is_empty() { + let idx = text.find(marker).unwrap_or(text.len()); + let (chunk, next) = text.split_at(idx); + text = next; + res.cleaned_text.push_str(chunk); + offset += TextSize::of(chunk); + + if let Some(next) = text.strip_prefix(marker) { + text = next; + + let marker_len = TextSize::of(marker); + res.markers.push(TextRange::at(offset, marker_len)); + offset += marker_len; + } + } + res + } + fn map_range_up(&self, range: TextRange) -> TextRange { + TextRange::new( + self.map_offset_up(range.start(), true), + self.map_offset_up(range.end(), false), + ) + } + fn map_offset_up(&self, mut offset: TextSize, start: bool) -> TextSize { + for r in &self.markers { + if r.start() < offset || (start && r.start() == offset) { + offset += r.len() + } + } + offset + } +} + /// Mapping from extracted documentation code to original code type RangesMap = BTreeMap; diff --git a/crates/ide/src/syntax_highlighting/test_data/injection.html b/crates/ide/src/syntax_highlighting/test_data/injection.html new file mode 100644 index 000000000..a54d303b4 --- /dev/null +++ b/crates/ide/src/syntax_highlighting/test_data/injection.html @@ -0,0 +1,48 @@ + + +
fn f(ra_fixture: &str) {}
+fn main() {
+    f(r"
+fn foo() {
+    foo($0{
+        92
+    }$0)
+}");
+}
+    
\ No newline at end of file diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index 30b5b648e..9e1a3974c 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs @@ -555,6 +555,25 @@ impl t for foo { ) } +#[test] +fn test_injection() { + check_highlighting( + r##" +fn f(ra_fixture: &str) {} +fn main() { + f(r" +fn foo() { + foo(\$0{ + 92 + }\$0) +}"); +} + "##, + expect_file!["./test_data/injection.html"], + false, + ); +} + /// Highlights the code given by the `ra_fixture` argument, renders the /// result as HTML, and compares it with the HTML file given as `snapshot`. /// Note that the `snapshot` file is overwritten by the rendered HTML. diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 05d6e8c9e..84c1d7ebb 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -26,6 +26,7 @@ pub use rustc_hash::FxHashMap; pub use crate::fixture::Fixture; pub const CURSOR_MARKER: &str = "$0"; +pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; /// Asserts that two strings are equal, otherwise displays a rich diff between them. /// -- cgit v1.2.3