handy text object motions
1" Credits: romainl and habamax
2
3" 24 simple text objects
4" ----------------------
5" i_ i. i: i, i; i| i/ i\ i* i+ i- i#
6" a_ a. a: a, a; a| a/ a\ a* a+ a- a#
7for char in [ '_', '.', ':', ',', ';', '<bar>', '/', '<bslash>', '*', '+', '-', '#' ]
8 execute 'xnoremap i' . char . ' :<C-u>normal! T' . char . 'vt' . char . '<CR>'
9 execute 'onoremap i' . char . ' :normal vi' . char . '<CR>'
10 execute 'xnoremap a' . char . ' :<C-u>normal! F' . char . 'vf' . char . '<CR>'
11 execute 'onoremap a' . char . ' :normal va' . char . '<CR>'
12endfor
13
14" line text objects
15" -----------------
16" il al
17xnoremap il g_o^
18onoremap il :<C-u>normal vil<CR>
19xnoremap al $o0
20onoremap al :<C-u>normal val<CR>
21
22" backquote text objects
23" -----------------
24" ix ax
25xnoremap ix :<C-u>normal vi`<CR>
26onoremap ix :<C-u>normal vi`<CR>
27xnoremap ax :<C-u>normal va`<CR>
28onoremap ax :<C-u>normal va`<CR>
29
30" number text object (integer and float)
31" --------------------------------------
32" in
33function! VisualNumber()
34 call search('\d\([^0-9\.]\|$\)', 'cW')
35 normal v
36 call search('\(^\|[^0-9\.]\d\)', 'becW')
37endfunction
38xnoremap in :<C-u>call VisualNumber()<CR>
39onoremap in :<C-u>normal vin<CR>
40
41" buffer text objects
42" -------------------
43" i% a%
44xnoremap i% :<C-u>let z = @/\|1;/^./kz<CR>G??<CR>:let @/ = z<CR>V'z
45onoremap i% :<C-u>normal vi%<CR>
46xnoremap a% GoggV
47onoremap a% :<C-u>normal va%<CR>
48
49" square brackets text objects
50" ----------------------------
51" ir ar
52xnoremap ir i[
53xnoremap ar a[
54onoremap ir :normal vi[<CR>
55onoremap ar :normal va[<CR>
56
57" C++ style block comment text objects
58" ------------------------------------
59" i? a?
60xnoremap a? [*o]*
61onoremap a? :<C-u>normal va?V<CR>
62xnoremap i? [*jo]*k
63onoremap i? :<C-u>normal vi?V<CR>
64
65" last change text object
66" -----------------------
67" ik ak
68xnoremap ik `]o`[
69onoremap ik :<C-u>normal vik<CR>
70onoremap ak :<C-u>normal vikV<CR>
71
72
73" Indent text object
74" ------------------
75" ii ai
76func! s:indent_textobj(inner)
77 if getline('.') =~ '^\s*$'
78 let ln_start = s:detect_nearest_line()
79 let ln_end = ln_start
80 else
81 let ln_start = line('.')
82 let ln_end = ln_start
83 endif
84
85 let indent = indent(ln_start)
86 if indent > 0
87 while indent(ln_start) >= indent && ln_start > 0
88 let ln_start = prevnonblank(ln_start-1)
89 endwhile
90
91 while indent(ln_end) >= indent && ln_end <= line('$')
92 let ln_end = s:nextnonblank(ln_end+1)
93 endwhile
94 else
95 while indent(ln_start) == 0 && ln_start > 0 && getline(ln_start) !~ '^\s*$'
96 let ln_start -= 1
97 endwhile
98 while indent(ln_start) > 0 && ln_start > 0
99 let ln_start = prevnonblank(ln_start-1)
100 endwhile
101 while indent(ln_start) == 0 && ln_start > 0 && getline(ln_start) !~ '^\s*$'
102 let ln_start -= 1
103 endwhile
104
105 while indent(ln_end) == 0 && ln_end <= line('$') && getline(ln_end) !~ '^\s*$'
106 let ln_end += 1
107 endwhile
108 while indent(ln_end) > 0 && ln_end <= line('$')
109 let ln_end = s:nextnonblank(ln_end+1)
110 endwhile
111 endif
112
113 if a:inner || indent == 0
114 let ln_start = s:nextnonblank(ln_start+1)
115 endif
116
117 if a:inner
118 let ln_end = prevnonblank(ln_end-1)
119 else
120 let ln_end = ln_end-1
121 endif
122
123 if ln_end < ln_start
124 let ln_end = ln_start
125 endif
126
127 exe ln_end
128 normal! V
129 exe ln_start
130endfunc
131
132
133func! s:nextnonblank(lnum) abort
134 let res = nextnonblank(a:lnum)
135 if res == 0
136 let res = line('$')+1
137 endif
138 return res
139endfunc
140
141
142func! s:detect_nearest_line() abort
143 let lnum = line('.')
144 let nline = s:nextnonblank(lnum)
145 let pline = prevnonblank(lnum)
146 if abs(nline - lnum) > abs(pline - lnum) || getline(nline) =~ '^\s*$'
147 return pline
148 else
149 return nline
150 endif
151endfunc
152
153onoremap <silent>ii :<C-u>call <sid>indent_textobj(v:true)<CR>
154onoremap <silent>ai :<C-u>call <sid>indent_textobj(v:false)<CR>
155xnoremap <silent>ii :<C-u>call <sid>indent_textobj(v:true)<CR>
156xnoremap <silent>ai :<C-u>call <sid>indent_textobj(v:false)<CR>