aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--helix-core/src/selection.rs14
-rw-r--r--helix-term/src/commands.rs40
2 files changed, 37 insertions, 17 deletions
diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs
index 6ca52ebf..e40fceb1 100644
--- a/helix-core/src/selection.rs
+++ b/helix-core/src/selection.rs
@@ -447,6 +447,20 @@ impl Selection {
self.transform(|r| r.min_width_1(text))
}
+ /// Transforms the selection into all of the left-side head positions,
+ /// using 1-width semantics.
+ pub fn cursors(self, text: RopeSlice) -> Self {
+ self.transform(|range| {
+ // For 1-width cursor semantics.
+ let pos = if range.anchor < range.head {
+ prev_grapheme_boundary(text, range.head).max(range.anchor)
+ } else {
+ range.head
+ };
+ Range::new(pos, pos)
+ })
+ }
+
pub fn fragments<'a>(&'a self, text: RopeSlice<'a>) -> impl Iterator<Item = Cow<str>> + 'a {
self.ranges.iter().map(move |range| range.fragment(text))
}
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index c6f592d9..5ac83d7b 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -1272,19 +1272,13 @@ fn append_mode(cx: &mut Context) {
doc.restore_cursor = true;
let text = doc.text().slice(..);
- // TODO: preserve selections, like in `Insert` mode. Probably we'll want
- // an explicit separate `Append` mode or something similar, so that we
- // don't change the selection at all, and instead just display and edit
- // things differently.
- let selection = doc
- .selection(view.id)
- .clone()
- .min_width_1(text)
- .transform(|range| Range::new(range.to(), range.to()));
+ let selection = doc.selection(view.id).clone().min_width_1(text);
+ // Make sure there's room at the end of the document if the last
+ // selection butts up against it.
let end = text.len_chars();
-
- if selection.iter().any(|range| range.head == end) {
+ let last_range = selection.iter().last().unwrap();
+ if !last_range.is_empty() && last_range.head == end {
let transaction = Transaction::change(
doc.text(),
std::array::IntoIter::new([(end, end, Some(doc.line_ending.as_str().into()))]),
@@ -1292,7 +1286,15 @@ fn append_mode(cx: &mut Context) {
doc.apply(&transaction, view.id);
}
- doc.set_selection(view.id, selection);
+ doc.set_selection(
+ view.id,
+ selection.clone().transform(|range| {
+ Range::new(
+ range.from(),
+ graphemes::next_grapheme_boundary(doc.text().slice(..), range.to()),
+ )
+ }),
+ );
}
mod cmd {
@@ -2829,11 +2831,11 @@ pub mod insert {
let (view, doc) = current!(cx.editor);
let text = doc.text();
- let selection = doc.selection(view.id);
+ let selection = doc.selection(view.id).clone().cursors(text.slice(..));
// run through insert hooks, stopping on the first one that returns Some(t)
for hook in HOOKS {
- if let Some(transaction) = hook(text, selection, c) {
+ if let Some(transaction) = hook(text, &selection, c) {
doc.apply(&transaction, view.id);
break;
}
@@ -2853,7 +2855,11 @@ pub mod insert {
// indent by one to reach 4 spaces).
let indent = Tendril::from(doc.indent_unit());
- let transaction = Transaction::insert(doc.text(), doc.selection(view.id), indent);
+ let transaction = Transaction::insert(
+ doc.text(),
+ &doc.selection(view.id).clone().cursors(doc.text().slice(..)),
+ indent,
+ );
doc.apply(&transaction, view.id);
}
@@ -2862,13 +2868,13 @@ pub mod insert {
let text = doc.text().slice(..);
let contents = doc.text();
- let selection = doc.selection(view.id);
+ let selection = doc.selection(view.id).clone().cursors(text);
let mut ranges = SmallVec::with_capacity(selection.len());
// TODO: this is annoying, but we need to do it to properly calculate pos after edits
let mut offs = 0;
- let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
+ let mut transaction = Transaction::change_by_selection(contents, &selection, |range| {
let pos = range.head;
let prev = if pos == 0 {