aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_db/src/line_index.rs12
-rw-r--r--crates/rust-analyzer/src/main_loop.rs18
2 files changed, 26 insertions, 4 deletions
diff --git a/crates/ra_ide_db/src/line_index.rs b/crates/ra_ide_db/src/line_index.rs
index 00ba95913..212cb7b5b 100644
--- a/crates/ra_ide_db/src/line_index.rs
+++ b/crates/ra_ide_db/src/line_index.rs
@@ -8,7 +8,9 @@ use superslice::Ext;
8 8
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct LineIndex { 10pub struct LineIndex {
11 /// Offset the the beginning of each line, zero-based
11 pub(crate) newlines: Vec<TextSize>, 12 pub(crate) newlines: Vec<TextSize>,
13 /// List of non-ASCII characters on each line
12 pub(crate) utf16_lines: FxHashMap<u32, Vec<Utf16Char>>, 14 pub(crate) utf16_lines: FxHashMap<u32, Vec<Utf16Char>>,
13} 15}
14 16
@@ -22,7 +24,9 @@ pub struct LineCol {
22 24
23#[derive(Clone, Debug, Hash, PartialEq, Eq)] 25#[derive(Clone, Debug, Hash, PartialEq, Eq)]
24pub(crate) struct Utf16Char { 26pub(crate) struct Utf16Char {
27 /// Start offset of a character inside a line, zero-based
25 pub(crate) start: TextSize, 28 pub(crate) start: TextSize,
29 /// End offset of a character inside a line, zero-based
26 pub(crate) end: TextSize, 30 pub(crate) end: TextSize,
27} 31}
28 32
@@ -120,7 +124,7 @@ impl LineIndex {
120 fn utf16_to_utf8_col(&self, line: u32, mut col: u32) -> TextSize { 124 fn utf16_to_utf8_col(&self, line: u32, mut col: u32) -> TextSize {
121 if let Some(utf16_chars) = self.utf16_lines.get(&line) { 125 if let Some(utf16_chars) = self.utf16_lines.get(&line) {
122 for c in utf16_chars { 126 for c in utf16_chars {
123 if col >= u32::from(c.start) { 127 if col > u32::from(c.start) {
124 col += u32::from(c.len()) - 1; 128 col += u32::from(c.len()) - 1;
125 } else { 129 } else {
126 // From here on, all utf16 characters come *after* the character we are mapping, 130 // From here on, all utf16 characters come *after* the character we are mapping,
@@ -226,8 +230,10 @@ const C: char = \"メ メ\";
226 // UTF-16 to UTF-8 230 // UTF-16 to UTF-8
227 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15)); 231 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextSize::from(15));
228 232
229 assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); 233 // メ UTF-8: 0xE3 0x83 0xA1, UTF-16: 0x30E1
230 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(23)); 234 assert_eq!(col_index.utf16_to_utf8_col(1, 17), TextSize::from(17)); // first メ at 17..20
235 assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextSize::from(20)); // space
236 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextSize::from(21)); // second メ at 21..24
231 237
232 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15)); 238 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextSize::from(15));
233 } 239 }
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 3bc2e0a46..401fae755 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -666,6 +666,10 @@ fn apply_document_changes(
666 mut line_index: Cow<'_, LineIndex>, 666 mut line_index: Cow<'_, LineIndex>,
667 content_changes: Vec<TextDocumentContentChangeEvent>, 667 content_changes: Vec<TextDocumentContentChangeEvent>,
668) { 668) {
669 // Remove when https://github.com/rust-analyzer/rust-analyzer/issues/4263 is fixed.
670 let backup_text = old_text.clone();
671 let backup_changes = content_changes.clone();
672
669 // The changes we got must be applied sequentially, but can cross lines so we 673 // The changes we got must be applied sequentially, but can cross lines so we
670 // have to keep our line index updated. 674 // have to keep our line index updated.
671 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we 675 // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
@@ -693,7 +697,19 @@ fn apply_document_changes(
693 } 697 }
694 index_valid = IndexValid::UpToLine(range.start.line); 698 index_valid = IndexValid::UpToLine(range.start.line);
695 let range = range.conv_with(&line_index); 699 let range = range.conv_with(&line_index);
696 old_text.replace_range(Range::<usize>::from(range), &change.text); 700 let mut text = old_text.to_owned();
701 match std::panic::catch_unwind(move || {
702 text.replace_range(Range::<usize>::from(range), &change.text);
703 text
704 }) {
705 Ok(t) => *old_text = t,
706 Err(e) => {
707 eprintln!("Bug in incremental text synchronization. Please report the following output on https://github.com/rust-analyzer/rust-analyzer/issues/4263");
708 dbg!(&backup_text);
709 dbg!(&backup_changes);
710 std::panic::resume_unwind(e);
711 }
712 }
697 } 713 }
698 None => { 714 None => {
699 *old_text = change.text; 715 *old_text = change.text;