Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-core/src/auto_pairs.rs')
-rw-r--r--helix-core/src/auto_pairs.rs150
1 files changed, 62 insertions, 88 deletions
diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs
index e319b76a..2fd373de 100644
--- a/helix-core/src/auto_pairs.rs
+++ b/helix-core/src/auto_pairs.rs
@@ -1,7 +1,7 @@
//! When typing the opening character of one of the possible pairs defined below,
//! this module provides the functionality to insert the paired closing character.
-use crate::{graphemes, movement::Direction, Range, Rope, Selection, Tendril, Transaction};
+use crate::{graphemes, movement::Direction, Change, Range, Rope, Tendril};
use std::collections::HashMap;
// Heavily based on https://github.com/codemirror/closebrackets/
@@ -104,31 +104,23 @@ impl Default for AutoPairs {
}
}
-// insert hook:
-// Fn(doc, selection, char) => Option<Transaction>
-// problem is, we want to do this per range, so we can call default handler for some ranges
-// so maybe ret Vec<Option<Change>>
-// but we also need to be able to return transactions...
-//
-// to simplify, maybe return Option<Transaction> and just reimplement the default
-
// [TODO]
// * delete implementation where it erases the whole bracket (|) -> |
// * change to multi character pairs to handle cases like placing the cursor in the
// middle of triple quotes, and more exotic pairs like Jinja's {% %}
#[must_use]
-pub fn hook(doc: &Rope, selection: &Selection, ch: char, pairs: &AutoPairs) -> Option<Transaction> {
- log::trace!("autopairs hook selection: {:#?}", selection);
+pub fn hook(doc: &Rope, range: &Range, ch: char, pairs: &AutoPairs) -> Option<(Change, Range)> {
+ log::trace!("autopairs hook range: {:#?}", range);
if let Some(pair) = pairs.get(ch) {
if pair.same() {
- return Some(handle_same(doc, selection, pair));
+ return handle_same(doc, range, pair);
} else if pair.open == ch {
- return Some(handle_open(doc, selection, pair));
+ return handle_open(doc, range, pair);
} else if pair.close == ch {
// && char_at pos == close
- return Some(handle_close(doc, selection, pair));
+ return handle_close(doc, range, pair);
}
}
@@ -251,94 +243,76 @@ fn get_next_range(doc: &Rope, start_range: &Range, len_inserted: usize) -> Range
Range::new(end_anchor, end_head)
}
-fn handle_open(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
- let transaction = Transaction::change_by_and_with_selection(doc, selection, |start_range| {
- let cursor = start_range.cursor(doc.slice(..));
- let next_char = doc.get_char(cursor);
- let len_inserted;
-
- // Since auto pairs are currently limited to single chars, we're either
- // inserting exactly one or two chars. When arbitrary length pairs are
- // added, these will need to be changed.
- let change = match next_char {
- Some(_) if !pair.should_close(doc, start_range) => {
- len_inserted = 1;
- let mut tendril = Tendril::new();
- tendril.push(pair.open);
- (cursor, cursor, Some(tendril))
- }
- _ => {
- // insert open & close
- let pair_str = Tendril::from_iter([pair.open, pair.close]);
- len_inserted = 2;
- (cursor, cursor, Some(pair_str))
- }
- };
+fn handle_open(doc: &Rope, range: &Range, pair: &Pair) -> Option<(Change, Range)> {
+ let cursor = range.cursor(doc.slice(..));
+ let next_char = doc.get_char(cursor);
+ let len_inserted;
+
+ // Since auto pairs are currently limited to single chars, we're either
+ // inserting exactly one or two chars. When arbitrary length pairs are
+ // added, these will need to be changed.
+ let change = match next_char {
+ Some(_) if !pair.should_close(doc, range) => {
+ return None;
+ }
+ _ => {
+ // insert open & close
+ let pair_str = Tendril::from_iter([pair.open, pair.close]);
+ len_inserted = 2;
+ (cursor, cursor, Some(pair_str))
+ }
+ };
- let next_range = get_next_range(doc, start_range, len_inserted);
+ let next_range = get_next_range(doc, range, len_inserted);
+ let result = (change, next_range);
- (change, Some(next_range))
- });
+ log::debug!("auto pair change: {:#?}", &result);
- log::debug!("auto pair transaction: {:#?}", transaction);
- transaction
+ Some(result)
}
-fn handle_close(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
- let transaction = Transaction::change_by_and_with_selection(doc, selection, |start_range| {
- let cursor = start_range.cursor(doc.slice(..));
- let next_char = doc.get_char(cursor);
- let mut len_inserted = 0;
+fn handle_close(doc: &Rope, range: &Range, pair: &Pair) -> Option<(Change, Range)> {
+ let cursor = range.cursor(doc.slice(..));
+ let next_char = doc.get_char(cursor);
- let change = if next_char == Some(pair.close) {
- // return transaction that moves past close
- (cursor, cursor, None) // no-op
- } else {
- len_inserted = 1;
- let mut tendril = Tendril::new();
- tendril.push(pair.close);
- (cursor, cursor, Some(tendril))
- };
+ let change = if next_char == Some(pair.close) {
+ // return transaction that moves past close
+ (cursor, cursor, None) // no-op
+ } else {
+ return None;
+ };
- let next_range = get_next_range(doc, start_range, len_inserted);
+ let next_range = get_next_range(doc, range, 0);
+ let result = (change, next_range);
- (change, Some(next_range))
- });
+ log::debug!("auto pair change: {:#?}", &result);
- log::debug!("auto pair transaction: {:#?}", transaction);
- transaction
+ Some(result)
}
/// handle cases where open and close is the same, or in triples ("""docstring""")
-fn handle_same(doc: &Rope, selection: &Selection, pair: &Pair) -> Transaction {
- let transaction = Transaction::change_by_and_with_selection(doc, selection, |start_range| {
- let cursor = start_range.cursor(doc.slice(..));
- let mut len_inserted = 0;
- let next_char = doc.get_char(cursor);
-
- let change = if next_char == Some(pair.open) {
- // return transaction that moves past close
- (cursor, cursor, None) // no-op
- } else {
- let mut pair_str = Tendril::new();
- pair_str.push(pair.open);
-
- // for equal pairs, don't insert both open and close if either
- // side has a non-pair char
- if pair.should_close(doc, start_range) {
- pair_str.push(pair.close);
- }
-
- len_inserted += pair_str.chars().count();
- (cursor, cursor, Some(pair_str))
- };
+fn handle_same(doc: &Rope, range: &Range, pair: &Pair) -> Option<(Change, Range)> {
+ let cursor = range.cursor(doc.slice(..));
+ let mut len_inserted = 0;
+ let next_char = doc.get_char(cursor);
+
+ let change = if next_char == Some(pair.open) {
+ // return transaction that moves past close
+ (cursor, cursor, None) // no-op
+ } else {
+ if !pair.should_close(doc, range) {
+ return None;
+ }
- let next_range = get_next_range(doc, start_range, len_inserted);
+ let pair_str = Tendril::from_iter([pair.open, pair.close]);
+ len_inserted = 2;
+ (cursor, cursor, Some(pair_str))
+ };
- (change, Some(next_range))
- });
+ let next_range = get_next_range(doc, range, len_inserted);
+ let result = (change, next_range);
- log::debug!("auto pair transaction: {:#?}", transaction);
+ log::debug!("auto pair change: {:#?}", &result);
- transaction
+ Some(result)
}