DEV Community

Cover image for I've been using vim in total a year, and I'll stick to it.
Azriz Jasni
Azriz Jasni

Posted on • Edited on

I've been using vim in total a year, and I'll stick to it.

And heres why:

  • after you learn vim, you will be less pressing ALT, CMD, CTRL, HOME.
  • you can achieve so many things with less keystrokes
  • vim also can record your commands with macros, so be sure to check it out below.

  • I'll be sharing few highlights from both of the video above that I feel its very handy. Hence, if you just started to learn how to use vim, please watch both of the video first as my examples below is suitable to someone already familiar with basics(Visual, Editing, Deleting, and Navigating).
  • However, I'll try to make this interactive as much as possible, so that anyone could get start easily. Since both of the video is quite long, I have 1 little tip on how to learn faster on my previous article.

Few notes before we start:

  • First, I've been editing this article for quite long with nested bullet points, and it doesn't really work. The numbering, indentation and some other stuff not properly align. Hence, I'll be using gist since it works fine. Also average reading will be around ~10min instead of 2min.
  • All the char is case-sensitive, and please excuse me if I'm using incorrect term/syntax 😅.
  • Please note that on below example I'll be using a lot of <cursor here> to indicate you need to move your cursor somewhere around there.
  • If you see <enter> it means you have to press enter. Same goes to <esc>.
  • Plus, if you see a formatting like this q, it means press the 'q' key in keyboard.
  • Lastly, I'm using this awesome repo for my vim config.

If you prefer to read in github gist, you can click this link. https://gist.github.com/AzrizHaziq/adcfdbf12c3b30b6523495e19f282b58#file-vim-md

Let's get started then:

https://dev.to/azrizhaziq/i-ve-been-using-vim-in-total-a-year-and-i-ll-stick-using-it-2e8k

