@@ -1,5 +1,5 @@
11use crate::graphemes;
2−use crate::selection::Range;
2+use crate::selection::{Range, Selection};
33use crate::state::{Direction, Granularity, Mode, State};
44use crate::transaction::{ChangeSet, Transaction};
55use crate::Tendril;
@@ -62,8 +62,55 @@ pub fn append_mode(state: &mut State, _count: usize) {
6262
6363// I inserts at the start of each line with a selection
6464// A inserts at the end of each line with a selection
65−// o inserts a new line before each line with a selection
66−// O inserts a new line after each line with a selection
65+
66+// o inserts a new line after each line with a selection
67+pub fn open_below(state: &mut State, _count: usize) {
68+ state.mode = Mode::Insert;
69+
70+ // calculate line numbers for each selection range
71+ let mut lines = state
72+ .selection
73+ .ranges()
74+ .iter()
75+ .map(|range| state.doc.char_to_line(range.head))
76+ .collect::<Vec<_>>();
77+
78+ lines.sort();
79+ lines.dedup();
80+
81+ let positions: Vec<_> = lines
82+ .into_iter()
83+ .map(|index| {
84+ // adjust all positions to the end of the line.
85+ let line = state.doc.line(index);
86+ let line_start = state.doc.line_to_char(index);
87+ line_start + line.len_chars()
88+ })
89+ .collect();
90+
91+ let changes = positions.iter().copied().map(|index|
92+ // generate changes
93+ (index, index, Some(Tendril::from_char('\n'))));
94+
95+ // TODO: count actually inserts "n" new lines and starts editing on all of them.
96+ // TODO: append "count" newlines and modify cursors to those lines
97+
98+ let selection = Selection::new(
99+ positions
100+ .iter()
101+ .copied()
102+ .map(|pos| Range::new(pos, pos))
103+ .collect(),
104+ 0,
105+ );
106+
107+ let transaction = Transaction::change(state, changes.collect()).with_selection(selection);
108+
109+ transaction.apply(state);
110+ // TODO: need to store into history if successful
111+}
112+
113+// O inserts a new line before each line with a selection
67114
68115pub fn normal_mode(state: &mut State, _count: usize) {
69116 // TODO: if leaving append mode, move cursor back by 1