diff options
Diffstat (limited to 'helix-term/src')
-rw-r--r-- | helix-term/src/commands.rs | 120 | ||||
-rw-r--r-- | helix-term/src/keymap.rs | 2 |
2 files changed, 120 insertions, 2 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 8866b79b..b530e30b 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -255,7 +255,8 @@ impl Command { space_mode, view_mode, left_bracket_mode, - right_bracket_mode + right_bracket_mode, + surround ); } @@ -1906,6 +1907,7 @@ fn goto_mode(cx: &mut Context) { match (doc.mode, ch) { (_, 'g') => move_file_start(cx), (_, 'e') => move_file_end(cx), + (_, 'm') => match_brackets(cx), (_, 'a') => switch_to_last_accessed_file(cx), (Mode::Normal, 'h') => move_line_start(cx), (Mode::Normal, 'l') => move_line_end(cx), @@ -3311,6 +3313,122 @@ fn right_bracket_mode(cx: &mut Context) { }) } +fn surround(cx: &mut Context) { + let count = cx.count; + cx.on_next_key(move |cx, event| { + if let KeyEvent { + code: KeyCode::Char(ch), + .. + } = event + { + // FIXME: count gets reset because of cx.on_next_key() + cx.count = count; + match ch { + 'a' => surround_add(cx), + 'r' => surround_replace(cx), + 'd' => { + surround_delete(cx); + let (view, doc) = current!(cx.editor); + } + _ => (), + } + } + }) +} + +use helix_core::surround; + +fn surround_add(cx: &mut Context) { + cx.on_next_key(move |cx, event| { + if let KeyEvent { + code: KeyCode::Char(ch), + .. + } = event + { + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); + let selection = doc.selection(view.id); + let (open, close) = surround::get_pair(ch); + + let mut changes = Vec::new(); + for (i, range) in selection.iter().enumerate() { + let (from, to) = (range.from(), range.to() + 1); + changes.push((from, from, Some(Tendril::from_char(open)))); + changes.push((to, to, Some(Tendril::from_char(close)))); + } + + let transaction = Transaction::change(doc.text(), changes.into_iter()); + doc.apply(&transaction, view.id); + doc.append_changes_to_history(view.id); + } + }) +} + +fn surround_replace(cx: &mut Context) { + let count = cx.count(); + cx.on_next_key(move |cx, event| { + if let KeyEvent { + code: KeyCode::Char(from), + .. + } = event + { + cx.on_next_key(move |cx, event| { + if let KeyEvent { + code: KeyCode::Char(to), + .. + } = event + { + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); + let selection = doc.selection(view.id); + + let change_pos = match surround::get_surround_pos(text, selection, from, count) + { + Some(c) => c, + None => return, + }; + + let (open, close) = surround::get_pair(to); + let transaction = Transaction::change( + doc.text(), + change_pos.iter().enumerate().map(|(i, &pos)| { + let ch = if i % 2 == 0 { open } else { close }; + (pos, pos + 1, Some(Tendril::from_char(ch))) + }), + ); + doc.apply(&transaction, view.id); + doc.append_changes_to_history(view.id); + } + }); + } + }) +} + +fn surround_delete(cx: &mut Context) { + let count = cx.count(); + cx.on_next_key(move |cx, event| { + if let KeyEvent { + code: KeyCode::Char(ch), + .. + } = event + { + let (view, doc) = current!(cx.editor); + let text = doc.text().slice(..); + let selection = doc.selection(view.id); + + let change_pos = match surround::get_surround_pos(text, selection, ch, count) { + Some(c) => c, + None => return, + }; + + let transaction = + Transaction::change(doc.text(), change_pos.into_iter().map(|p| (p, p + 1, None))); + doc.apply(&transaction, view.id); + doc.append_changes_to_history(view.id); + } + }) +} + impl fmt::Display for Command { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let Command(name, _) = self; diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 46d495c3..cce3d31f 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -200,7 +200,7 @@ impl Default for Keymaps { // extend_to_whole_line, crop_to_whole_line - key!('m') => Command::match_brackets, + key!('m') => Command::surround, // TODO: refactor into // key!('m') => commands::select_to_matching, // key!('M') => commands::back_select_to_matching, |