Skip to content

Commit b59a3ff

Browse files
committed
account for overlapping deletes
1 parent c5a5779 commit b59a3ff

File tree

3 files changed

+161
-40
lines changed

3 files changed

+161
-40
lines changed

β€Žhelix-core/src/auto_pairs.rsβ€Ž

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ pub fn hook_insert(
136136

137137
#[must_use]
138138
pub fn hook_delete(doc: &Rope, range: &Range, pairs: &AutoPairs) -> Option<(Deletion, Range)> {
139+
log::trace!("autopairs delete hook range: {:#?}", range);
140+
139141
let text = doc.slice(..);
140142
let cursor = range.cursor(text);
141143

@@ -175,12 +177,27 @@ pub fn handle_delete(doc: &Rope, range: &Range) -> Option<(Deletion, Range)> {
175177
let size_delete = end_next - end_prev;
176178
let next_head = graphemes::next_grapheme_boundary(text, range.head) - size_delete;
177179

178-
let next_range = match range.direction() {
179-
Direction::Forward => Range::new(range.anchor, next_head),
180-
Direction::Backward => Range::new(range.anchor - size_delete, next_head),
180+
// if the range is a single grapheme cursor, we do not want to shrink the
181+
// range, just move it, so we only subtract the size of the closing pair char
182+
let next_anchor = match (range.direction(), range.is_single_grapheme(text)) {
183+
// single grapheme forward needs to move, but only the width of the
184+
// character under the cursor, which is the closer
185+
(Direction::Forward, true) => range.anchor - (end_next - cursor),
186+
(Direction::Backward, true) => range.anchor - (cursor - end_prev),
187+
188+
(Direction::Forward, false) => range.anchor,
189+
(Direction::Backward, false) => range.anchor - size_delete,
181190
};
182191

183-
log::trace!("auto pair delete: {:?}, range: {:?}", delete, range,);
192+
let next_range = Range::new(next_anchor, next_head);
193+
194+
log::trace!(
195+
"auto pair delete: {:?}, range: {:?}, next_range: {:?}, text len: {}",
196+
delete,
197+
range,
198+
next_range,
199+
text.len_chars()
200+
);
184201

185202
Some((delete, next_range))
186203
}

β€Žhelix-core/src/transaction.rsβ€Ž

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -813,10 +813,13 @@ impl Transaction {
813813
{
814814
let mut end_ranges = SmallVec::with_capacity(selection.len());
815815
let mut offset = 0;
816+
let mut last = 0;
816817

817818
let transaction = Transaction::delete_by_selection(doc, selection, |start_range| {
818819
let ((from, to), end_range) = f(start_range);
819-
let change_size = to - from;
820+
821+
// must account for possibly overlapping deletes
822+
let change_size = if last > from { to - last } else { to - from };
820823

821824
let new_range = if let Some(end_range) = end_range {
822825
end_range
@@ -830,10 +833,18 @@ impl Transaction {
830833
new_range.head.saturating_sub(offset),
831834
);
832835

836+
log::trace!(
837+
"delete from: {}, to: {}, offset: {}, new_range: {:?}, offset_range: {:?}",
838+
from,
839+
to,
840+
offset,
841+
new_range,
842+
offset_range
843+
);
844+
833845
end_ranges.push(offset_range);
834846
offset += change_size;
835-
836-
log::trace!("delete from: {}, to: {}, offset: {}", from, to, offset);
847+
last = to;
837848

838849
(from, to)
839850
});

β€Žhelix-term/tests/test/auto_pairs.rsβ€Ž

Lines changed: 126 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ async fn delete_basic() -> anyhow::Result<()> {
683683
test((
684684
format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END),
685685
"i<backspace>",
686-
format!("#[{}|]#", LINE_END),
686+
format!("#[|{}]#", LINE_END),
687687
))
688688
.await?;
689689
}
@@ -695,9 +695,21 @@ async fn delete_basic() -> anyhow::Result<()> {
695695
async fn delete_multi() -> anyhow::Result<()> {
696696
for pair in DEFAULT_PAIRS {
697697
test((
698-
format!("{}#[|{}]#{}", pair.0, pair.1, LINE_END),
698+
format!(
699+
indoc! {"\
700+
{open}#[|{close}]#
701+
{open}#(|{close})#
702+
{open}#(|{close})#
703+
"},
704+
open = pair.0,
705+
close = pair.1,
706+
),
699707
"i<backspace>",
700-
format!("#[{}|]#", LINE_END),
708+
indoc! {"\
709+
#[|\n]#
710+
#(|\n)#
711+
#(|\n)#
712+
"},
701713
))
702714
.await?;
703715
}
@@ -711,7 +723,21 @@ async fn delete_whitespace() -> anyhow::Result<()> {
711723
test((
712724
format!("{} #[| ]#{}", pair.0, pair.1),
713725
"i<backspace>",
714-
format!("{}#[{}|]#", pair.0, pair.1),
726+
format!("{}#[|{}]#", pair.0, pair.1),
727+
))
728+
.await?;
729+
}
730+
731+
Ok(())
732+
}
733+
734+
#[tokio::test(flavor = "multi_thread")]
735+
async fn delete_whitespace_after_word() -> anyhow::Result<()> {
736+
for pair in DEFAULT_PAIRS {
737+
test((
738+
format!("foo{} #[| ]#{}", pair.0, pair.1),
739+
"i<backspace>",
740+
format!("foo{}#[|{}]#", pair.0, pair.1),
715741
))
716742
.await?;
717743
}
@@ -736,7 +762,7 @@ async fn delete_whitespace_multi() -> anyhow::Result<()> {
736762
"i<backspace>",
737763
format!(
738764
indoc! {"\
739-
{open}#[{close}|]#
765+
{open}#[|{close}]#
740766
{open}#(|{open})#{close}{close}
741767
{open}{open}#(|{close}{close})#
742768
foo#(|\n)#
@@ -830,7 +856,7 @@ async fn delete_configured_multi_byte_chars() -> anyhow::Result<()> {
830856
(
831857
format!("{}#[|{}]#{}", open, close, LINE_END),
832858
"i<backspace>",
833-
format!("#[{}|]#", LINE_END),
859+
format!("#[|{}]#", LINE_END),
834860
),
835861
)
836862
.await?;
@@ -843,9 +869,95 @@ async fn delete_configured_multi_byte_chars() -> anyhow::Result<()> {
843869
async fn delete_after_word() -> anyhow::Result<()> {
844870
for pair in DEFAULT_PAIRS {
845871
test((
846-
format!("foo{}#[|{}]#{}", pair.0, pair.1, LINE_END),
872+
&format!("foo{}#[|{}]#", pair.0, pair.1),
847873
"i<backspace>",
848-
format!("foo#[{}|]#", LINE_END),
874+
"foo#[|\n]#",
875+
))
876+
.await?;
877+
}
878+
879+
Ok(())
880+
}
881+
882+
#[tokio::test(flavor = "multi_thread")]
883+
async fn insert_then_delete() -> anyhow::Result<()> {
884+
for pair in differing_pairs() {
885+
test((
886+
"#[\n|]#\n",
887+
format!("ofoo{}<backspace>", pair.0),
888+
"\nfoo#[\n|]#\n",
889+
))
890+
.await?;
891+
}
892+
893+
Ok(())
894+
}
895+
896+
#[tokio::test(flavor = "multi_thread")]
897+
async fn insert_then_delete_whitespace() -> anyhow::Result<()> {
898+
for pair in differing_pairs() {
899+
test((
900+
"foo#[\n|]#",
901+
format!("i{}<space><backspace><backspace>", pair.0),
902+
"foo#[|\n]#",
903+
))
904+
.await?;
905+
}
906+
907+
Ok(())
908+
}
909+
910+
#[tokio::test(flavor = "multi_thread")]
911+
async fn insert_then_delete_multi() -> anyhow::Result<()> {
912+
for pair in differing_pairs() {
913+
test((
914+
indoc! {"\
915+
through a day#[\n|]#
916+
in and out of weeks#(\n|)#
917+
over a year#(\n|)#
918+
"},
919+
format!("i{}<space><backspace><backspace>", pair.0),
920+
indoc! {"\
921+
through a day#[|\n]#
922+
in and out of weeks#(|\n)#
923+
over a year#(|\n)#
924+
"},
925+
))
926+
.await?;
927+
}
928+
929+
Ok(())
930+
}
931+
932+
#[tokio::test(flavor = "multi_thread")]
933+
async fn append_then_delete() -> anyhow::Result<()> {
934+
for pair in differing_pairs() {
935+
test((
936+
"fo#[o|]#",
937+
format!("a{}<space><backspace><backspace>", pair.0),
938+
"fo#[o\n|]#",
939+
))
940+
.await?;
941+
}
942+
943+
Ok(())
944+
}
945+
946+
#[tokio::test(flavor = "multi_thread")]
947+
async fn append_then_delete_multi() -> anyhow::Result<()> {
948+
for pair in differing_pairs() {
949+
test((
950+
indoc! {"\
951+
#[through a day|]#
952+
#(in and out of weeks|)#
953+
#(over a year|)#
954+
"},
955+
format!("a{}<space><backspace><backspace>", pair.0),
956+
indoc! {"\
957+
#[through a day\n|]#
958+
#(in and out of weeks\n|)#
959+
#(over a year\n|)#
960+
"},
849961
))
850962
.await?;
851963
}
@@ -876,7 +988,7 @@ async fn delete_before_word() -> anyhow::Result<()> {
876988
test((
877989
format!("{}#[|{}]#foo{}", pair.0, pair.1, LINE_END),
878990
"i<backspace>",
879-
format!("#[f|]#oo{}", LINE_END),
991+
format!("#[|f]#oo{}", LINE_END),
880992
))
881993
.await?;
882994
}
@@ -940,7 +1052,7 @@ async fn delete_before_eol() -> anyhow::Result<()> {
9401052
close = pair.1
9411053
),
9421054
"i<backspace>",
943-
format!("{0}#[{0}|]#", LINE_END),
1055+
format!("{0}#[|{0}]#", LINE_END),
9441056
))
9451057
.await?;
9461058
}
@@ -971,25 +1083,6 @@ async fn delete_auto_pairs_disabled() -> anyhow::Result<()> {
9711083
Ok(())
9721084
}
9731085

974-
#[tokio::test(flavor = "multi_thread")]
975-
async fn delete_multi_range() -> anyhow::Result<()> {
976-
for pair in DEFAULT_PAIRS {
977-
test((
978-
format!(
979-
"{open}#[|{close}]#{eol}{open}#(|{close})#{eol}{open}#(|{close})#{eol}",
980-
open = pair.0,
981-
close = pair.1,
982-
eol = LINE_END
983-
),
984-
"i<backspace>",
985-
format!("#[{eol}|]##({eol}|)##({eol}|)#", eol = LINE_END),
986-
))
987-
.await?;
988-
}
989-
990-
Ok(())
991-
}
992-
9931086
#[tokio::test(flavor = "multi_thread")]
9941087
async fn delete_before_multi_code_point_graphemes() -> anyhow::Result<()> {
9951088
for pair in DEFAULT_PAIRS {
@@ -1016,7 +1109,7 @@ async fn delete_before_multi_code_point_graphemes() -> anyhow::Result<()> {
10161109
pair.0, pair.1, LINE_END
10171110
),
10181111
"i<backspace>",
1019-
format!("hello #[πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦|]# goodbye{}", LINE_END),
1112+
format!("hello #[|πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦]# goodbye{}", LINE_END),
10201113
))
10211114
.await?;
10221115

@@ -1072,7 +1165,7 @@ async fn delete_nested_open_inside_pair() -> anyhow::Result<()> {
10721165
),
10731166
"i<backspace>",
10741167
format!(
1075-
"{open}#[{close}|]#{eol}",
1168+
"{open}#[|{close}]#{eol}",
10761169
open = pair.0,
10771170
close = pair.1,
10781171
eol = LINE_END
@@ -1103,7 +1196,7 @@ async fn delete_nested_open_inside_pair_multi() -> anyhow::Result<()> {
11031196
),
11041197
"i<backspace>",
11051198
format!(
1106-
"{outer_open}#[{outer_close}|]#{eol}{outer_open}#({outer_close}|)#{eol}{outer_open}#({outer_close}|)#{eol}",
1199+
"{outer_open}#[|{outer_close}]#{eol}{outer_open}#(|{outer_close})#{eol}{outer_open}#(|{outer_close})#{eol}",
11071200
outer_open = outer_pair.0,
11081201
outer_close = outer_pair.1,
11091202
eol = LINE_END
@@ -1187,7 +1280,7 @@ async fn delete_mixed_dedent() -> anyhow::Result<()> {
11871280
),
11881281
"i<backspace>",
11891282
indoc! {"\
1190-
bar = #[\n|]#
1283+
bar = #[|\n]#
11911284
#(|\n)#
11921285
fo#(|\n)#
11931286
"},

0 commit comments

Comments
Β (0)