on master help sign in
Implement the f/t/F/T find/till family of commands.
4acf301Blaž Hrastnik
TODO.md+1−1
@@ -25,7 +25,7 @@
25- [ ] CI binary builds
25- [ ] CI binary builds
26
26
27- [ ] regex search / select next
27- [ ] regex search / select next
28−- [ ] f / t mappings
28+- [x] f / t mappings
29- [ ] open_above (O) command
29- [ ] open_above (O) command
30- [ ] = for auto indent line/selection
30- [ ] = for auto indent line/selection
31- [x] q should only close the view, if all are closed, close the editor
31- [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 @@
1use crate::RopeSlice;
1use crate::RopeSlice;
2
2
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> {
4 // start searching right after pos
10 // start searching right after pos
5 let mut chars = text.chars_at(pos + 1);
11 let mut chars = text.chars_at(pos + 1);
6
12
@@ -16,10 +22,20 @@ pub fn find_nth_next(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt
16 }
22 }
17 }
23 }
18
24
25+ if !inclusive {
26+ pos -= 1;
27+ }
28+
19 Some(pos)
29 Some(pos)
20}
30}
21
31
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> {
23 // start searching right before pos
39 // start searching right before pos
24 let mut chars = text.chars_at(pos.saturating_sub(1));
40 let mut chars = text.chars_at(pos.saturating_sub(1));
25
41
@@ -35,5 +51,9 @@ pub fn find_nth_prev(text: RopeSlice, ch: char, mut pos: usize, n: usize) -> Opt
35 }
51 }
36 }
52 }
37
53
54+ if !inclusive {
55+ pos -= 1;
56+ }
57+
38 Some(pos)
58 Some(pos)
39}
59}
helix-term/src/commands.rs+87−5
@@ -5,7 +5,7 @@ use helix_core::{
5 regex::{self, Regex},
5 regex::{self, Regex},
6 register, search, selection,
6 register, search, selection,
7 state::{coords_at_pos, pos_at_coords, Direction, Granularity, State},
7 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,
9};
9};
10
10
11use once_cell::sync::Lazy;
11use once_cell::sync::Lazy;
@@ -236,7 +236,13 @@ pub fn extend_next_word_end(cx: &mut Context) {
236 doc.set_selection(selection);
236 doc.set_selection(selection);
237}
237}
238
238
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+{
240 // TODO: count is reset to 1 before next key so we move it into the closure here.
246 // TODO: count is reset to 1 before next key so we move it into the closure here.
241 // Would be nice to carry over.
247 // Would be nice to carry over.
242 let count = cx.count;
248 let count = cx.count;
@@ -252,9 +258,13 @@ pub fn find_next_char(cx: &mut Context) {
252 let text = doc.text().slice(..);
258 let text = doc.text().slice(..);
253
259
254 let selection = doc.selection().transform(|mut range| {
260 let selection = doc.selection().transform(|mut range| {
255− if let Some(pos) = search::find_nth_next(text, ch, range.head, count) {
261+ if let Some(pos) = search::find_nth_next(text, ch, range.head, count, inclusive) {
256− Range::new(range.head, pos)
262+ if extend {
257− // or (range.anchor, pos) for extend
263+ Range::new(range.anchor, pos)
264+ } else {
265+ // select
266+ Range::new(range.head, pos)
267+ }
258 // or (pos, pos) to move to found val
268 // or (pos, pos) to move to found val
259 } else {
269 } else {
260 range
270 range
@@ -266,6 +276,78 @@ pub fn find_next_char(cx: &mut Context) {
266 })
276 })
267}
277}
268
278
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+
269fn scroll(view: &mut View, offset: usize, direction: Direction) {
351fn scroll(view: &mut View, offset: usize, direction: Direction) {
270 use Direction::*;
352 use Direction::*;
271 let text = view.doc.text().slice(..);
353 let text = view.doc.text().slice(..);
helix-term/src/keymap.rs+8−3
@@ -137,10 +137,10 @@ pub fn default() -> Keymaps {
137 key!('k') => commands::move_line_up,
137 key!('k') => commands::move_line_up,
138 key!('l') => commands::move_char_right,
138 key!('l') => commands::move_char_right,
139
139
140− // key!('t') => commands::till_next_char,
140+ key!('t') => commands::find_till_char,
141 key!('f') => commands::find_next_char,
141 key!('f') => commands::find_next_char,
142− // key!('T') => commands::till_prev_char,
142+ shift!('T') => commands::till_prev_char,
143− // key!('f') => commands::find_prev_char,
143+ shift!('F') => commands::find_prev_char,
144 // and matching set for select mode (extend)
144 // and matching set for select mode (extend)
145
145
146 key!('0') => commands::move_line_start,
146 key!('0') => commands::move_line_start,
@@ -261,6 +261,11 @@ pub fn default() -> Keymaps {
261 key!('b') => commands::extend_prev_word_start,
261 key!('b') => commands::extend_prev_word_start,
262 key!('e') => commands::extend_next_word_end,
262 key!('e') => commands::extend_next_word_end,
263
263
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+
264 Key {
269 Key {
265 code: KeyCode::Esc,
270 code: KeyCode::Esc,
266 modifiers: Modifiers::NONE
271 modifiers: Modifiers::NONE