-
Notifications
You must be signed in to change notification settings - Fork 110
AdvancedTopicTutorial
- High speed tour from beginner to expert in 7 steps
- Core concept of Vim: Two important role in editing.
- Operator modifier
- Advanced concept
- persistent-selection
- preset-occurrence
- When occurrence is exists, target is re-selected before applying operator to target.
- Useful operator and target(Motion, TextObject) used with ocurrence.
- Motion
- TextObject
- Exercise.
To attract your attention, I'll first try to lift up your Vim level with only 7 steps!
- You know visual-mode
- Use TextObject
- Use better Operator
- Combine operator with text-object
- Modify operator's behavior by
o
to make it operate on occurrence - Use preset-occurrence
- Use persistent-selection
This is 1st paragraph text.
2nd line also include text text text.
3rd line include text text text
This is 2nd paragraph text.
2nd line also include text text text.
3rd line include text text text
4th text
Say you want to replace the whole 1st paragraph with abc
.
You first select the paragraph using visual-mode
.
-
v j j $
orV j j
. -
d
to delete selected text. -
i
to startinsert-mode
. - Type
abc
thenescape
.
DONE. Well done.
You can do better by using TextObject
.
You can select the whole paragraph with i p
(inner-paragraph
).
-
v i p
. -
d
to delete selected text. -
i
to startinsert-mode
. - Type
abc
thenescape
.
DONE. Much better.
You can do even better by using Operator
.
Instead of triggering delete
on the selected text, then starting insert-mode
with i
, you can perform both steps at once with the change
operator.
-
v i p
. -
c
tochange
text. Whole paragraph getsdeleted
and you end up ininsert-mode
. - Type
abc
thenescape
.
DONE. Much, much better.
You can do way better by not using visual-mode
at all.
What's the benefit?
You don't have to type v
or V
to start visual-mode
, saving one keystroke.
You edit more declaratively than imperatively.
Instead of saying "select then mutate this selection", you could be saying "mutate this target" and leave the details to the vim backend.
The more you get familiar with this flow (operator
first, then target
), the less you'll resort to using the visual-mode
.
On the bonus side, by going operator
first, your operation becomes repeatable with .
!
By repeating the same operator on successive targets, you can quickly apply the same editing transaction to different places (different paragraphs in this example).
-
c i p
tochange
inner-paragraph
. Operator first, then target(TextObject). - Type
abc
thenescape
.
DONE. Wow, the number of keystrokes was dramatically reduced!
And you may now apply the same editing intent to next paragraph, simply by moving the cursor to next paragraph then hitting .
to reapply the operator!
New requirement…
Instead of changing the whole paragraph to abc
, you want to replace text
, which appears in the 1st paragraph, with abc
.
That's when the o
operator-modifier comes into play!
- Move the cursor to
text
in the 1st paragraph. -
c o i p
, orc o p
. - Type
abc
thenescape
.
DONE. What happened?
The o
is the operator-modifier, which alters an operator's default behavior.
The effect of o
is that it re-selects the keyword under-cursor within the whole target area (the 1st paragraph in this case, due to p
being the target) under the hood.
To gain a better understanding of this concept of using an operator in combination with occurrence
, it might be easier first to thinking about operators and target in the following way: *instead of saying "Do this operation, on this target", let's instead say "Apply this operator to this target" (which the results in the same operation).
In this example, we're interested in "Apply change operator to this paragraph" instead of "Change this paragraph"
From there, when occurrence
gets involved, the sentence becomes: "Apply change operator to occurrences in this paragraph".
And of course, you may repeat the same edit-unit on the 2nd paragraph, with .
.
Again, new requirement.
You now also want to change the text
and line
keywords in the 1st paragraph to abc
.
Now you have to replace two keywords at once.
You can achieve that by using preset-occurrence
.
Instead of typing o
in the middle of your operation, you can pre-set occurrences with g o
.
- Move cursor to
text
in the 1st paragraph. -
g o
topreset-occurrence
fortext
keyword. - Move to the 2nd line over the
line
keyword, theng o
. -
c i p
orc p
. - Type
abc
thenescape
.
DONE. Since you performed a pre-set on the keywords occurences, your operator is applied to the text
and the line
keywords just the same.
The benefit is that you can choose the operator after you have already decided the occurrence keyword, the target being the area to operate within as usual.
New requirement!
You want to replace line
and text
in both the 1st and the 2nd paragraphs.
But, you also want to exclude the 2nd line of the 2nd paragraph. Therefore, you cannot use the .
powerful repeating trick!
In this case, persistent-selection
comes to the rescue.
- Create
preset-occurrence
fortext
andline
keywords withg o
. -
v i p
to select the 1st paragraph, thenj j
to extend the selection to the 1st line of the 2nd paragraph. -
enter
. The actual selection becomes apersistent-selection
. -
j j
to move to the 3rd line of the 2nd paragraph. -
V j
to select 3rd and 4th lines of the 2nd paragraph. -
c
to changepreset-occurrence
s' keywords within the selection (which includespersistent-selection
). - Type
abc
.
DONE. Well DONE.
You're now a super Vimmer!!
To sum it up:
- The Operator is the verb of an operation.
- The TextObject is the object of an operation.
- An Operation is a full-fledged sentence in text editing in Vim, resulting in an edit/action.
Do practice with different verbs (Operator) and different objects (Motion or TextObject)!!
Train your finger and muscle memory until you can type without thinking, until you can transform text with minimum keystroke footprint!!
To complement your understanding, I strongly recommend you read Operator, the true power of Vim by kana.
- Sample text is Atom's excerpt from vim-mode-plus's keymap definition.
- Your mission is to transform string from
'?': 'vim-mode-plus:search-backwards'
form toSearchBackwards
. - You have to do this for ALL lines in sample text, and finally sort all lines.
- If I explain in imperative editing style, what you'll do is
- Remove leading keystroke part including ending
:
. - Also you have to remove
vim-mode-plus:
- Also you have to remove line-ending
'
- Then you need to transform
dash-case
toDashCase
form. - Finally sort all lines. and remove blank lines. `
- Remove leading keystroke part including ending
'`': 'vim-mode-plus:move-to-mark'
"'": 'vim-mode-plus:move-to-mark-line'
'/': 'vim-mode-plus:search'
'?': 'vim-mode-plus:search-backwards'
'*': 'vim-mode-plus:search-current-word'
'#': 'vim-mode-plus:search-current-word-backwards'
'n': 'vim-mode-plus:repeat-search'
'N': 'vim-mode-plus:repeat-search-reverse'
'%': 'vim-mode-plus:move-to-pair'
')': 'vim-mode-plus:move-to-next-sentence'
'(': 'vim-mode-plus:move-to-previous-sentence'
# ')': 'vim-mode-plus:move-to-next-sentence-skip-blank-row'
# '(': 'vim-mode-plus:move-to-previous-sentence-skip-blank-row'
'[': 'vim-mode-plus:move-up-to-edge'
']': 'vim-mode-plus:move-down-to-edge'
'}': 'vim-mode-plus:move-to-next-paragraph'
'{': 'vim-mode-plus:move-to-previous-paragraph'
'G': 'vim-mode-plus:move-to-last-line'
'g g': 'vim-mode-plus:move-to-first-line'
'H': 'vim-mode-plus:move-to-top-of-screen'
'L': 'vim-mode-plus:move-to-bottom-of-screen'
'M': 'vim-mode-plus:move-to-middle-of-screen'
MoveDownToEdge
MoveToBottomOfScreen
MoveToFirstLine
MoveToLastLine
MoveToMark
MoveToMarkLine
MoveToMiddleOfScreen
MoveToNextParagraph
MoveToNextSentence
MoveToNextSentenceSkipBlankRow
MoveToPair
MoveToPreviousParagraph
MoveToPreviousSentence
MoveToPreviousSentenceSkipBlankRow
MoveToTopOfScreen
MoveUpToEdge
RepeatSearch
RepeatSearchReverse
Search
SearchBackwards
SearchCurrentWord
SearchCurrentWordBackwards
- Assuming macOS keymaps
- You need to enable
incrementalSearch
setting.
- Start incremental-search by
/
. - Input
.*plus:
in the search field, confirm highlight (this is the target you willchange
). -
ctrl-cmd-c
(change-occurrence-from-search
which change matches of search), enteroperator-pending
mode, so you have to tell a target of operator. -
i e
(inner-entire
), to specify whole buffer as a target. - You are now in
insert-mode
with multiple-cursors on each line.ctrl-e
to move to EOL thenctrl-h
to remove trailing single quotes'
. -
escape
to return tonormal-mode
. You have still multiple cursors. -
ctrl-s
(transform-string-by-select-list
) then selectPascalize
and confirm byenter
, theni W
(inner-whole-word
). Adash-case
were transformed to aDashCase
. -
g g
to move to top of buffer.g s G
. tosort
(g s
) from here-to-bottom-of-buffer (G
). -
d i p
removes consolidated(by sorting) blank rows.
It seems to be complex procedure, but it's matter of how much your finger is trained.
It's the same as swing practice in baseball, same as piano fingering, same as kata in karate.
Just train, let's train your finger muscle!!
In order to understand an advanced topic like occurrence-modifier
, preset-occurrence
, persistent-selection
without difficulty, you must understand the very basic concept which consists of editing-in-the-vim-world.
So please patiently and carefully read the following short conceptual explanation.
In Vim editing, there are two very important key roles which compose your whole editing experience. The two key roles are Operator and Target.
- Operator: Specify what to do. The verb. The verb which requires an object.
- Target: Specify where, which to do. The target of the operator. The object for the verb.
So all of Vim editing is continuously telling vim to "Do what to which target".
- Do what is expressed by Operator
- Which target is expressed by Motion or TextObject
- An operator require a target
- If an operator does not have a satisfactory target, it enter
operator-pending
mode to get target from user. In other words,operator-pending
mode istarget-waiting
mode. - Some operators are pre-targeted so they don't have to get the target from user (it won't enter
operator-pending
. e.gD
is pre-targeted with$
motion. soD
is short hand ford $
. - Pre-targeted operators are good for less keystrokes but bad for flexibility, since they don't allow you to specify an arbitrary target you want to mutate.
- A target is a range of text determined by
Motion
orTextObject
. -
TextObject
defines target range (start
andend
position). -
Motion
is essentially used to move cursor, so it only define final-target-position (destination to move). - When
Motion
is used as target, current-cursor-position (here
) is used asstart
; you can think motion-as-target like text-object with a range which extends from here-to-destination. -
visual-mode
is special. When you type an operator invisual-mode
, it immediately mutatecurrent-selection
, In other words all operators used invisual-mode
are pre-targeted (preset-target) tocurrent-selection
.
To use operator-modifier, you insert keystroke between operator and target.
Following text illustrate where or when you have to type operator-modifier
.
# delete from-here-to-next-row in linewise
d j
^ here
# delete from here-to-next-word in characterwise
d w
^ here
# change inner-paragraph mutate whole paragraph
c i p
^ here
In vmp, currently three operator-modifiers are available.(ctrl-v
modifier is not yet supported.)
-
v
: Force target range tocharacterwise
range. -
V
: Force target range tolinewise
range. -
o
: Reselect occurrences of keyword within target range before applying operator.
# delete from-here-to-next-row in characterwise.(characterwise range, not whole two lines).
d v j
^ characterwise modifier is used.
# delete from here-to-next-word in linewise.(whole current line).
d V w
^ linewise V modifier is used, target range become linewise.
# change all occurrence of keyword under-cursor appears in paragraph.
c o i p
^ o modifier pick cursor-word as occurrence, re-select it appearing in paragraph.
For o
modifier, OccurrenceModifier
Before starting explanation, here are some fancy GIFs to motivate you to learn these new way of editing.
From v0.58.0.
- Allow user to set target BEFORE operator.
- Used as implicit target of operator. As like selection in
visual-mode
is used as implict target. - Config:
autoSelectPersistentSelectionOnOperate
(default=true
) control to disable implicit targeting. - Keymap: In
visual
,enter
tocreate-persistent-selection
. - If you map
c s
tochange-surround
, I recommend you to change it, also change other keymaps starting withc
. Otherwise, you have to wait timeout after typingc
where you can immediately mutate persistent-selection. - Following two operation do the same thing, but former target is normal selection, later target is
persistent-selection
.-
V j j c
: change two three line. -
V j j enter c
: change three line.
-
- Work on multiple target without using mouse: set multiple target by
persistent-selection
then mutate. - Narrow target range to include particular set of
occurrence
.
From v0.58.0.
- Allow user to set occurrence BEFORE operator.
- Keymap: In
normal
,visual
,g o
totoggle-preset-occurrence
.- It add/remove
preset-occurrence
at cursor position. - When removing, it remove one by one, not all.
- It add/remove
- Keymap: In incsearch input,
cmd-o
toadd-occurrence-pattern-from-search
- It add
preset-occurrence
by search-pattern.
- It add
- Following two operation do the same thing, but former is
operator-modifier
, later ispreset-occurrence
(g o
).-
c o $
: change cursor-word till end-of-line. -
g o c $
: change cursor-word till end-of-line.
-
- I recommend user also try to enable
stayOnTransformString
,stayOnDelete
feature, it fit well withoccurrence
editing.
- preset-occurrence: Used to specify occurrence preliminarily. Instead of using
o
in the middle of operator, user can presetoccurrence
. - persistent-selection: Used to specify target preliminarily. As like in
visual-mode
, when you specify operator, operator immediately apply mutation onpersistent-selection
range.
- occurrences is now new target, not original target range like paragraph itself.
- Instead of mutate(by
delete
,change
) whole paragraph, it mutate occurrences only. - As long as start or end point of occurrence is intersecting with target-range, vmp treats it as "target".
- This inclusive tolerance allow user to apply selected set of occurrence using
visual-mode
orpersistent-selection
very roughly.
- Operator just works on target
- Don't care if it was occurrence-reselected-target or was-normal-target
- Just mutate target-range. That's it.
Although all operator, motion, text-object is used with occurrence
and preset-occurrence
.
Following table list frequently used operator and target used with occurrence
.
The more you familiar with these target, the more you can use occurrence
naturally, fluently.
So train your finger until you can type without thinking, until you type from your muscle memory!!
Key | Command | Description |
---|---|---|
C |
change-to-last-character-of-line |
Change occurr from here to EOL |
D |
delete-line |
Delete occurr from here to EOL |
Key | Command | Description |
---|---|---|
$ |
move-to-last-character-of-line |
Same as D , But used with o modifier |
^ |
move-to-first-character-of-line |
Opposite of $ , here to HOL(Head of line) |
G |
move-to-last-line |
Here to bottom of buffer |
r |
replace |
Used with preset-occurrence and visual or persistent-selection
|
g g |
move-to-first-line |
From here to top of buffer. |
H |
move-to-top-of-screen |
From here to visible top. Top row of screen. |
L |
move-to-bottom-of-screen |
From here to visible bottom. Bottom row of screen. |
M |
move-to-middle-of-screen |
From here to visible middle. Middle row of screen. |
[ |
move-up-to-edge |
From here to upper edge |
] |
move-down-to-edge |
From here to down edge |
/ |
search |
From here to next search match. |
? |
search-backwards |
From here to previous search match. |
* |
search-current-word |
From here to next cursor-word match. |
# |
search-current-word-backwards |
From here to previous cursor-word match. |
} |
move-to-next-paragraph |
From here to next blank row. |
{ |
move-to-previous-paragraph |
From here to previous blank row. |
Key | Command | Description |
---|---|---|
i v |
inner-visible-area |
Visible screen are. Whole rows you can see in current screen view. |
a v |
a-visible-area |
Same as i v . No behavior diff. |
i e |
inner-entire |
Entire buffer. |
a e |
a-entire |
Same as a e . No behavior diff. |
i p |
inner-paragraph |
Consecutive non-blank rows. |
i i |
inner-indentation |
Consecutive non-blank and equal or deeper indent level rows. |
a i |
a-indentation |
Consecutive equal or deeper indent level rows includes blank-row. |
i f |
inner-function |
Inner function area, not include first row(where parameter comes) |
a f |
a-function |
Include whole function, better than i f to mutate occurrence
|
i l |
inner-current-line |
Current line text excluding leading and trailing spaces. |
i z |
inner-fold |
Inner fold, nearest enclosed fold are, not include first row. |
a z |
a-fold |
Same as i z but include first row. |
I'll explain basic usage of preset-occurrence
by using the following simple text.
This text have 3 instance of 'text' in the whole text
This text have 3 instance of 'text' in the whole text
- Place cursor on first "text" occurrence.
-
g o
to mark it aspreset-occurrence
. - Try with different operator with different target. by
undo
ing byu
on each try.
-
C
:change
, three 'text' occurrences on 1st line. -
d d
:delete
, three 'text' occurrences on 1st. -
D
: alsodelete
, three 'text' occurrences on 1st. -
c j
:change
, six 'text' occurrences on 1st line and 2nd line. -
d j
:delete
, six 'text' occurrences on 1st line and 2nd line.
- Move to
'text'
in the middle of 1st line. -
g o
to mark it aspreset-occurrence
. - Try with different operator with different target. by
undo
ing byu
on each try.
-
C
:change
, two 'text' occurrences appears from here to EOL on 1st line. -
c ^
:change
, two 'text' occurrences appears from here to HOL(head of line) on 1st line. -
v j d
:delete
, four 'text' occurrences with exception of first and last 'text' occurrence.
- Select
t
char invisual-mode
. -
g o
to set thatt
char as occurrence -
d j
delete allt
char from two lines.
- This feature, preset-occurrence-by-search-pattern is available only when you enabled
incrementalSearch
from setting view.
- Start incremental-search with
/
- Search
\bt\w+
which is pattern for word starting witht
character. -
cmd-o
, setpreset-occurrence
to pattern-matched text. -
d j
delete everyt
starting word from two line.
For I f
and A f
in step 3 to work, you need to enable "keymap I
and A
to insert-at-start-of-target
and insert-at-end-of-target
when editor has preset-occurrence
marker." config(from v1.4.0).
- Place cursor on to that parameter name.
- Mark that parameter name with
g o
- Do whatever from following
-
c f
orc a f
to change same parameter name appears in current-function in bulk. -
I f
orI a f
to insert start-of-each occurrence, which is useful when you want to prefix it. -
A f
orA a f
to insert start-of-each occurrence, which is useful when you want to suffix it.
When you want to consolidate some messy code which always calling similar set of method in sequence, that mean you move some code into object's method.
Let's say you want to move logic that use mutation.getPoint(xxx)
, mutation.getMarker(xxx)
in sequence to Mutation
class's method to consolidate logic.
- Copy & paste under the new method definition of
Mutation
class - Then select
mutation.
-
g o
to createpreset-occurrence
. for textmutation
. -
c f
orc a f
to change wholemutation.
occurrences in function -
this.
thenescape
. - Now all
mutation.
is now replaced tothis.getPoint(xxx)
,this.getMarker(xxx)
to work inthis
new context.
You want to remove line which include console.log
.
- Search (
/
) - Input pattern:
^.*console\.log*\n
. -
cmd-o
setpreset-occurrence
to line includeconsole.log
-
d G
delete every-console-log-line-from-here-to-end-of-buffer.
The point is 2nd step, use regex pattern to match whole line. (use ^
and \n
)
cmd-d
is mapped to find-and-replace:select-next
.
Which select next occurrences of cursor-word one by one.
cmd-k cmd-d
skips current occurrence then select next, which is good to skip one occurrence, but not good when you want skip more.
Using persistent-selection
, skipping words become very easy.
1st line text text
2nd line also include text text text.
3rd text text text
- Place cursor to first
text
in 1st line -
cmd-d
twice to select nexttext
in 1st line, but you want to skip 2nd line'stext
occurrence. - Instead of type
cmd-k cmd-d
three times, typeenter
, which convert real selection topersistent-selection
- Move to 3rd line by
2 j 0
thencmd-d
three times to select threetext
in 3rd line. - Then do whatever you want.
persistent-selection
is treated like a real selection. Operator operate onpersistent-selection
if it exists in buffer.
-
c
to changetext
excepttext
in 2nd line. -
d
to deletetext
excepttext
in 2nd line. -
g U
to upcasetext
excepttext
in 2nd line. -
s (
to to maketext
to(text)
by surround(keymap is just an example when you maps
tosurround
).