summaryrefslogtreecommitdiff
path: root/helix-term/src
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src')
-rw-r--r--helix-term/src/commands.rs24
1 files changed, 18 insertions, 6 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index c74dfb39..5498a437 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -4773,6 +4773,8 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
let mut ranges = SmallVec::with_capacity(selection.len());
let text = doc.text().slice(..);
+ let mut offset = 0isize;
+
for range in selection.ranges() {
let fragment = range.slice(text);
let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment.into())) {
@@ -4788,13 +4790,23 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
return;
}
- let (from, to) = match behavior {
- ShellBehavior::Replace => (range.from(), range.to()),
- ShellBehavior::Insert => (range.from(), range.from()),
- ShellBehavior::Append => (range.to(), range.to()),
- _ => (range.from(), range.from()),
+ let output_len = output.chars().count();
+
+ let (from, to, deleted_len) = match behavior {
+ ShellBehavior::Replace => (range.from(), range.to(), range.len()),
+ ShellBehavior::Insert => (range.from(), range.from(), 0),
+ ShellBehavior::Append => (range.to(), range.to(), 0),
+ _ => (range.from(), range.from(), 0),
};
- ranges.push(Range::new(to, to + output.chars().count()));
+
+ // These `usize`s cannot underflow because selection ranges cannot overlap.
+ // Once the MSRV is 1.66.0 (mixed_integer_ops is stabilized), we can use checked
+ // arithmetic to assert this.
+ let anchor = (to as isize + offset - deleted_len as isize) as usize;
+ let new_range = Range::new(anchor, anchor + output_len).with_direction(range.direction());
+ ranges.push(new_range);
+ offset = offset + output_len as isize - deleted_len as isize;
+
changes.push((from, to, Some(output)));
}