on master help sign in
Implement the f/t/F/T find/till family of commands.
commit4acf30102282584e31d8ac9a7a69e45acbdd64ec authorBlaž Hrastnik <blaz@mxxn.io> dateThu 11 Mar 2021, 16:14 (6 years ago) parent62c9912
4 files changed+118−11
TODO.md+1−1 helix-core/src/search.rs+22−2 helix-term/src/commands.rs+87−5 helix-term/src/keymap.rs+8−3
TODO.md+1−1
@@ -25,7 +25,7 @@
2525- [ ] CI binary builds
2626
2727- [ ] regex search / select next
28−- [ ] f / t mappings
28+- [x] f / t mappings
2929- [ ] open_above (O) command
3030- [ ] = for auto indent line/selection
3131- [x] q should only close the view, if all are closed, close the editor
helix-core/src/search.rs+22−2
@@ -1,6 +1,12 @@
11use crate::RopeSlice;
22
3−pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Option<usize> {
3+pub fn find_nth_next(
4+ text: RopeSlice,
5+ ch: char,
6+ mut pos: usize,
7+ n: usize,
8+ inclusive: bool,
9+) -> Option<usize> {
410 // start searching right after pos
511 let mut chars = text.chars_at(pos + 1);
612
@@ -16,10 +22,20 @@ pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt
1622 }
1723 }
1824
25+ if !inclusive {
26+ pos -= 1;
27+ }
28+
1929 Some(pos)
2030}
2131
22−pub fn find_nth_prev(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Option<usize> {
32+pub fn find_nth_prev(
33+ text: RopeSlice,
34+ ch: char,
35+ mut pos: usize,
36+ n: usize,
37+ inclusive: bool,
38+) -> Option<usize> {
2339 // start searching right before pos
2440 let mut chars = text.chars_at(pos.saturating_sub(1));
2541
@@ -35,5 +51,9 @@ pub fn find_nth_prev(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt
3551 }
3652 }
3753
54+ if !inclusive {
55+ pos -= 1;
56+ }
57+
3858 Some(pos)
3959}
helix-term/src/commands.rs+87−5
@@ -5,7 +5,7 @@ use helix_core::{
55 regex::{self, Regex},
66 register, search, selection,
77 state::{coords_at_pos, pos_at_coords, Direction, Granularity, State},
8− Change, ChangeSet, Position, Range, Selection, Tendril, Transaction,
8+ Change, ChangeSet, Position, Range, RopeSlice, Selection, Tendril, Transaction,
99};
1010
1111use once_cell::sync::Lazy;
@@ -236,7 +236,13 @@ pub fn extend_next_word_end(cx: &mut Context) {
236236 doc.set_selection(selection);
237237}
238238
239−pub fn find_next_char(cx: &mut Context) {
239+#[inline]
240+fn _find_char<F>(cx: &mut Context, search_fn: F, inclusive: bool, extend: bool)
241+where
242+ // TODO: make an options struct for and abstract this Fn into a searcher type
243+ // use the definition for w/b/e too
244+ F: Fn(RopeSlice, char, usize, usize, bool) -> Option<usize>,
245+{
240246 // TODO: count is reset to 1 before next key so we move it into the closure here.
241247 // Would be nice to carry over.
242248 let count = cx.count;
@@ -252,9 +258,13 @@ pub fn find_next_char(cx: &mut Context) {
252258 let text = doc.text().slice(..);
253259
254260 let selection = doc.selection().transform(|mut range| {
255− if let Some(pos) = search::find_nth_next(text, ch, range.head, count) {
256− Range::new(range.head, pos)
257− // or (range.anchor, pos) for extend
261+ if let Some(pos) = search::find_nth_next(text, ch, range.head, count, inclusive) {
262+ if extend {
263+ Range::new(range.anchor, pos)
264+ } else {
265+ // select
266+ Range::new(range.head, pos)
267+ }
258268 // or (pos, pos) to move to found val
259269 } else {
260270 range
@@ -266,6 +276,78 @@ pub fn find_next_char(cx: &mut Context) {
266276 })
267277}
268278
279+pub fn find_till_char(cx: &mut Context) {
280+ _find_char(
281+ cx,
282+ search::find_nth_next,
283+ false, /* inclusive */
284+ false, /* extend */
285+ )
286+}
287+
288+pub fn find_next_char(cx: &mut Context) {
289+ _find_char(
290+ cx,
291+ search::find_nth_next,
292+ true, /* inclusive */
293+ false, /* extend */
294+ )
295+}
296+
297+pub fn extend_till_char(cx: &mut Context) {
298+ _find_char(
299+ cx,
300+ search::find_nth_next,
301+ false, /* inclusive */
302+ true, /* extend */
303+ )
304+}
305+
306+pub fn extend_next_char(cx: &mut Context) {
307+ _find_char(
308+ cx,
309+ search::find_nth_next,
310+ true, /* inclusive */
311+ true, /* extend */
312+ )
313+}
314+
315+pub fn till_prev_char(cx: &mut Context) {
316+ _find_char(
317+ cx,
318+ search::find_nth_prev,
319+ false, /* inclusive */
320+ false, /* extend */
321+ )
322+}
323+
324+pub fn find_prev_char(cx: &mut Context) {
325+ _find_char(
326+ cx,
327+ search::find_nth_prev,
328+ true, /* inclusive */
329+ false, /* extend */
330+ )
331+}
332+
333+pub fn extend_till_prev_char(cx: &mut Context) {
334+ _find_char(
335+ cx,
336+ search::find_nth_prev,
337+ false, /* inclusive */
338+ true, /* extend */
339+ )
340+}
341+
342+pub fn extend_prev_char(cx: &mut Context) {
343+ _find_char(
344+ cx,
345+ search::find_nth_prev,
346+ true, /* inclusive */
347+ true, /* extend */
348+ )
349+}
350+
269351fn scroll(view: &mut View, offset: usize, direction: Direction) {
270352 use Direction::*;
271353 let text = view.doc.text().slice(..);
helix-term/src/keymap.rs+8−3
@@ -137,10 +137,10 @@ pub fn default() -> Keymaps {
137137 key!('k') => commands::move_line_up,
138138 key!('l') => commands::move_char_right,
139139
140− // key!('t') => commands::till_next_char,
140+ key!('t') => commands::find_till_char,
141141 key!('f') => commands::find_next_char,
142− // key!('T') => commands::till_prev_char,
143− // key!('f') => commands::find_prev_char,
142+ shift!('T') => commands::till_prev_char,
143+ shift!('F') => commands::find_prev_char,
144144 // and matching set for select mode (extend)
145145
146146 key!('0') => commands::move_line_start,
@@ -261,6 +261,11 @@ pub fn default() -> Keymaps {
261261 key!('b') => commands::extend_prev_word_start,
262262 key!('e') => commands::extend_next_word_end,
263263
264+ key!('t') => commands::extend_till_char,
265+ key!('f') => commands::extend_next_char,
266+ shift!('T') => commands::extend_till_prev_char,
267+ shift!('F') => commands::extend_prev_char,
268+
264269 Key {
265270 code: KeyCode::Esc,
266271 modifiers: Modifiers::NONE