aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-05-06 13:59:59 +0000
committerBlaž Hrastnik2021-05-06 14:02:32 +0000
commitf8844c68116cbbb1f24c49a5a7da95da7963616e (patch)
treeb4b38f168349dfa6a59cd45cbdbbe00f039aa32d
parentfd4fd12fa3dd565b56edb395bd625b0d2ec8ad46 (diff)
Implement pair expansion when pressing new line between bracket pairs.
From: {|} To: { | }
-rw-r--r--helix-core/src/auto_pairs.rs2
-rw-r--r--helix-term/src/commands.rs51
2 files changed, 44 insertions, 9 deletions
diff --git a/helix-core/src/auto_pairs.rs b/helix-core/src/auto_pairs.rs
index bbd1cea4..ffd16daf 100644
--- a/helix-core/src/auto_pairs.rs
+++ b/helix-core/src/auto_pairs.rs
@@ -3,7 +3,7 @@ use smallvec::SmallVec;
// Heavily based on https://github.com/codemirror/closebrackets/
-const PAIRS: &[(char, char)] = &[
+pub const PAIRS: &[(char, char)] = &[
('(', ')'),
('{', '}'),
('[', ']'),
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index aebdb465..a273fc6f 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -1471,17 +1471,52 @@ pub mod insert {
pub fn insert_newline(cx: &mut Context) {
let (view, doc) = cx.current();
let text = doc.text().slice(..);
- let transaction =
- Transaction::change_by_selection(doc.text(), doc.selection(view.id), |range| {
- let pos = range.head;
- // TODO: offset range.head by 1? when calculating?
- let indent_level = indent::suggested_indent_for_pos(doc.syntax(), text, pos, true);
- let indent = doc.indent_unit().repeat(indent_level);
- let mut text = String::with_capacity(1 + indent.len());
+
+ let contents = doc.text();
+ let selection = doc.selection(view.id);
+ let mut ranges = SmallVec::with_capacity(selection.len());
+
+ let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
+ let pos = range.head;
+
+ let prev = if pos == 0 {
+ ' '
+ } else {
+ contents.char(pos - 1)
+ };
+ let curr = contents.char(pos);
+
+ // TODO: offset range.head by 1? when calculating?
+ let indent_level =
+ indent::suggested_indent_for_pos(doc.syntax(), text, pos.saturating_sub(1), true);
+ let indent = doc.indent_unit().repeat(indent_level);
+ let mut text = String::with_capacity(1 + indent.len());
+ text.push('\n');
+ text.push_str(&indent);
+
+ let head = pos + text.len();
+
+ ranges.push(Range::new(
+ if range.is_empty() { head } else { range.anchor },
+ head,
+ ));
+
+ // if between a bracket pair
+ if helix_core::auto_pairs::PAIRS.contains(&(prev, curr)) {
+ // another newline, indent the end bracket one level less
+ let indent = doc.indent_unit().repeat(indent_level.saturating_sub(1));
text.push('\n');
text.push_str(&indent);
+
(pos, pos, Some(text.into()))
- });
+ } else {
+ (pos, pos, Some(text.into()))
+ }
+ });
+
+ transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
+ //
+
doc.apply(&transaction, view.id);
}