Skip to content

AdvancedTopicTutorial

t9md edited this page Jul 10, 2017 · 59 revisions

High speed tour from beginner to expert in 7 steps

To attract your attention, I'll first try to lift up your Vim level with only 7 steps!

  1. You know visual-mode
  2. Use TextObject
  3. Use better Operator
  4. Combine opertor with text-object
  5. Modify operator's behavior by o to make it operate on occurrence
  6. Use preset-occurrence
  7. Use persistent-selection

0. Text to use in this tour

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

1. You know visual-mode

You want to replace 1st whole paragraph to abc.
You select text of paragraph using visual-mode.

  1. v j j $ or V j j
  2. d to delete selected text
  3. i to start insert-mode.
  4. Type abc then escape.

DONE. well done.

2. Use TextObject

You can do it better by using TextObject
You can select whole paragraph by i p(inner-paragraph).

  1. v i p
  2. d to delete selected text
  3. i to start insert-mode.
  4. Type abc then escape.

DONE. much better.

3. Use better Operator

You can do it better by using Operator
Instead of delete text then start insert-mode by i, you can do it both at once by change operator.

  1. v i p
  2. c to change text. Whole paragraph was deleted and you are now in insert-mode.
  3. Type abc then escape.

DONE. much much better.

4. Combine operator with text-object

You can do it better by not using visual-mode

What's the benefit?
You don't have to type v or V to start visual-mode, saved one keystroke.
You edit more declaratively than imperatively.
Instead of saying "select then mutate this selection", you can say "mutate this target".
The more you get familiar with this flow(operator first then target), the less you use visual-mode.
One bonus, by telling operator first, your operation become repeatable by ..
By repeating you can apply same editing transaction to different place(different paragraph in this example).

  1. c i p to change inner-paragraph. Operator first, then target(TextObject).
  2. Type abc then escape.

DONE. Wow, the number of keystrokes reduced drastically!
And you can now apply same edit to next paragaph, move cursor to next paragraph then try . to repeat!

5. Modify operator's behavior by o to make it operate on occurrence

New requirement.
Instead of changing the whole paragraph to abc, you want to replace text appears in 1st pargraph to abc Here o operator-modifier comes in play!

  1. Move cursor to text in 1st paragraph.
  2. c o i p, or c o p.
  3. Type abc then escape

DONE. What happened?
The o is operator-modifier, which modify operator's behavior.
The effect of o is it re-selects the keyword under-cursor from target area(1st paragraph in this case) under the hood.
When you use operator with occurrence, it's easier to understand by thinking in the following way.
Instead of saying "Do this operation on this target", you can say "Apply this operator to this target".
In this example case "Apply change operator to this paragraph" instead of saying "Change this paragraph" When occurrence is involved, the sentence become "Apply change operator to occurrences in this paragraph"

And off course you can repeat the same edit-unit on 2nd paragraph, confirm it by . on 2nd paragraph.

6. Use preset-occurrence

New requirement.
You also want to change text and line keyword in 1st paragraph to abc.
Now you have to replace two keyword.
You can do it by using preset-occurrence.
Instead of typing o in the middle of operation, you can pre-set occurrence by g o.

  1. Move cursor to text in 1st paragraph.
  2. g o to preset-occurrence for text keywrod.
  3. Move to 2nd line line keywrod then g o.
  4. c i p or c p
  5. Type abc then escape

DONE. Since you pre-set the occurrence keyword, your operator is applied to the text and the line keywords. The benefit is that you can choose the operator after you have already decided the occurrence keyword.

7. Use persistent-selection

New requirement.
You want to replace line and text in the 1st and 2nd paragraphs.
But you want to exclude 2nd line of 2nd paragraph, so you can not use . repeat power!!
In this case, persistent-selection helps you.

  1. Create preset-occurrence for text and line keyword by g o.
  2. v i p to select the 1st paragraph then j j to extend selection to 1st line of 2nd paragraph.
  3. enter. The real selection becomes a persistent-selection
  4. j j to move to the 3rd line of the 2nd paragraph
  5. V j to select 3rd and 4th line of paragraph-2
  6. c to change preset-occurrence keyword within selection (which includes persistent-selection).
  7. Type abc.

DONE. Well DONE.
You're now a super Vimmer!!

  • The Operator is verb of operation.
  • The TextObject is object of operation.
  • Operation is sentence in text editing in Vim.

Do practice with different verb (Operator) and different object (Motion or TextObject)!!
Train your finger, muscle memory until you can type without thinking, until you can transform text with minimum keystroke!!.

To compliment your understanding, I strongly recommend you to read operator, the true power of Vim by kana.

8. Extra complex operation

Mission

  • 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 to SearchBackwards.
  • 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 to DashCase form.
    • Finally sort all lines. and remove blank lines. `

Text before transform

'`': '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'

Text after transform

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.
  1. Start incremental-search by /.
  2. Input .*plus: in the search field, confirm highlight (this is the target you will change).
  3. ctrl-cmd-c (change-occurrence-from-search which change matches of search), enter operator-pending mode, so you have to tell a target of operator.
  4. i e (inner-entire), to specify whole buffer as a target.
  5. You are now in insert-mode with multiple-cursors on each line. ctrl-e to move to EOL then ctrl-h to remove trailing single quotes '.
  6. escape to return to normal-mode. You have still multiple cursors.
  7. ctrl-s ( transform-string-by-select-list ) then select Pascalize and confirm by enter, then i W ( inner-whole-word ). A dash-case were transformed to a DashCase.
  8. g g to move to top of buffer. g s G. to sort (g s) from here-to-bottom-of-buffer (G).
  9. 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!!

