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]
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::{
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()
};
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);
.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]
);
}
- 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 = {
result.apply(&mut actual);
actual
};
- assert_eq_text!(after, &actual);
+ assert_eq_text!(ra_fixture_after, &actual);
}
#[test]
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 {
}
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);
}
}
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
type RangesMap = BTreeMap<TextSize, TextSize>;
--- /dev/null
+
+<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>
\ No newline at end of file
)
}
+#[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.
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.
///