1. Inside (ciw)

  • It's stand for change inside word.

  • You also can change w to any char like (,}.

  • Below are some other variation that you can use:

    • diw delete inside word
    • vi( visual inside bracket
    • yiw yank inside word
    • dis delete inside sentence.
    • dip delete inside paragraph.
    • ci3w change inside 3 words

    Example

    Below I have a word inside bracket, and I would like to change it to my name:

    # before
    Lorem ipsum dolor sit amet, (inven<cursor here>tore) adipisicing elit.
    
    # type: ciwazrizhaziq
    # after
    Lorem ipsum dolor sit amet, (azrizhaziq) adipisicing elit.

2. Around (caw)

  • It's stand for change around word.

  • Most of the points here is the same as point number 1.

  • For the variations of around, just change i to a:

    • daw delete around word
    • va( visual around bracket

    Examples

    1. Given below scenario you want to change around bracket to your name
    # before
    Lorem ipsum dolor sit amet, (inven<cursor here>tore) adipisicing elit.
    
    # type: ca(azrizhaziq<esc>
    # after
    Lorem ipsum dolor sit amet, azrizhaziq adipisicing elit.
    1. Change this to implicit arrow function (remove return keyword and braces)
    // before
    const average = (...numbers: number[]): number => {
      return /* <cursor here> */ numbers.reduce((acc, n) => acc + n, 0) / numbers.length
    }
    
    // type: Dva{p
    // Delete all right chars until the end, visual around {, and then paste
    // after
    const average = (...numbers: number[]): number => numbers.reduce((acc, n) => acc + n, 0) / numbers.length  

3. t, f and then followed by any char that you want to search

  • t I'm not sure what it's stand for, f is find. Both used to find a char after cursor in current line.

  • The different is t will put cursor before the search char, while f will put at the char.

  • Now that you know small case t & f does, T and K does the opposite. Both will search before cursor in current line.

    Examples

    1. below example is not properly assign to string[]
    // typescript
        // before
    /* <cursor here> */ const names: string[] = ['azriz', 'haziq', 1985, 02, 30, true]
    
    // type f1dt]X
    // find 1, and put the cursor at it, find ] but put cursor before it, and delete a left char
    // after
    const names: string[] = ['azriz', 'haziq',]
    • If you want to find the next occurrence of searched char in a line use ;
    // below you want to change GBP $ to GBP £
    // before
    /* <cursor here> */ const currencies: string[] = ['MYR RM', 'AUD $', 'CNY ¥', 'SGD $', 'GBP $', 'JPY ¥']
    
    // type: f$;;r€
    // find $, find next, find next, replace €
    // after
    const currencies: string[] = ['MYR RM', 'AUD $', 'CNY ¥', 'SGD $', 'GBP $', 'JPY ¥'] 

4. :wq to save and quit

  • Instead of hit 5 keystrokes with below command its only 3 keystroke
    • ZZ save and quit
    • ZQ discard changes and quit

5. zc close folds, zo open folds

  • Used to fold codes. If you have 1k LOC(line of code), this will be handy.
  • You can focus on which chunk of code to focus.
  • This command it's not in both video as I remember.

6. J (not in the video)

  • It join the whole line below current cursor and append to current cursor.

  • Kinda hard to put in words, let's see in action

    Example

    // before
    /* <cursor here> */ var json = {
      name: 'azriz haziq', // see this line
      dob: '30 02 1985',
      hobbies: ['smash keyboard', 'press esc key']
    }
    
    // type: J
    // after
    var json = {
      name: 'azriz haziq',
      dob: '30 02 1985',
      hobbies: ['smash keyboard', 'press esc key']
    }
    
    // type: JJJ or 3J
    // after
    var json = { name: 'azriz haziq', dob: '30 02 1985', hobbies: ['smash keyboard', 'press esc key'] }

7. Mostly if you use with SHIFTchar, it will perform an action to before

  • I had a hard time at first how to differentiate certain key action. Some perform at before and sometime at after.
  • So how I remember it usually, capital char will perform action before current cursor/char/line.
  • O will add a new line before current line, while o will add new line after current line.
  • I will move the cursor at beginning of current line, while i will change to insert mode and put the cursor before char.
  • Same goes to P paste before a char, p paste after char.
  • After you search a term, and then you can hit N to find previous, n and find after.
  • But not all the case is like this, G, A, C, D perform differently.

8. Macros

  • Killer feature in vim.

  • Records all your keystrokes, and then you can replay the keystroke later.

  • AFAIK(as far as I know), you can't do this in any normal GUI editor like VS Code, Webstorm, notepad++, etc.

  • Macros only uses 2 keys which is q, and @.

  • The sequence to start macro is like this: qd...q.

    • first q is to start recording, while the last q is stop recording.
    • d save macro into 'd'. You can save this to any char.
    • ... stand for any command you want to record.
    • To run the macro that you just save in d, press it with @d.

    Examples

    1. Let's start with first example:

      • Below is CSP response header from twitter.com

      • It's quite hard to read since it is a one line of string

      • So let chunk it up with macro.

        # before
        <cursor here> connect-src 'self' blob: https://*.giphy.com https://*.pscp.tv https://*.video.pscp.tv https://*.twimg.com https://api.twitter.com https://api-stream.twitter.com https://ads-api.twitter.com https://aa.twitter.com https://caps.twitter.com https://media.riffsy.com https://pay.twitter.com https://sentry.io https://ton.twitter.com https://twitter.com https://upload.twitter.com https://www.google-analytics.com https://app.link https://api2.branch.io https://bnc.lt wss://*.pscp.tv https://vmap.snappytv.com https://vmapstage.snappytv.com https://vmaprel.snappytv.com https://vmap.grabyo.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net ; default-src 'self'; form-action 'self' https://twitter.com https://*.twitter.com; font-src 'self' https://*.twimg.com; frame-src 'self' https://twitter.com https://mobile.twitter.com https://pay.twitter.com https://cards-frame.twitter.com  https://accounts.google.com/; img-src 'self' blob: data: https://*.cdn.twitter.com https://ton.twitter.com https://*.twimg.com https://analytics.twitter.com https://cm.g.doubleclick.net https://www.google-analytics.com https://www.periscope.tv https://www.pscp.tv https://media.riffsy.com https://*.giphy.com https://*.pscp.tv https://*.periscope.tv https://prod-periscope-profile.s3-us-west-2.amazonaws.com https://platform-lookaside.fbsbx.com https://scontent.xx.fbcdn.net https://scontent-sea1-1.xx.fbcdn.net https://*.googleusercontent.com; manifest-src 'self'; media-src 'self' blob: https://twitter.com https://*.twimg.com https://*.vine.co https://*.pscp.tv https://*.video.pscp.tv https://*.giphy.com https://media.riffsy.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net; object-src 'none'; script-src 'self' 'unsafe-inline' https://*.twimg.com   https://www.google-analytics.com https://twitter.com https://app.link https://apis.google.com/js/platform.js https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js  'nonce-YmY0NTUzYjUtODYyYy00OGI0LTliZjctOTU4MDYxY2JkMjA2'; style-src 'self' 'unsafe-inline' https://*.twimg.com; worker-src 'self' blob:; report-uri https://twitter.com/i/csp_report?a=O5RXE===&ro=false
        
        # type below
        # qd                # start record and save to d
        # f;a<enter><esc>   # find ;, enter insert mode, enter and escape
        # q                 # stop recording
        # @d                # run once the record command
        # @@                # run previous macros command
        # 5@d               # run command 5 time
        connect-src 'self' blob: https://*.giphy.com https://*.pscp.tv https://*.video.pscp.tv https://*.twimg.com https://api.twitter.com https://api-stream.twitter.com https://ads-api.twitter.com https://aa.twitter.com https://caps.twitter.com https://media.riffsy.com https://pay.twitter.com https://sentry.io https://ton.twitter.com https://twitter.com https://upload.twitter.com https://www.google-analytics.com https://app.link https://api2.branch.io https://bnc.lt wss://*.pscp.tv https://vmap.snappytv.com https://vmapstage.snappytv.com https://vmaprel.snappytv.com https://vmap.grabyo.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net ;
        default-src 'self';
        form-action 'self' https://twitter.com https://*.twitter.com;
        font-src 'self' https://*.twimg.com;
        frame-src 'self' https://twitter.com https://mobile.twitter.com https://pay.twitter.com https://cards-frame.twitter.com  https://accounts.google.com/;
        img-src 'self' blob: data: https://*.cdn.twitter.com https://ton.twitter.com https://*.twimg.com https://analytics.twitter.com https://cm.g.doubleclick.net https://www.google-analytics.com https://www.periscope.tv https://www.pscp.tv https://media.riffsy.com https://*.giphy.com https://*.pscp.tv https://*.periscope.tv https://prod-periscope-profile.s3-us-west-2.amazonaws.com https://platform-lookaside.fbsbx.com https://scontent.xx.fbcdn.net https://scontent-sea1-1.xx.fbcdn.net https://*.googleusercontent.com;
        manifest-src 'self';
        media-src 'self' blob: https://twitter.com https://*.twimg.com https://*.vine.co https://*.pscp.tv https://*.video.pscp.tv https://*.giphy.com https://media.riffsy.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net;
        object-src 'none';
        script-src 'self' 'unsafe-inline' https://*.twimg.com   https://www.google-analytics.com https://twitter.com https://app.link https://apis.google.com/js/platform.js https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js  'nonce-YmY0NTUzYjUtODYyYy00OGI0LTliZjctOTU4MDYxY2JkMjA2';
        style-src 'self' 'unsafe-inline' https://*.twimg.com;
        worker-src 'self' blob:;
        report-uri https://twitter.com/i/csp_report?a=O5RXE===&ro=false
      • This example its pretty easy and can be done with normal IDE, just search everything ;, move 1 right and then hit enter, it will have the same result as above.

    2. Next, an example that is hard to achieve with normal editor.

      • So I have a pretty html here, and I want to change this to correct <table> markup.

      • Based on the snippet below, you can see children of <li> does not have proper structure. Sometime, the children is in same lime with <li>, and its also have multiline nested children.

        <!-- before -->
        <!-- <cursor-here> -->
        <ul>
          <li data-testId="1" class="abc"><span><svg /></span></li>
          <li data-testId="2" class="def">
            <p><small>1 + 2 = 3</small><b>3</b></p>
          </li>
          <li data-testId="3" class="qwe">
            <div>
              <button type="submit">
                <span>Click me</span>
              </button>
            </div>
          </li>
          <li data-testId="4" class="zxc"><!-- this is empty --></li>
          <li data-testId="5" class="asd">🧑‍💻❤️🐈</li>
        </ul>
      • So what we are going to do is, change <li> to <tr>, and <tr> children will have ${class}-${testId}

        <!-- before -->
        <li data-testId="1" class="abc"><span><svg /></span></li>
        
        <!-- after -->
        <tr data-testId="1" class="abc">abc-1</tr>
      • I believe if we are going to do with normal editor it will take a lot of time. You will be spending hitting CTRL /CMD/SHIFT/Arrow-right/Arrow-left a lot.

      • Bear with me as this is going to be very long steps.

        <!-- type: <esc> is escape key, <enter> is enter key
        qq                     # start recording
        /data<enter>           # search data
        dit                    # delete inside tag, I just knew this!!
        0w                     # put cursor at starting line
        fd                     # find d
        dt>                    # delete up until before >, d also save into clipboard     
        O                      # create new line above       
        <tr <esc>pa></tr><esc> # please make after you type this line the result will be <tr data-testId="1" class="abc"></td>
        0w                     # put cursor at starting line              
        fcf"lywf>p             # find c, find ", move 1 right, yank a word, find >, and paste
        0w                     # put cursor at starting line             
        f"lywt<a-<esc>p        # find ", move 1 right, yank a word, find a put cursor before <, paste
        jdd                    # go down, delete whole line
        q                      # stop recording
        -->
        <!-- after running above commands -->
        <ul>
          <tr data-testId="1" class="abc">abc-1</tr>   <!-- notice this line changed -->
          <li data-testId="2" class="def">
            <p><small>1 + 2 = 3</small><b>3</b></p>
          </li>
          <li data-testId="3" class="qwe">
            <div>
              <button type="submit">
                <span>Click me</span>
              </button>
            </div>
          </li>
          <li data-testId="4" class="zxc"><!-- this is empty --></li>
          <li data-testId="5" class="asd">🧑‍💻❤️🐈</li>
        </ul>
         <!-- since we save the macro to q, then we can type below -->
        <!-- type: @q -->
        <ul>
          <tr data-testId="1" class="abc">abc-1</tr>  <!-- notice this line changed -->
          <tr data-testId="2" class="def">def-2</tr>  <!-- notice this line changed -->
          <li data-testId="3" class="qwe">
            <div>
              <button type="submit">
                <span>Click me</span>
              </button>
            </div>
          </li>
          <li data-testId="4" class="zxc"><!-- this is empty --></li>
          <li data-testId="5" class="asd">🧑‍💻❤️🐈</li>
        </ul>
      • If you manage to reach here, Congratulation 🎉🎉.

      • Actually, we can shortcut few steps above with substitution :%s/tr/li/g<enter>, but I'll leave this for you to discover yourself.

9. Rerun previous command with .

  • This is a continuation from point 8.

  • please make sure your last command is @q

  • please note that this is no limited to macros only, you can literally use this . with any kind of command.

    <!-- type: .... -->
    <ul>
      <tr data-testId="1" class="abc">abc-1</tr>
      <tr data-testId="2" class="def">def-2</tr>
      <tr data-testId="3" class="qwe">qwe-3</tr>
      <tr data-testId="4" class="zxc">zxc-4</tr>
      <tr data-testId="5" class="asd">asd-5</tr>
    </ul>
  • Lastly, as you can see it's not a correct html <table> markup. Hence, please feel free to change it by putting children of <tr> to have <td>, and change <ul> to <table>.

10. :help <char/word>

  • last but not least, vim have its own massive docs. Just try to find any keyword that you want to know more.
    • :help del
    • :help v_it search visual inside tag:
  1. Bonus tips
  • In 1st and 2nd point, we learned inside and around.
  • There is another vim plugin which is to handle surround.
  • They have comprehensive examples on their readme, do check it out https://github.com/tpope/vim-surround.
view raw vim.md hosted with ❤ by GitHub
  • Now that you have learn few things here, why not give it a try first? You might have same hobbies like mine (search above 🤣).
  • Please, don't try to remember all the keys, since vim already have a good mnemonics.
  • However, there is a lot of things that I didn't mention in both of the videos. Hence, I strongly suggest you to watch it. - I hope my example is easy to understand. Let me know if the example is not clear enough for you/typos or anything in comment. Thank you for reading.

Top comments (0)