Core concept of Vim: Two important role in editing.

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

Operator demands target to specify on which area the operator operates

  • 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 is target-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.g D is pre-targeted with $ motion. so D is short hand for d $.
  • 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.

What is a target?

  • A target is a range of text determined by Motion or TextObject.
  • TextObject defines target range (start and end 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 as start; 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 in visual-mode, it immediately mutate current-selection, In other words all operators used in visual-mode are pre-targeted (preset-target) to current-selection.

Operator modifier

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 to characterwise range.
  • V: Force target range to linewise range.
  • o: Reselect occurrences of keyword within target range before applying operator.

example

# 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 parapgraph.
c o i p
  ^ o modifier pick cursor-word as occurrence, re-select it appearing in paragraph.

For o modifier, OccurrenceModifier

Advanced concept

Before starting explanation, here are some fancy GIFs to motivate you to learn these new way of editing.

Basic usage of preset-occurrence

Delete debug print console.log line in bulk.

Bulk delete text with arbitrary boundary using visual-mode.

Using persistent-selection to pre-specify operator's target

persistent-selection

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 to create-persistent-selection.
  • If you map c s to change-surround, I recommend you to change it, also change other keymaps starting with c. Otherwise, you have to wait timeout after typing c 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.

Common use case

  • Work on multiple target without using mouse: set multiple target by persistent-selection then mutate.
  • Narrow target range to include particular set of occurrence.

preset-occurrence

From v0.58.0.

  • Allow user to set occurrence BEFORE operator.
  • Keymap: In normal, visual, g o to toggle-preset-occurrence.
    • It add/remove preset-occurrence at cursor position.
    • When removing, it remove one by one, not all.
  • Keymap: In incsearch input, cmd-o to add-occurrence-pattern-from-search
    • It add preset-occurrence by search-pattern.
  • Following two operation do the same thing, but former is operator-modifier, later is preset-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 with occurrence editing.

preset-occurrence? vs persistent-selection?

  • preset-occurrence: Used to specify occurrence preliminarily. Instead of using o in the middle of operator, user can preset occurrence.
  • persistent-selection: Used to specify target preliminarrily. As like in visual-mode, when you specify opearator, operator immediately apply mutation on persistent-selection range.

When occurrence is exists, target is re-selected before applying operator to target.

  • occurrences is now new target, not original target range like paragpraph itself.
  • Instead of mutate(by delete, change) whole paragraph, it mutate occurrences only.
  • As long as start or end pointion of occurrence is intersecting with target-range, vmp treat it as "target".
  • This inclusive tolerance allow user to apply selected set of occurrence using visual-mode or persistent-selection very roughly.

Operator just operate on target

  • 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.

Useful operator and target(Motion, TextObject) used with ocurrence.

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, untill you type from your muscle memory!!

Operator

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

Motion

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.

TextObject

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.

Exercise

Basic

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

Use with motion.

  1. Place cursor on first "text" occurrence.
  2. g o to mark it as preset-occurrence.
  3. Try with different operator with different target. by undo ing by u on each try.
  • C: change, three 'text' occurrences on 1st line.
  • d d: delete, three 'text' occurrences on 1st.
  • D: also delete, 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.

  1. Move to 'text' in the middle of 1st line.
  2. g o to mark it as preset-occurrence.
  3. Try with different operator with different target. by undo ing by u 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.

Preset occurrence from visual area

  1. Select t char in visual-mode.
  2. g o to set that t char as occurrence
  3. d j delete all t char from two lines.

Preset occurrence by pattern match using /.

  • This feature, preset-occurrence-by-search-pattern is available only when you enabled incrementalSearch from setting view.

  1. Start incremental-search with /
  2. Search \bt\w+ which is pattern for word starting with t character.
  3. cmd-o, set preset-occurrence to pattern-matched text.
  4. d j delete every t starting word from two line.

Practical

Rename function parameters in bulk in refactoring,

  1. Place cursor on to that parameter name.
  2. Mark that parameter name with g o
  3. Do whatever from following
  • c f or c a f to change same parameter name appears in current-function in bulk.
  • I f or I a f to insert start-of-each occurrence, which is useful when you want to prefix it.
  • A f or A a f to insert start-of-each occurrence, which is useful when you want to suffix it.

Change the explicit receiver to this in bulk when moving some set of logic into one method.

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.

  1. Copy & paste under the new method definition of Mutation class
  2. Then select mutation.
  3. g o to create preset-occurrence. for text mutation.
  4. c f or c a f to change whole mutation. occurrences in function
  5. this. then escape.
  6. Now all mutation. is now replaced to this.getPoint(xxx), this.getMarker(xxx) to work in this new context.

Remove whole line.

You want to remove line which include console.log.

  1. Search (/)
  2. Input pattern: ^.*console\.log*\n.
  3. cmd-o set preset-occurrence to line include console.log
  4. 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)

Work with default cmd-d: Skipping become easy with persistent-selection

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
  1. Place cursor to first text in 1st line
  2. cmd-d twice to select next text in 1st line, but you want to skip 2nd line's text occurrence.
  3. Instead of type cmd-k cmd-d three times, type enter, which convert real selection to persistent-selection
  4. Move to 3rd line by 2 j 0 then cmd-d three times to select three text in 3rd line.
  5. Then do whatever you want. persistent-selection is treated like a real selection. Operator operate on persistent-selection if it exists in buffer.
  • c to change text except text in 2nd line.
  • d to delete text except text in 2nd line.
  • g U to upcase text except text in 2nd line.
  • s ( to to make text to (text) by surround(keymap is just an example when you map s to surround).
Clone this wiki locally