aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-03-11 07:14:52 +0000
committerBlaž Hrastnik2021-03-11 07:15:27 +0000
commit4acf30102282584e31d8ac9a7a69e45acbdd64ec (patch)
tree397163644e7adca237cf3309b942895ebc5fa4cb
parent62c991230f511b2dc11f8d1701260511800429d4 (diff)
Implement the f/t/F/T find/till family of commands.
-rw-r--r--TODO.md2
-rw-r--r--helix-core/src/search.rs24
-rw-r--r--helix-term/src/commands.rs92
-rw-r--r--helix-term/src/keymap.rs11
4 files changed, 118 insertions, 11 deletions
diff --git a/TODO.md b/TODO.md
index 72ceaadc..f65a3536 100644
--- a/TODO.md
+++ b/TODO.md
@@ -25,7 +25,7 @@
- [ ] CI binary builds
- [ ] regex search / select next
-- [ ] f / t mappings
+- [x] f / t mappings
- [ ] open_above (O) command
- [ ] = for auto indent line/selection
- [x] q should only close the view, if all are closed, close the editor
diff --git a/helix-core/src/search.rs b/helix-core/src/search.rs
index c03f60df..af754ab7 100644
--- a/helix-core/src/search.rs
+++ b/helix-core/src/search.rs
@@ -1,6 +1,12 @@
use crate::RopeSlice;
-pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Option<usize> {
+pub fn find_nth_next(
+ text: RopeSlice,
+ ch: char,
+ mut pos: usize,
+ n: usize,
+ inclusive: bool,
+) -> Option<usize> {
// start searching right after pos
let mut chars = text.chars_at(pos + 1);
@@ -16,10 +22,20 @@ pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt
}
}
+ if !inclusive {
+ pos -= 1;
+ }
+
Some(pos)
}
-pub fn find_nth_prev(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Option<usize> {
+pub fn find_nth_prev(
+ text: RopeSlice,
+ ch: char,
+ mut pos: usize,
+ n: usize,
+ inclusive: bool,
+) -> Option<usize> {
// start searching right before pos
let mut chars = text.chars_at(pos.saturating_sub(1));
@@ -35,5 +51,9 @@ pub fn find_nth_prev(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt
}
}
+ if !inclusive {
+ pos -= 1;
+ }
+
Some(pos)
}
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index f60f646e..edc38a48 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -5,7 +5,7 @@ use helix_core::{
regex::{self, Regex},
register, search, selection,
state::{coords_at_pos, pos_at_coords, Direction, Granularity, State},
- Change, ChangeSet, Position, Range, Selection, Tendril, Transaction,
+ Change, ChangeSet, Position, Range, RopeSlice, Selection, Tendril, Transaction,
};
use once_cell::sync::Lazy;
@@ -236,7 +236,13 @@ pub fn extend_next_word_end(cx: &mut Context) {
doc.set_selection(selection);
}
-pub fn find_next_char(cx: &mut Context) {
+#[inline]
+fn _find_char<F>(cx: &mut Context, search_fn: F, inclusive: bool, extend: bool)
+where
+ // TODO: make an options struct for and abstract this Fn into a searcher type
+ // use the definition for w/b/e too
+ F: Fn(RopeSlice, char, usize, usize, bool) -> Option<usize>,
+{
// TODO: count is reset to 1 before next key so we move it into the closure here.
// Would be nice to carry over.
let count = cx.count;
@@ -252,9 +258,13 @@ pub fn find_next_char(cx: &mut Context) {
let text = doc.text().slice(..);
let selection = doc.selection().transform(|mut range| {
- if let Some(pos) = search::find_nth_next(text, ch, range.head, count) {
- Range::new(range.head, pos)
- // or (range.anchor, pos) for extend
+ if let Some(pos) = search::find_nth_next(text, ch, range.head, count, inclusive) {
+ if extend {
+ Range::new(range.anchor, pos)
+ } else {
+ // select
+ Range::new(range.head, pos)
+ }
// or (pos, pos) to move to found val
} else {
range
@@ -266,6 +276,78 @@ pub fn find_next_char(cx: &mut Context) {
})
}
+pub fn find_till_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_next,
+ false, /* inclusive */
+ false, /* extend */
+ )
+}
+
+pub fn find_next_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_next,
+ true, /* inclusive */
+ false, /* extend */
+ )
+}
+
+pub fn extend_till_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_next,
+ false, /* inclusive */
+ true, /* extend */
+ )
+}
+
+pub fn extend_next_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_next,
+ true, /* inclusive */
+ true, /* extend */
+ )
+}
+
+pub fn till_prev_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_prev,
+ false, /* inclusive */
+ false, /* extend */
+ )
+}
+
+pub fn find_prev_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_prev,
+ true, /* inclusive */
+ false, /* extend */
+ )
+}
+
+pub fn extend_till_prev_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_prev,
+ false, /* inclusive */
+ true, /* extend */
+ )
+}
+
+pub fn extend_prev_char(cx: &mut Context) {
+ _find_char(
+ cx,
+ search::find_nth_prev,
+ true, /* inclusive */
+ true, /* extend */
+ )
+}
+
fn scroll(view: &mut View, offset: usize, direction: Direction) {
use Direction::*;
let text = view.doc.text().slice(..);
diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs
index d956679a..58a465fe 100644
--- a/helix-term/src/keymap.rs
+++ b/helix-term/src/keymap.rs
@@ -137,10 +137,10 @@ pub fn default() -> Keymaps {
key!('k') => commands::move_line_up,
key!('l') => commands::move_char_right,
- // key!('t') => commands::till_next_char,
+ key!('t') => commands::find_till_char,
key!('f') => commands::find_next_char,
- // key!('T') => commands::till_prev_char,
- // key!('f') => commands::find_prev_char,
+ shift!('T') => commands::till_prev_char,
+ shift!('F') => commands::find_prev_char,
// and matching set for select mode (extend)
key!('0') => commands::move_line_start,
@@ -261,6 +261,11 @@ pub fn default() -> Keymaps {
key!('b') => commands::extend_prev_word_start,
key!('e') => commands::extend_next_word_end,
+ key!('t') => commands::extend_till_char,
+ key!('f') => commands::extend_next_char,
+ shift!('T') => commands::extend_till_prev_char,
+ shift!('F') => commands::extend_prev_char,
+
Key {
code: KeyCode::Esc,
modifiers: Modifiers::NONE