1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
|
if !exists('g:field_marshal_insert_include_bindings')
let g:field_marshal_insert_include_bindings = 1
endif
if g:field_marshal_insert_include_bindings
" Like 'I', but skip past the first v:count1 WORDs. Useful for when one wants
" the 'I' behavior to respect comments.
"
" If there are fewer than v:count1 WORDs in the line, then append to the end of
" the line.
"
" Have to cheese this a little bit to get the redo (.) operator to work with it.
" This is done by making a "sort-of" 0-width text object that exists where the
" change should happen.
"
" If the 'g' is present, that acts similar to gI -- it does not skip
" whitespace and starts insertion directly after the v:count1'th word.
noremap cI <Plug>(insert-after-comment)
noremap cgI <Plug>(insert-after-comment-g)
" Insert before/after a motion.
"
" Zi - takes a text object, moves to the beginning of that text object and
" places the user in INSERT mode.
"
" Za - takes a text object, moves to the end of that text object and places
" the user in INSERT mode.
"
" Some of this functionality can be replicated using <C-R><C-P> in insert
" mode. For example, suffixing the current word with 'ed' can be
" accomplished with either:
"
" Zaeed<esc>
"
" or
"
" ce^R^P"ed<esc>
"
" or Prefixing with sub can be accomplished with
"
" Zibsub<esc>
"
" or
"
" cbsub^R^P"<esc>
"
" However the traditional ^R^P" solution is not very pretty and prone to
" typeos.
"
" This also means that certain motions are now redundant and can be
" emulated. For example:
"
" I === Zi^
" gI === Zi0
" A === Za$
"
"
noremap Zi <Plug>(insert-before-motion)
noremap Za <Plug>(append-after-motion)
noremap Zo <Plug>(open-after-motion)
noremap ZO <Plug>(OPEN-after-motion)
noremap Z[ <Plug>(to-object-start)
noremap Z] <Plug>(to-object-end)
" Zgi -- start another insert using the same parameters from the last Z[ia]
noremap Zgi c<Plug>(insert-about-obj)
vnoremap <expr> Zi "\<esc>'<" . (visualmode() == "V" ? "0" : "") . "i"
vnoremap <expr> Za "\<esc>'>" . (visualmode() == "V" ? "$" : "") . "a"
endif
noremap <Plug>(insert-after-comment) <cmd>call <sid>insert_comment_count(v:count1)<cr>1c<Plug><sid>(insert-comment-obj-nog)
noremap <Plug>(insert-after-comment-g)> <cmd>call <sid>insert_comment_count(v:count1)<cr>1c<Plug><sid>(insert-comment-obj-g)
onoremap <Plug><sid>(insert-comment-obj-nog) <cmd>call <sid>insert_comment_obj(0)<cr>
onoremap <Plug><sid>(insert-comment-obj-g) <cmd>call <sid>insert_comment_obj(1)<cr>
" Set the count for the insert comment command.
function! s:insert_comment_count(count) abort
let s:count = a:count
endfunction
" The function which will set the insert comment.
function! s:insert_comment_obj(g, ...) abort
if v:operator == 'c'
let end = 0
normal! 0
let i = 0
call search('^\s*\zs\S', '', line('.'))
while i < s:count
if col('.') == col('$') - 1
let end = 1
break
endif
if a:g
let pattern = '\S*\zs\ze\s\+'
else
let pattern = '\S*\s\+\zs'
endif
if ! search(pattern, '', line('.'))
let end = 1
break
endif
let i += 1
endwhile
" Cheese because 0-width visual selections aren't a thing, I don't think, so
" instead insert an ephemeral space and VIsual highlight that space, the c
" command will then remove that ephemeral space, all with the user being
" none-the-wiser.
if end
exec "normal! A \<esc>v"
else
exec "normal! i \<esc>v"
endif
else
endif
endfunction
noremap <silent> <Plug>(insert-before-motion)
\ <cmd>call <sid>prepare_operation('i', "c\<Plug>(insert-about-obj)")
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
noremap <silent> <Plug>(append-after-motion)
\ <cmd>call <sid>prepare_operation('a', "c\<Plug>(insert-about-obj)")
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
noremap <silent> <Plug>(open-after-motion)
\ <cmd>call <sid>prepare_operation('o', "c\<Plug>(insert-about-obj)")
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
noremap <silent> <Plug>(OPEN-after-motion)
\ <cmd>call <sid>prepare_operation('O', "c\<Plug>(insert-about-obj)")
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
nnoremap <silent> <Plug>(to-object-start)
\ <cmd>call <sid>prepare_operation('[', "\<Plug>(to-object-pos-post)")
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
nnoremap <silent> <Plug>(to-object-end)
\ <cmd>call <sid>prepare_operation(']', "\<Plug>(to-object-pos-post)")
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
" The Z[ and Z] commands as text motions. These are done in a similar hacky way as other plugin
" mappings in this file
"
" What they do, is:
"
" 1. prepare the operation, and prepare to send <operator>\<plug>(to-object-pos-post)
" 2. escape operator-pending mode. This mapping is not the actual mapping we want to use for the
" operation, we just use this as a dummy to set up all the variables needed for the actual
" operation.
" 3. start the recording macro.
" 4. enter operating-pending mode again. This will record the macro. Once the user has entered the
" operator, it will then call the <operator>\<plug>(to-object-pos-post). This is the command
" that we really want to be able repeat with the dot (.) operator.
onoremap <silent> <Plug>(to-object-start)
\ <cmd>call <sid>prepare_operation('[', printf("%s\<Plug>(to-object-pos-post)", v:operator))<cr>
\<esc>
\<cmd>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
onoremap <silent> <Plug>(to-object-end)
\ <cmd>call <sid>prepare_operation(']', printf("%s\<Plug>(to-object-pos-post)", v:operator))<cr>
\<esc>
\<cmd>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
onoremap <silent> <Plug>(to-object-pos-post) <cmd>call <sid>to_object_start()<cr>
nnoremap <silent> <Plug>(to-object-pos-post) <cmd>call <sid>to_object_start()<cr>
onoremap <silent> <Plug>(insert-about-obj) <cmd>call <sid>insert_before_recorded()<cr>
nnoremap <silent> <Plug>(insert-about-obj) <cmd>call <sid>insert_before_recorded()<cr>
" Save the 'l' register. This is the register used for recording the text
" motion.
let s:savereg = []
let s:savepos = []
let s:instype = ''
" Not many people use the 'z' register, right?
let s:reg_to_clobber = 'z'
" if exists('&urf')
" " Neovim has Rahm's multibyte register extension patch. Pick an arbitrary
" " unicode character which is probably not used very often to clobber.
" let s:reg_to_clobber = '∫'
" endif
function! s:start_recording()
exec "normal! q" . s:reg_to_clobber
endfunction
let s:operate_keys=''
function! s:prepare_operation(instype, operate_keys)
echom "operate_keys: " . a:operate_keys
" Unfortunately macros kinda break this feature. While I think I might be able
" to patch together a fix to make them work, I figure that I'll see if there's
" any real need to implement it.
if reg_recording() != ''
normal! q
endif
let s:savereg = [getreg(s:reg_to_clobber, 1, 1), getregtype(s:reg_to_clobber)]
let s:savepos = getpos('.')
let s:instype = a:instype
let s:operate_keys = a:operate_keys
endfunction
noremap <plug>(ñóþ) <nop>
" Save the motion postions, for use with g@.
function s:save_object(t) abort
let s:object = {
\ "type": a:t,
\ "start": getpos("'["),
\ "end": getpos("']")
\ }
endfunction
function! s:to_object_start() abort
set operatorfunc=s:save_object
exec "normal g@" . s:recorded
let pos = s:instype == '[' ? s:object.start : s:object.end
echom printf("Jump To [%s] (%s) (%s)", string(pos), s:recorded, v:operator)
call setpos('.', pos)
endfunction
function! s:insert_before_recorded() abort
let l:instype = s:instype
" Something of a hack. If the motion starts with i or a, it is probably a
" text object.
"
" I think there's probably a better way to handle this, but
if s:recorded =~ '^[ia]' || s:recorded =~ 'g[nN]' || s:recorded =~ '[_]'
" Without Rahm's patched Neovim, custom text objects will not work. This is
" because while the redo buffer is saved and restored when calling a user
" function, repeat_cmdline is not, and thus the g@ command clobbers the
" repeat_cmdline which breaks the redobuff. Ergo the first Zi will work,
" but subsequent repititions with the dot operator will not work.
set operatorfunc=s:save_object
exec "normal g@" . s:recorded
if l:instype == 'a'
call setpos(".", s:object.end)
if s:object.type == 'line'
normal! $
endif
elseif l:instype == 'i'
call setpos(".", s:object.start)
if s:object.type == 'line'
normal! 0
endif
if s:object.start[2] > col(".")
" Trying to insert at the $. Needs to be append.
let l:instype = 'a'
endif
elseif l:instype == 'o'
call setpos(".", s:object.end)
elseif l:instype == 'O'
call setpos(".", s:object.start)
endif
else
exec "normal " . s:recorded
endif
if l:instype == 'a'
exec "normal! \<esc>a \<esc>v"
elseif l:instype == 'i'
exec "normal! \<esc>i \<esc>v"
elseif l:instype == 'o'
exec "normal! \<esc>o \<esc>v"
elseif l:instype == 'O'
exec "normal! \<esc>O \<esc>v"
endif
endfunction
" Record the operator
function! s:recordop(...) abort
" Stop recording
normal! q
" Save the recorded amount
let s:recorded=getreg(s:reg_to_clobber)
" A limitation of normal! is that it can't start with a space, so use a NOP
" instead.
if s:recorded =~ '^\s'
let s:recorded = "\<plug>(ñóþ)" . s:recorded
endif
" Restore the register
call setreg(s:reg_to_clobber, s:savereg[0], s:savereg[1])
" Restore the position
call setpos('.', s:savepos)
" Called <Plug>(insert-about-obj). This is the part that can be repeated.
call feedkeys(s:operate_keys)
endfunction
|