Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/transaction.rs')
-rw-r--r--helix-core/src/transaction.rs24
1 files changed, 20 insertions, 4 deletions
diff --git a/helix-core/src/transaction.rs b/helix-core/src/transaction.rs
index f24f2094..c5c94b75 100644
--- a/helix-core/src/transaction.rs
+++ b/helix-core/src/transaction.rs
@@ -29,6 +29,12 @@ pub enum Assoc {
/// Acts like `Before` if a word character is inserted
/// before the position, otherwise acts like `After`
BeforeWord,
+ /// Acts like `Before` but if the position is within an exact replacement
+ /// (exact size) the offset to the start of the replacement is kept
+ BeforeSticky,
+ /// Acts like `After` but if the position is within an exact replacement
+ /// (exact size) the offset to the start of the replacement is kept
+ AfterSticky,
}
impl Assoc {
@@ -40,13 +46,17 @@ impl Assoc {
fn insert_offset(self, s: &str) -> usize {
let chars = s.chars().count();
match self {
- Assoc::After => chars,
+ Assoc::After | Assoc::AfterSticky => chars,
Assoc::AfterWord => s.chars().take_while(|&c| char_is_word(c)).count(),
// return position before inserted text
- Assoc::Before => 0,
+ Assoc::Before | Assoc::BeforeSticky => 0,
Assoc::BeforeWord => chars - s.chars().rev().take_while(|&c| char_is_word(c)).count(),
}
}
+
+ pub fn sticky(self) -> bool {
+ matches!(self, Assoc::BeforeSticky | Assoc::AfterSticky)
+ }
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
@@ -456,8 +466,14 @@ impl ChangeSet {
if pos == old_pos && assoc.stay_at_gaps() {
new_pos
} else {
- // place to end of insert
- new_pos + assoc.insert_offset(s)
+ let ins = assoc.insert_offset(s);
+ // if the deleted and inserted text have the exact same size
+ // keep the relative offset into the new text
+ if *len == ins && assoc.sticky() {
+ new_pos + (pos - old_pos)
+ } else {
+ new_pos + assoc.insert_offset(s)
+ }
}
}),
i