|
| 1 | +" Given three positions, return the position closest to the first one. |
| 2 | +function! s:closest_position(main, a, b) |
| 3 | + let a_distance = mapnew(a:main, {k,v->abs(v-a:a[k])}) |
| 4 | + let b_distance = mapnew(a:main, {k,v->abs(v-a:b[k])}) |
| 5 | + if a_distance[1] < b_distance[1] |
| 6 | + return a:a |
| 7 | + endif |
| 8 | + if a_distance[1] > b_distance[1] |
| 9 | + return a:b |
| 10 | + endif |
| 11 | + if a_distance[2] < b_distance[2] |
| 12 | + return a:a |
| 13 | + endif |
| 14 | + if a_distance[2] > b_distance[2] |
| 15 | + return a:b |
| 16 | + endif |
| 17 | + " Distances are the same, return either one |
| 18 | + return a:a |
| 19 | +endfunction! |
| 20 | + |
1 | 21 | function! s:select(object_type, right_boundary)
|
2 | 22 | let left_boundaries = ['_\+\k', '\<', '\l\u', '\u\u\ze\l', '\a\d', '\d\a']
|
3 |
| - call search(join(left_boundaries, '\|'), 'bce') |
4 |
| - let start_position = getpos('.') |
5 | 23 |
|
| 24 | + " Gather all possible matches |
| 25 | + let cursor_position = getpos('.') |
| 26 | + let all_positions = [] |
| 27 | + for boundary in left_boundaries |
| 28 | + " search() moves the cursor, so we need to reset the cursor's position |
| 29 | + " before each search |
| 30 | + call setpos('.', cursor_position) |
| 31 | + if search(boundary, 'bce') > 0 |
| 32 | + call add(all_positions, getpos('.')) |
| 33 | + endif |
| 34 | + endfor |
| 35 | + |
| 36 | + " Try to find a good match on the same line and on the left of the cursor |
| 37 | + let start_position = v:null |
| 38 | + let potential_matches = filter(copy(all_positions), |
| 39 | + \ {v -> v[1] == cursor_position[1] && v[2] <= cursor_position[2]}) |
| 40 | + if len(potential_matches) > 0 |
| 41 | + let start_position = reduce(potential_matches, |
| 42 | + \ {a, b -> s:closest_position(cursor_position, a, b)}) |
| 43 | + endif |
| 44 | + |
| 45 | + if type(start_position) == type(v:null) |
| 46 | + " No match found yet, try on the same line but on the right of the |
| 47 | + " cursor |
| 48 | + let potential_matches = filter(copy(all_positions), |
| 49 | + \ {v -> v[1] == cursor_position[1] && v[2] > cursor_position[2]}) |
| 50 | + if len(potential_matches) > 0 |
| 51 | + let start_position = reduce(potential_matches, |
| 52 | + \ {a, b -> s:closest_position(cursor_position, a, b)}) |
| 53 | + endif |
| 54 | + endif |
| 55 | + |
| 56 | + if type(start_position) == type(v:null) |
| 57 | + " No match found yet, try to find one on lines above the cursor |
| 58 | + let potential_matches = filter(copy(all_positions), |
| 59 | + \ {v -> v[1] < cursor_position[1]}) |
| 60 | + if len(potential_matches) > 0 |
| 61 | + let start_position = reduce(potential_matches, |
| 62 | + \ {a, b -> s:closest_position(cursor_position, a, b)}) |
| 63 | + endif |
| 64 | + endif |
| 65 | + |
| 66 | + if type(start_position) == type(v:null) |
| 67 | + " No match found yet, try to find one on below after the cursor |
| 68 | + let potential_matches = filter(copy(all_positions), |
| 69 | + \ {v -> v[1] > cursor_position[1]}) |
| 70 | + if len(potential_matches) > 0 |
| 71 | + let start_position = reduce(potential_matches, |
| 72 | + \ {a, b -> s:closest_position(cursor_position, a, b)}) |
| 73 | + endif |
| 74 | + endif |
| 75 | + |
| 76 | + if type(start_position) == type(v:null) |
| 77 | + " The buffer must not contain any words - fall back to the cursor's |
| 78 | + " position |
| 79 | + let start_position = cursor_position |
| 80 | + endif |
| 81 | + |
| 82 | + call setpos('.', start_position) |
6 | 83 | call search('\>', 'c')
|
7 | 84 | let word_end = getpos('.')
|
8 | 85 | call setpos('.', start_position)
|
|
0 commit comments