aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-03-19 15:16:34 +0000
committerBlaž Hrastnik2021-03-22 04:53:43 +0000
commitdf306fe031e6ddb188cda9d33da019b65af8cd99 (patch)
tree7d30efe2b026e3259cf9dba7cfd29d6de9e46da8
parent42d07b0621f034049ba3872122144ea9e69092eb (diff)
Implement open_above (O).
-rw-r--r--TODO.md2
-rw-r--r--helix-term/src/commands.rs57
-rw-r--r--helix-term/src/keymap.rs2
3 files changed, 52 insertions, 9 deletions
diff --git a/TODO.md b/TODO.md
index 0411c12b..dbca1424 100644
--- a/TODO.md
+++ b/TODO.md
@@ -16,7 +16,7 @@
- [ ] CI binary builds
- [ ] regex search / select next
-- [ ] open_above (O) command
+- [x] open_above (O) command
- [ ] = for auto indent line/selection
- [x] q should only close the view, if all are closed, close the editor
- [ ] buffers should sit on editor.buffers, view simply refs them
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index fc98f712..b9ee933d 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -869,13 +869,6 @@ pub fn open_below(cx: &mut Context) {
text.push_str(&indent);
let text = text.repeat(count);
- // TODO: ideally we want to run a hook over the transactions to figure out and reindent all
- // \n's as a post-processing step?
- // behaviors:
- // - on insert mode enter: we add newline + indent and position cursor at the end
- // - on 3o/3O: we insert 3 newlines + indents each and position cursors at ends
-
- // generate changes
(index, index, Some(text.into()))
})
.collect();
@@ -902,6 +895,56 @@ pub fn open_below(cx: &mut Context) {
}
// O inserts a new line before each line with a selection
+pub fn open_above(cx: &mut Context) {
+ let count = cx.count;
+ let mut doc = cx.doc();
+ enter_insert_mode(&mut doc);
+
+ let lines = selection_lines(doc.text(), doc.selection());
+
+ let positions = lines.into_iter().map(|index| {
+ // adjust all positions to the end of the previous line
+ doc.text().line_to_char(index).saturating_sub(1)
+ });
+
+ let text = doc.text().slice(..);
+
+ let changes: Vec<Change> = positions
+ .map(|index| {
+ // TODO: share logic with insert_newline for indentation
+ let indent_level =
+ helix_core::indent::suggested_indent_for_pos(doc.syntax(), text, index, 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 text = text.repeat(count);
+
+ // generate changes
+ (index, index, Some(text.into()))
+ })
+ .collect();
+
+ // TODO: count actually inserts "n" new lines and starts editing on all of them.
+ // TODO: append "count" newlines and modify cursors to those lines
+
+ let selection = Selection::new(
+ changes
+ .iter()
+ .map(|(start, _end, text): &Change| {
+ let len = text.as_ref().map(|text| text.len()).unwrap(); // minus newline
+ let pos = start + len;
+ Range::new(pos, pos)
+ })
+ .collect(),
+ 0,
+ );
+
+ let transaction =
+ Transaction::change(doc.text(), changes.into_iter()).with_selection(selection);
+
+ doc.apply(&transaction);
+}
pub fn normal_mode(cx: &mut Context) {
let mut doc = cx.doc();
diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs
index 5a39b774..1f34aa9e 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-term/src/keymap.rs
@@ -160,7 +160,7 @@ pub fn default() -> Keymaps {
key!('a') => commands::append_mode,
shift!('A') => commands::append_to_line,
key!('o') => commands::open_below,
- // key!('O') => commands::open_above,
+ shift!('O') => commands::open_above,
// [<space> ]<space> equivalents too (add blank new line, no edit)