-
Notifications
You must be signed in to change notification settings - Fork 267
/
README
592 lines (533 loc) · 32 KB
/
README
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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
======
Vimode
======
.. contents::
About
=====
Vimode is a Vim-mode plugin for Geany written by a guy who does not use Vim.
Expect problems unexpected by a Vim user and, please, report them.
Despite the limited Vim knowledge of the author, the plugin tries to be a
reasonably complete Vim mode implementation featuring:
* normal mode, insert/replace mode, visual mode, line visual mode
* repeated commands (e.g. 10dd - delete 10 lines)
* "motion" commands (e.g. d10l - delete 10 characters to the right)
* "text object" commands (e.g. di( - delete inner contents of parentheses)
* visual mode commands (e.g. ~ to swap case of the selected text)
* basic ex mode commands like :s, including range specifications (e.g.
:5,8s/foo/bar/g - replace foo with bar on lines 5 through 8)
* most basic navigation, selection and text manipulation commands - see the end
of this file for the full list
* command repetition using "." and repeated insert
It should be relatively easy to add more (non-special) commands so if you run
into something you are missing, please let me know.
Setup and Configuration
=======================
The plugin can be enabled/disabled from the Plugin Manager of Geany. Once enabled,
it adds a new menu called Vim Mode under the Tools menu with the following items.
Enable Vim Mode
---------------
Enables/disables the Vim mode. A keybinding can be assigned to this action so
you can for instance use Geany normally and enable/disable the Vim mode as
needed.
Insert Mode for Dummies
-----------------------
This makes the insert mode behave like normal Geany, only the escape key allows
you to switch to the Vim command mode. This is basically "Vim for the rest of us"
who want to use the editor in a standard (understand non-vim) way but who like
the idea of having access to Vim commands from time to time. Highly unintrusive
so you basically do not know about the Vim mode normally.
Start in Insert Mode
--------------------
By default, the plugin starts in the normal mode. If you enable the "dummies"
mode above, you might also want to enable this option so you do not have to
switch to the insert mode manually when the application starts.
Behavior
========
Upon changing mode, the plugin writes the current mode in the status bar. The
caret shape also indicates the current mode:
* block, not blinking - normal mode
* vertical line, not blinking - visual mode
* blinking vertical line - insert mode
* blinking underscore - replace mode
When evaluating key presses, the plugin checks if the keypress is a Vim command
or a part of a command in which case the plugin consumes the key press event
and does not propagate it to Geany. When the keypress is not a Vim command,
the plugin sends it to Geany which processes it normally based in its internal
logic. This means that it is still possible to use normal Geany keybindings
with this plugin unless they conflict with a Vim command.
If autocompletion popups or tooltips are present in insert mode, escape closes
them first without entering the normal mode so you do not enter normal mode
by accident.
Limitations and Problems
------------------------
I tried to implement a reasonable subset of Vim commands but please note that
the judgement what is a reasonable set of commands was made by a guy who does not
use Vim. So it is very probable I missed some totally fundamental behavior
of Vim every Vim user would expect to be present. Please report such problems.
This is an incomplete list of known limitations of the plugin:
* selection in visual mode does not behave the same way as in Vim - the reason is
that the editor component Geany uses (Scintilla) uses cursor which is always
between characters and not on characters (block cursor which appears to be
on top of a character behaves as if it were before the character). This may lead
to situations when the position of the cursor is off by one. This issue might
be fixed later but it will be tricky.
* undo does not preserve cursor position the same way Vim does - probably fixable
* block visual mode is not implemented - probably possible using Scintilla's
multiple selection feature
* select submode of insert mode is not implemented
* named registers and related commands are not implemented
* Ctrl+X mode is not implemented
* marks are not implemented
* many fold commands are not implemented
* most commands starting with "'", "z", and "g" are not implemented
* most ex mode commands are not implemented (excluding basic stuff like search,
replace, saving, etc.)
* despite being mentioned below, none of the commands for quitting (:q, ZZ, etc.)
work because the corresponding function is not in Geany API yet - everything is
ready in the plugin though
* only the 'g' flag is supported in the substitute command
* in search and substitute the regular expressions are based on Scintilla regular
expressions which differ from Vim. Check the Scintilla documentation at
https://www.scintilla.org/ScintillaDoc.html#Searching for more details.
In addition, \c is also supported to allow case-insensitive search.
FAQ
===
Why does Vimode suck so much?
-----------------------------
Well, it simulates the Vim behavior - what did you expect?
No, stupid, I mean why does your implementation suck so much?
-------------------------------------------------------------
Ah, that's simple - I am not a Vim user. Before writing this plugin, I knew
about 5 Vim commands (after writing this plugin, my knowledge has nearly doubled).
Even though I kind of like the idea behind the editor, my poor brain isn't able
to remember in which mode I currently am and what keypresses I can use. This
means I don't really know how a typical user uses Vim and I probably miss
some very basic things Vim users take for granted. Please report such issues
so I can improve the plugin.
So why the hell did you write this plugin?
------------------------------------------
It was the constant whining of Vim users at Prague and Chemnitz Linux Days which
made me write the plugin. And it turned out that writing a Vim editor is
quite a lot of fun - much more than using it.
Meh, even I could write a better Vim plugin
-------------------------------------------
Great! Submit patches! Fix bugs! All contributions are really welcome.
Help! I enabled your plugin together with others and the editor is really strange now!
--------------------------------------------------------------------------------------
This, my friend, is the world of Vim. Welcome! Fortunately, you can easily
disable it using Geany's Plugin Manager. Phew!
Help! I am a long-time Vim user and can't quit the editor, :q doesn't work!
---------------------------------------------------------------------------
Geany currently doesn't allow plugins to quit the editor so you have to do
it in a non-vim way. This is where the tricky part starts for Vim users: with your
mouse navigate to the top-right corner of the window to the X button and click
it - behold, the window closes (I know, totally counter-intuitive for Vim users).
After building the plugin, I noticed a binary called viw, what is it?
---------------------------------------------------------------------
After I started writing the plugin, I soon realized that in fact, I am writing
a new editor. I nearly didn't use any Geany calls and most of the code just
calls the Scintilla API. At this point I decided to separate the Geany plugin
part from the rest of the code which is completely Geany-independent. And now
I could write a simple editor which just uses Scintilla and GTK (well,
not exactly - the way it builds now it still uses Scintilla from libgeany
but the build could be easily modified to link against statically built
Scintilla without any Geany dependency). So yeah, I'm a real man now, have my own
editor - it only sucks it's a Vim clone. And in fact it turned out to be useful
for the development of the plugin because one can use the viw (Vi Worsened)
editor for testing instead of having to restart Geany all the time.
So does it mean I could use your code and add Vim support to another editor?
----------------------------------------------------------------------------
Yes - as long as the editor is based on Scintilla and GTK. If it is, it should
be really simple - just check the "backends" directory how it is done for Geany
and viw. I believe it should still be quite simple to modify the code if
the editor uses Scintilla but doesn't use GTK - the amount of the used GTK code
is very small (most work will be with re-mapping the key event codes to the
other library). If your editor isn't Scintilla-based, you are more or less
doomed - most of the code deals with Scintilla and switching to a different
editor component basically means rewriting the plugin.
Contact
=======
Author
------
Jiří Techet, <techet(at)gmail(dot)com>.
Bug Reports
-----------
Please direct all questions, bug reports and patches to the combined geany-plugins
project at https://github.com/geany/geany-plugins and open the corresponding
bug report or pull request there. To notify the author of this plugin about
your post, mention him using his github user name (@techee).
License
=======
Vimode is distributed under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. A copy of this license
can be found in the file COPYING included with the source code of this
program.
Downloads
=========
Vimode is part of the combined Geany Plugins release. For more information and
downloads, please visit https://plugins.geany.org/geany-plugins/
Source Code
===========
The source code is available at::
git clone https://github.com/geany/geany-plugins.git
Implemented Commands
====================
The rest of the file contains a list of Vim commands which have been at least
partially implemented in the plugin. This is taken from the index.txt Vim help
file which is also present in the root directory of the plugin. If you add
a new command, please do not forget to update the table below.::
==============================================================================
1. Insert mode insert-index
tag char action in Insert mode
-----------------------------------------------------------------------
i_CTRL-@ CTRL-@ insert previously inserted text and stop
insert
i_CTRL-A CTRL-A insert previously inserted text
i_CTRL-C CTRL-C quit insert mode, without checking for
abbreviation, unless 'insertmode' set.
i_CTRL-D CTRL-D delete one shiftwidth of indent in the current
line
i_CTRL-E CTRL-E insert the character which is below the cursor
i_<BS> <BS> delete character before the cursor
i_CTRL-H CTRL-H same as <BS>
i_<Tab> <Tab> insert a <Tab> character
i_CTRL-I CTRL-I same as <Tab>
i_<NL> <NL> same as <CR>
i_CTRL-J CTRL-J same as <CR>
i_<CR> <CR> begin new line
i_CTRL-M CTRL-M same as <CR>
i_CTRL-O CTRL-O execute a single command and return to insert
mode
i_CTRL-T CTRL-T insert one shiftwidth of indent in current
line
i_CTRL-W CTRL-W delete word before the cursor
i_CTRL-Y CTRL-Y insert the character which is above the cursor
i_<Esc> <Esc> end insert mode (unless 'insertmode' set)
i_CTRL-[ CTRL-[ same as <Esc>
i_<Del> <Del> delete character under the cursor
i_<Left> <Left> cursor one character left
i_<S-Left> <S-Left> cursor one word left
i_<C-Left> <C-Left> cursor one word left
i_<Right> <Right> cursor one character right
i_<S-Right> <S-Right> cursor one word right
i_<C-Right> <C-Right> cursor one word right
i_<Up> <Up> cursor one line up
i_<S-Up> <S-Up> same as <PageUp>
i_<Down> <Down> cursor one line down
i_<S-Down> <S-Down> same as <PageDown>
i_<Home> <Home> cursor to start of line
i_<C-Home> <C-Home> cursor to start of file
i_<End> <End> cursor past end of line
i_<C-End> <C-End> cursor past end of file
i_<PageUp> <PageUp> one screenful backward
i_<PageDown> <PageDown> one screenful forward
i_<Insert> <Insert> toggle Insert/Replace mode
==============================================================================
2. Normal mode normal-index
CHAR any non-blank character
WORD a sequence of non-blank characters
N a number entered before the command
{motion} a cursor movement command
Nmove the text that is moved over with a {motion}
SECTION a section that possibly starts with '}' instead of '{'
note: 1 = cursor movement command; 2 = can be undone/redone
tag char note action in Normal mode
------------------------------------------------------------------------------
CTRL-B CTRL-B 1 scroll N screens Backwards
CTRL-D CTRL-D scroll Down N lines (default: half a screen)
CTRL-E CTRL-E scroll N lines upwards (N lines Extra)
CTRL-F CTRL-F 1 scroll N screens Forward
<BS> <BS> 1 same as "h"
CTRL-H CTRL-H 1 same as "h"
<NL> <NL> 1 same as "j"
CTRL-J CTRL-J 1 same as "j"
<CR> <CR> 1 cursor to the first CHAR N lines lower
CTRL-M CTRL-M 1 same as <CR>
CTRL-N CTRL-N 1 same as "j"
CTRL-P CTRL-P 1 same as "k"
CTRL-R CTRL-R 2 redo changes which were undone with 'u'
CTRL-U CTRL-U scroll N lines Upwards (default: half a
screen)
CTRL-Y CTRL-Y scroll N lines downwards
<Space> <Space> 1 same as "l"
# # 1 search backward for the Nth occurrence of
the ident under the cursor
$ $ 1 cursor to the end of Nth next line
% % 1 find the next (curly/square) bracket on
this line and go to its match, or go to
matching comment bracket, or go to matching
preprocessor directive.
N% {count}% 1 go to N percentage in the file
& & 2 repeat last :s
star * 1 search forward for the Nth occurrence of
the ident under the cursor
+ + 1 same as <CR>
, , 1 repeat latest f, t, F or T in opposite
direction N times
- - 1 cursor to the first CHAR N lines higher
. . 2 repeat last change with count replaced with
N
/ /{pattern}<CR> 1 search forward for the Nth occurrence of
{pattern}
/<CR> /<CR> 1 search forward for {pattern} of last search
count 0 1 cursor to the first char of the line
count 1 prepend to command to give a count
count 2 "
count 3 "
count 4 "
count 5 "
count 6 "
count 7 "
count 8 "
count 9 "
: : 1 start entering an Ex command
; ; 1 repeat latest f, t, F or T N times
< <{motion} 2 shift Nmove lines one 'shiftwidth'
leftwards
<< << 2 shift N lines one 'shiftwidth' leftwards
> >{motion} 2 shift Nmove lines one 'shiftwidth'
rightwards
>> >> 2 shift N lines one 'shiftwidth' rightwards
? ?{pattern}<CR> 1 search backward for the Nth previous
occurrence of {pattern}
?<CR> ?<CR> 1 search backward for {pattern} of last search
A A 2 append text after the end of the line N times
B B 1 cursor N WORDS backward
C ["x]C 2 change from the cursor position to the end
of the line, and N-1 more lines [into
register x]; synonym for "c$"
D ["x]D 2 delete the characters under the cursor
until the end of the line and N-1 more
lines [into register x]; synonym for "d$"
E E 1 cursor forward to the end of WORD N
F F{char} 1 cursor to the Nth occurrence of {char} to
the left
G G 1 cursor to line N, default last line
H H 1 cursor to line N from top of screen
I I 2 insert text before the first CHAR on the
line N times
J J 2 Join N lines; default is 2
L L 1 cursor to line N from bottom of screen
M M 1 cursor to middle line of screen
N N 1 repeat the latest '/' or '?' N times in
opposite direction
O O 2 begin a new line above the cursor and
insert text, repeat N times
P ["x]P 2 put the text [from register x] before the
cursor N times
R R 2 enter replace mode: overtype existing
characters, repeat the entered text N-1
times
S ["x]S 2 delete N lines [into register x] and start
insert; synonym for "cc".
T T{char} 1 cursor till after Nth occurrence of {char}
to the left
V V start linewise Visual mode
W W 1 cursor N WORDS forward
X ["x]X 2 delete N characters before the cursor [into
register x]
Y ["x]Y yank N lines [into register x]; synonym for
"yy"
ZZ ZZ store current file if modified, and exit
ZQ ZQ exit current file always
^ ^ 1 cursor to the first CHAR of the line
_ _ 1 cursor to the first CHAR N - 1 lines lower
a a 2 append text after the cursor N times
b b 1 cursor N words backward
c ["x]c{motion} 2 delete Nmove text [into register x] and
start insert
cc ["x]cc 2 delete N lines [into register x] and start
insert
d ["x]d{motion} 2 delete Nmove text [into register x]
dd ["x]dd 2 delete N lines [into register x]
e e 1 cursor forward to the end of word N
f f{char} 1 cursor to Nth occurrence of {char} to the
right
g g{char} extended commands, see g below
h h 1 cursor N chars to the left
i i 2 insert text before the cursor N times
j j 1 cursor N lines downward
k k 1 cursor N lines upward
l l 1 cursor N chars to the right
n n 1 repeat the latest '/' or '?' N times
o o 2 begin a new line below the cursor and
insert text, repeat N times
p ["x]p 2 put the text [from register x] after the
cursor N times
r r{char} 2 replace N chars with {char}
s ["x]s 2 (substitute) delete N characters [into
register x] and start insert
t t{char} 1 cursor till before Nth occurrence of {char}
to the right
u u 2 undo changes
v v start characterwise Visual mode
w w 1 cursor N words forward
x ["x]x 2 delete N characters under and after the
cursor [into register x]
y ["x]y{motion} yank Nmove text [into register x]
yy ["x]yy yank N lines [into register x]
bar | 1 cursor to column N
~ ~ 2 'tildeop' off: switch case of N characters
under cursor and move the cursor N
characters to the right
<C-End> <C-End> 1 same as "G"
<C-Home> <C-Home> 1 same as "gg"
<C-Left> <C-Left> 1 same as "b"
<C-Right> <C-Right> 1 same as "w"
<Del> ["x]<Del> 2 same as "x"
<Down> <Down> 1 same as "j"
<End> <End> 1 same as "$"
<Home> <Home> 1 same as "0"
<Insert> <Insert> 2 same as "i"
<Left> <Left> 1 same as "h"
<PageDown> <PageDown> same as CTRL-F
<PageUp> <PageUp> same as CTRL-B
<Right> <Right> 1 same as "l"
<S-Down> <S-Down> 1 same as CTRL-F
<S-Left> <S-Left> 1 same as "b"
<S-Right> <S-Right> 1 same as "w"
<S-Up> <S-Up> 1 same as CTRL-B
<Up> <Up> 1 same as "k"
==============================================================================
2.1 Text objects objects
These can be used after an operator or in Visual mode to select an object.
tag command action in op-pending and Visual mode
------------------------------------------------------------------------------
v_aquote a" double quoted string
v_a' a' single quoted string
v_a( a( same as ab
v_a) a) same as ab
v_a< a< "a <>" from '<' to the matching '>'
v_a> a> same as a<
v_aB aB "a Block" from "[{" to "]}" (with brackets)
v_aW aW "a WORD" (with white space)
v_a[ a[ "a []" from '[' to the matching ']'
v_a] a] same as a[
v_a` a` string in backticks
v_ab ab "a block" from "[(" to "])" (with braces)
v_aw aw "a word" (with white space)
v_a{ a{ same as aB
v_a} a} same as aB
v_iquote i" double quoted string without the quotes
v_i' i' single quoted string without the quotes
v_i( i( same as ib
v_i) i) same as ib
v_i< i< "inner <>" from '<' to the matching '>'
v_i> i> same as i<
v_iB iB "inner Block" from "[{" and "]}"
v_iW iW "inner WORD"
v_i[ i[ "inner []" from '[' to the matching ']'
v_i] i] same as i[
v_i` i` string in backticks without the backticks
v_ib ib "inner block" from "[(" to "])"
v_iw iw "inner word"
v_i{ i{ same as iB
v_i} i} same as iB
==============================================================================
2.4 Commands starting with 'g' g
tag char note action in Normal mode
------------------------------------------------------------------------------
gE gE 1 go backwards to the end of the previous
WORD
gU gU{motion} 2 make Nmove text uppercase
ge ge 1 go backwards to the end of the previous
word
gg gg 1 cursor to line N, default first line
gu gu{motion} 2 make Nmove text lowercase
g~ g~{motion} 2 swap case for Nmove text
==============================================================================
2.5 Commands starting with 'z' z
tag char note action in Normal mode
------------------------------------------------------------------------------
z<CR> z<CR> redraw, cursor line to top of window,
cursor on first non-blank
z+ z+ cursor on line N (default line below
window), otherwise like "z<CR>"
z- z- redraw, cursor line at bottom of window,
cursor on first non-blank
z. z. redraw, cursor line to center of window,
cursor on first non-blank
zA zA open a closed fold or close an open fold
recursively
zC zC close folds recursively
zM zM set 'foldlevel' to zero
zO zO open folds recursively
zR zR set 'foldlevel' to the deepest fold
za za open a closed fold, close an open fold
zb zb redraw, cursor line at bottom of window
zc zc close a fold
zo zo open fold
zt zt redraw, cursor line at top of window
zz zz redraw, cursor line at center of window
==============================================================================
3. Visual mode visual-index
Most commands in Visual mode are the same as in Normal mode. The ones listed
here are those that are different.
tag command note action in Visual mode
------------------------------------------------------------------------------
v_CTRL-C CTRL-C stop Visual mode
v_: : start a command-line with the highlighted
lines as a range
v_< < 2 shift the highlighted lines one
'shiftwidth' left
v_> > 2 shift the highlighted lines one
'shiftwidth' right
v_C C 2 delete the highlighted lines and start
insert
v_D D 2 delete the highlighted lines
v_J J 2 join the highlighted lines
v_O O Move horizontally to other corner of area.
v_R R 2 delete the highlighted lines and start
insert
v_S S 2 delete the highlighted lines and start
insert
v_U U 2 make highlighted area uppercase
v_V V make Visual mode linewise or stop Visual
mode
v_X X 2 delete the highlighted lines
v_Y Y yank the highlighted lines
v_c c 2 delete highlighted area and start insert
v_d d 2 delete highlighted area
v_o o move cursor to other corner of area
v_r r 2 delete highlighted area and start insert
v_s s 2 delete highlighted area and start insert
v_u u 2 make highlighted area lowercase
v_v v make Visual mode characterwise or stop
Visual mode
v_x x 2 delete the highlighted area
v_y y yank the highlighted area
v_~ ~ 2 swap case for the highlighted area
==============================================================================
5. EX commands ex-cmd-index :index
This is a brief but complete listing of all the ":" commands, without
mentioning any arguments. The optional part of the command name is inside [].
The commands are sorted on the non-optional part of their name.
tag command action
------------------------------------------------------------------------------
:& :& repeat last ":substitute"
:< :< shift lines one 'shiftwidth' left
:> :> shift lines one 'shiftwidth' right
:copy :co[py] copy lines
:cquit :cq[uit] quit Vim with an error code
:delete :d[elete] delete lines
:exit :exi[t] same as ":xit"
:join :j[oin] join lines
:move :m[ove] move lines
:put :pu[t] insert contents of register in the text
:quit :q[uit] quit current window (when one window quit Vim)
:quitall :quita[ll] quit Vim
:qall :qa[ll] quit Vim
:redo :red[o] redo one undone change
:substitute :s[ubstitute] find and replace text
:t :t same as ":copy"
:undo :u[ndo] undo last change(s)
:update :up[date] write buffer if modified
:write :w[rite] write to a file
:wall :wa[ll] write all (changed) buffers
:wq :wq write to a file and quit window or Vim
:wqall :wqa[ll] write all changed buffers and quit Vim
:xit :x[it] write if buffer changed and quit window or Vim
:xall :xa[ll] same as ":wqall"
:yank :y[ank] yank lines into a register
:~ :~ repeat last ":substitute"