From bb55d654ce83c444707b9cf8a7c6f7316b305de5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 25 Jul 2022 14:50:09 +0200 Subject: [PATCH] Handle IME composition with multiple cursors --- crates/editor/src/editor.rs | 110 +++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 27 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 2a187c58b2..29d51f6e0f 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5739,6 +5739,17 @@ impl Editor { }) .detach() } + + fn marked_text_ranges<'a>( + &'a self, + cx: &'a AppContext, + ) -> Option>> { + let snapshot = self.buffer.read(cx).read(cx); + let (_, ranges) = self.text_highlights::(cx)?; + Some(ranges.into_iter().map(move |range| { + range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot) + })) + } } impl EditorSnapshot { @@ -5922,11 +5933,8 @@ impl View for Editor { } fn marked_text_range(&self, cx: &AppContext) -> Option> { - let range = self.text_highlights::(cx)?.1.get(0)?; - let snapshot = self.buffer.read(cx).read(cx); - let range_utf16 = - range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot); - Some(range_utf16.start.0..range_utf16.end.0) + let range = self.marked_text_ranges(cx)?.next()?; + Some(range.start.0..range.end.0) } fn unmark_text(&mut self, cx: &mut ViewContext) { @@ -5946,9 +5954,32 @@ impl View for Editor { } self.transact(cx, |this, cx| { - if let Some(range) = range_utf16.or_else(|| this.marked_text_range(cx)) { + let new_selected_ranges = if let Some(range_utf16) = range_utf16 { + let selected_range = this.selected_text_range(cx).unwrap(); + let start_delta = range_utf16.start as isize - selected_range.start as isize; + let end_delta = range_utf16.end as isize - selected_range.end as isize; + Some( + this.selections + .all::(cx) + .into_iter() + .map(|mut selection| { + selection.start.0 = + (selection.start.0 as isize).saturating_add(start_delta) as usize; + selection.end.0 = + (selection.end.0 as isize).saturating_add(end_delta) as usize; + selection.start..selection.end + }) + .collect::>(), + ) + } else if let Some(marked_ranges) = this.marked_text_ranges(cx) { + Some(marked_ranges.collect()) + } else { + None + }; + + if let Some(new_selected_ranges) = new_selected_ranges { this.change_selections(None, cx, |selections| { - selections.select_ranges([OffsetUtf16(range.start)..OffsetUtf16(range.end)]) + selections.select_ranges(new_selected_ranges) }); } this.handle_input(text, cx); @@ -5976,35 +6007,56 @@ impl View for Editor { } let transaction = self.transact(cx, |this, cx| { - let range_to_replace = if let Some(mut marked_range) = this.marked_text_range(cx) { + let ranges_to_replace = if let Some(marked_ranges) = this.marked_text_ranges(cx) { + let mut marked_ranges = marked_ranges.collect::>(); if let Some(relative_range_utf16) = range_utf16.as_ref() { - marked_range.end = marked_range.start + relative_range_utf16.end; - marked_range.start += relative_range_utf16.start; + for marked_range in &mut marked_ranges { + marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end; + marked_range.start.0 += relative_range_utf16.start; + } } - Some(marked_range) + Some(marked_ranges) } else if let Some(range_utf16) = range_utf16 { - Some(range_utf16) + let selected_range = this.selected_text_range(cx).unwrap(); + let start_delta = range_utf16.start as isize - selected_range.start as isize; + let end_delta = range_utf16.end as isize - selected_range.end as isize; + Some( + this.selections + .all::(cx) + .into_iter() + .map(|mut selection| { + selection.start.0 = + (selection.start.0 as isize).saturating_add(start_delta) as usize; + selection.end.0 = + (selection.end.0 as isize).saturating_add(end_delta) as usize; + selection.start..selection.end + }) + .collect::>(), + ) } else { None }; - if let Some(range) = range_to_replace { - this.change_selections(None, cx, |s| { - s.select_ranges([OffsetUtf16(range.start)..OffsetUtf16(range.end)]) - }); + if let Some(ranges) = ranges_to_replace { + this.change_selections(None, cx, |s| s.select_ranges(ranges)); } - let selection = this.selections.newest_anchor(); - let marked_range = { + let marked_ranges = { let snapshot = this.buffer.read(cx).read(cx); - selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot) + this.selections + .disjoint_anchors() + .into_iter() + .map(|selection| { + selection.start.bias_left(&*snapshot)..selection.end.bias_right(&*snapshot) + }) + .collect::>() }; if text.is_empty() { this.unmark_text(cx); } else { this.highlight_text::( - vec![marked_range.clone()], + marked_ranges.clone(), this.style(cx).composition_mark, cx, ); @@ -6012,16 +6064,20 @@ impl View for Editor { this.handle_input(text, cx); - if let Some(mut new_selected_range) = new_selected_range_utf16 { + if let Some(new_selected_range) = new_selected_range_utf16 { let snapshot = this.buffer.read(cx).read(cx); - let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0; - new_selected_range.start += insertion_start; - new_selected_range.end += insertion_start; + let new_selected_ranges = marked_ranges + .into_iter() + .map(|marked_range| { + let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0; + OffsetUtf16(new_selected_range.start + insertion_start) + ..OffsetUtf16(new_selected_range.end + insertion_start) + }) + .collect::>(); + drop(snapshot); this.change_selections(None, cx, |selections| { - selections - .select_ranges([OffsetUtf16(new_selected_range.start) - ..OffsetUtf16(new_selected_range.end)]) + selections.select_ranges(new_selected_ranges) }); } });