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
|
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)
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>save_state('i')
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
noremap <silent> <Plug>(append-after-motion) <cmd>call <sid>save_state('a')
\<bar>call <sid>start_recording()
\<bar>set operatorfunc=<sid>recordop<cr>g@
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
function! s:save_state(instype)
" 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
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:insert_before_recorded() abort
" 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
" 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, butth
if s:recorded =~ '^[ia]'
" 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 s:instype == 'a'
call setpos(".", s:object.end)
if s:object.type == 'line'
normal! $
endif
else
call setpos(".", s:object.start)
if s:object.type == 'line'
normal! 0
endif
endif
else
exec "normal " . s:recorded
endif
if s:instype == 'a'
exec "normal! \<esc>a \<esc>v"
else
exec "normal! \<esc>i \<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)
" 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("c\<Plug>(insert-about-obj)")
endfunction
|