@@ -161,34 +161,35 @@ impl Range {
161 self.from() <= pos && pos < self.to()
161 self.from() <= pos && pos < self.to()
164− /// Map a range through a set of changes. Returns a new range representing the same position
164+ /// Map a range through a set of changes. Returns a new range representing
165− /// after the changes are applied.
165+ /// the same position after the changes are applied. Note that this
166+ /// function runs in O(N) (N is number of changes) and can therefore
167+ /// cause performance problems if run for a large number of ranges as the
168+ /// complexity is then O(MN) (for multicuror M=N usually). Instead use
169+ /// [Selection::map] or [ChangeSet::update_positions] instead
166− pub fn map(self, changes: &ChangeSet) -> Self {
170+ pub fn map(mut self, changes: &ChangeSet) -> Self {
167 use std::cmp::Ordering;
171 use std::cmp::Ordering;
168− let (anchor, head) = match self.anchor.cmp(&self.head) {
172+ if changes.is_empty() {
169− Ordering::Equal => (
173+ return self;
170− changes.map_pos(self.anchor, Assoc::After),
171− changes.map_pos(self.head, Assoc::After),
174− changes.map_pos(self.anchor, Assoc::After),
175− changes.map_pos(self.head, Assoc::Before),
177− Ordering::Greater => (
178− changes.map_pos(self.anchor, Assoc::Before),
179− changes.map_pos(self.head, Assoc::After),
183− // We want to return a new `Range` with `horiz == None` every time,
184− // even if the anchor and head haven't changed, because we don't
185− // know if the *visual* position hasn't changed due to
186− // character-width or grapheme changes earlier in the text.
190− old_visual_position: None,
176+ let positions_to_map = match self.anchor.cmp(&self.head) {
177+ Ordering::Equal => [
178+ (&mut self.anchor, Assoc::After),
179+ (&mut self.head, Assoc::After),
182+ (&mut self.anchor, Assoc::After),
183+ (&mut self.head, Assoc::Before),
185+ Ordering::Greater => [
186+ (&mut self.head, Assoc::After),
187+ (&mut self.anchor, Assoc::Before),
190+ changes.update_positions(positions_to_map.into_iter());
191+ self.old_visual_position = None;
194 /// Extend the range to cover at least `from` `to`.
195 /// Extend the range to cover at least `from` `to`.
@@ -450,18 +451,44 @@ impl Selection {
451 /// Map selections over a set of changes. Useful for adjusting the selection position after
452 /// Map selections over a set of changes. Useful for adjusting the selection position after
452 /// applying changes to a document.
453 /// applying changes to a document.
453− pub fn map(self, changes: &ChangeSet) -> Self {
454+ pub fn map(mut self, changes: &ChangeSet) -> Self {
454 if changes.is_empty() {
455 if changes.is_empty() {
455 return self;
456 return self;
458+ self = self.map_no_normalize(changes);
459+ // TODO: only normalize if needed (any ranges out of order)
460+ self = self.normalize();
461− .map(|range| range.map(changes))
465+ /// Map selections over a set of changes. Useful for adjusting the selection position after
462− .collect(),
466+ /// applying changes to a document. Doesn't normalize the selection
463− self.primary_index,
467+ pub fn map_no_normalize(mut self, changes: &ChangeSet) -> Self {
468+ if changes.is_empty() {
472+ let positions_to_map = self.ranges.iter_mut().flat_map(|range| {
473+ use std::cmp::Ordering;
474+ range.old_visual_position = None;
475+ match range.anchor.cmp(&range.head) {
476+ Ordering::Equal => [
477+ (&mut range.anchor, Assoc::After),
478+ (&mut range.head, Assoc::After),
481+ (&mut range.anchor, Assoc::After),
482+ (&mut range.head, Assoc::Before),
484+ Ordering::Greater => [
485+ (&mut range.head, Assoc::After),
486+ (&mut range.anchor, Assoc::Before),
490+ changes.update_positions(positions_to_map);
467 pub fn ranges(&self) -> &[Range] {
494 pub fn ranges(&self) -> &[Range] {