mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
Better fixture highlight
This commit is contained in:
parent
7967ce85cf
commit
f459375f48
7 changed files with 140 additions and 18 deletions
|
@ -49,14 +49,14 @@ mod tests {
|
||||||
fn flip_comma_works_for_function_parameters() {
|
fn flip_comma_works_for_function_parameters() {
|
||||||
check_assist(
|
check_assist(
|
||||||
flip_comma,
|
flip_comma,
|
||||||
"fn foo(x: i32,$0 y: Result<(), ()>) {}",
|
r#"fn foo(x: i32,$0 y: Result<(), ()>) {}"#,
|
||||||
"fn foo(y: Result<(), ()>, x: i32) {}",
|
r#"fn foo(y: Result<(), ()>, x: i32) {}"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flip_comma_target() {
|
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]
|
#[test]
|
||||||
|
|
|
@ -61,7 +61,9 @@ use std::{str::FromStr, sync::Arc};
|
||||||
|
|
||||||
use cfg::CfgOptions;
|
use cfg::CfgOptions;
|
||||||
use rustc_hash::FxHashMap;
|
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 vfs::{file_set::FileSet, VfsPath};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -142,10 +144,14 @@ impl ChangeFixture {
|
||||||
|
|
||||||
for entry in fixture {
|
for entry in fixture {
|
||||||
let text = if entry.text.contains(CURSOR_MARKER) {
|
let text = if entry.text.contains(CURSOR_MARKER) {
|
||||||
|
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);
|
let (range_or_offset, text) = extract_range_or_offset(&entry.text);
|
||||||
assert!(file_position.is_none());
|
assert!(file_position.is_none());
|
||||||
file_position = Some((file_id, range_or_offset));
|
file_position = Some((file_id, range_or_offset));
|
||||||
text.to_string()
|
text.to_string()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
entry.text.clone()
|
entry.text.clone()
|
||||||
};
|
};
|
||||||
|
|
|
@ -198,8 +198,8 @@ mod tests {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn check_join_lines(before: &str, after: &str) {
|
fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||||
let (before_cursor_pos, before) = extract_offset(before);
|
let (before_cursor_pos, before) = extract_offset(ra_fixture_before);
|
||||||
let file = SourceFile::parse(&before).ok().unwrap();
|
let file = SourceFile::parse(&before).ok().unwrap();
|
||||||
|
|
||||||
let range = TextRange::empty(before_cursor_pos);
|
let range = TextRange::empty(before_cursor_pos);
|
||||||
|
@ -214,7 +214,7 @@ mod tests {
|
||||||
.apply_to_offset(before_cursor_pos)
|
.apply_to_offset(before_cursor_pos)
|
||||||
.expect("cursor position is affected by the edit");
|
.expect("cursor position is affected by the edit");
|
||||||
let actual = add_cursor(&actual, actual_cursor_pos);
|
let actual = add_cursor(&actual, actual_cursor_pos);
|
||||||
assert_eq_text!(after, &actual);
|
assert_eq_text!(ra_fixture_after, &actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -604,8 +604,8 @@ fn foo() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_join_lines_sel(before: &str, after: &str) {
|
fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) {
|
||||||
let (sel, before) = extract_range(before);
|
let (sel, before) = extract_range(ra_fixture_before);
|
||||||
let parse = SourceFile::parse(&before);
|
let parse = SourceFile::parse(&before);
|
||||||
let result = join_lines(&parse.tree(), sel);
|
let result = join_lines(&parse.tree(), sel);
|
||||||
let actual = {
|
let actual = {
|
||||||
|
@ -613,7 +613,7 @@ fn foo() {
|
||||||
result.apply(&mut actual);
|
result.apply(&mut actual);
|
||||||
actual
|
actual
|
||||||
};
|
};
|
||||||
assert_eq_text!(after, &actual);
|
assert_eq_text!(ra_fixture_after, &actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -22,7 +22,8 @@ pub(super) fn highlight_injection(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let value = literal.value()?;
|
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() {
|
if let Some(range) = literal.open_quote_text_range() {
|
||||||
acc.add(HighlightedRange {
|
acc.add(HighlightedRange {
|
||||||
|
@ -33,9 +34,10 @@ pub(super) fn highlight_injection(
|
||||||
}
|
}
|
||||||
|
|
||||||
for mut h in analysis.highlight(tmp_file_id).unwrap() {
|
for mut h in analysis.highlight(tmp_file_id).unwrap() {
|
||||||
if let Some(r) = literal.map_range_up(h.range) {
|
let range = marker_info.map_range_up(h.range);
|
||||||
h.range = r;
|
if let Some(range) = literal.map_range_up(range) {
|
||||||
acc.add(h)
|
h.range = range;
|
||||||
|
acc.add(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +52,52 @@ pub(super) fn highlight_injection(
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data to remove `$0` from string and map ranges
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct MarkerInfo {
|
||||||
|
cleaned_text: String,
|
||||||
|
markers: Vec<TextRange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
/// Mapping from extracted documentation code to original code
|
||||||
type RangesMap = BTreeMap<TextSize, TextSize>;
|
type RangesMap = BTreeMap<TextSize, TextSize>;
|
||||||
|
|
||||||
|
|
48
crates/ide/src/syntax_highlighting/test_data/injection.html
Normal file
48
crates/ide/src/syntax_highlighting/test_data/injection.html
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body { margin: 0; }
|
||||||
|
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
|
||||||
|
|
||||||
|
.lifetime { color: #DFAF8F; font-style: italic; }
|
||||||
|
.label { 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; }
|
||||||
|
.field { color: #94BFF3; }
|
||||||
|
.function { color: #93E0E3; }
|
||||||
|
.function.unsafe { color: #BC8383; }
|
||||||
|
.operator.unsafe { color: #BC8383; }
|
||||||
|
.parameter { color: #94BFF3; }
|
||||||
|
.text { color: #DCDCCC; }
|
||||||
|
.type { color: #7CB8BB; }
|
||||||
|
.builtin_type { color: #8CD0D3; }
|
||||||
|
.type_param { color: #DFAF8F; }
|
||||||
|
.attribute { color: #94BFF3; }
|
||||||
|
.numeric_literal { color: #BFEBBF; }
|
||||||
|
.bool_literal { color: #BFE6EB; }
|
||||||
|
.macro { color: #94BFF3; }
|
||||||
|
.module { color: #AFD8AF; }
|
||||||
|
.value_param { color: #DCDCCC; }
|
||||||
|
.variable { color: #DCDCCC; }
|
||||||
|
.format_specifier { color: #CC696B; }
|
||||||
|
.mutable { text-decoration: underline; }
|
||||||
|
.escape_sequence { color: #94BFF3; }
|
||||||
|
.keyword { color: #F0DFAF; font-weight: bold; }
|
||||||
|
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||||
|
.control { font-style: italic; }
|
||||||
|
|
||||||
|
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||||
|
</style>
|
||||||
|
<pre><code><span class="keyword">fn</span> <span class="function declaration">f</span><span class="punctuation">(</span><span class="value_param declaration">ra_fixture</span><span class="punctuation">:</span> <span class="operator">&</span><span class="builtin_type">str</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span>
|
||||||
|
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
||||||
|
<span class="function">f</span><span class="punctuation">(</span><span class="string_literal">r"</span>
|
||||||
|
<span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span>
|
||||||
|
<span class="function">foo</span><span class="punctuation">(</span>$0<span class="punctuation">{</span>
|
||||||
|
<span class="numeric_literal">92</span>
|
||||||
|
<span class="punctuation">}</span>$0<span class="punctuation">)</span>
|
||||||
|
<span class="punctuation">}</span><span class="string_literal">"</span><span class="punctuation">)</span><span class="punctuation">;</span>
|
||||||
|
<span class="punctuation">}</span>
|
||||||
|
</code></pre>
|
|
@ -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
|
/// Highlights the code given by the `ra_fixture` argument, renders the
|
||||||
/// result as HTML, and compares it with the HTML file given as `snapshot`.
|
/// result as HTML, and compares it with the HTML file given as `snapshot`.
|
||||||
/// Note that the `snapshot` file is overwritten by the rendered HTML.
|
/// Note that the `snapshot` file is overwritten by the rendered HTML.
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub use rustc_hash::FxHashMap;
|
||||||
pub use crate::fixture::Fixture;
|
pub use crate::fixture::Fixture;
|
||||||
|
|
||||||
pub const CURSOR_MARKER: &str = "$0";
|
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.
|
/// Asserts that two strings are equal, otherwise displays a rich diff between them.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in a new issue