Vim Workflow (Part Deux)

Introduction

If you've not read over my two previous Vim posts (A guide to getting started with Vim and Vim Workflow) then I suggest you do that first as that'll give you an idea of how I use Vim and what my previous workflow was like.

I've decided that it was time to simplify my Vim set-up and to better automate and understand some processes.

Note: not all of this was related to just Vim but my general dotfiles set-up as well.

Hopefully by sharing my updated workflow you might pick up some techniques that you like and want to utilise yourself (or maybe not).

No more tmux

I love tmux but for all its power I pretty much only ever used it for spliting the screen into panes (or Windows if you're talking Vim terminology).

The one really cool feature of a pane in tmux was the fact that it could just be pointed at a terminal shell (so I could run shell commands without affecting my current Vim window).

So why would I give that up? What am I using now?

Well, I'm just using Vim's standard windows feature! So let me explain how I use Vim windows...

Update: just to be clear that I do still use tmux but only when I'm doing TDD or refactoring with tests. That is the one instance where I'll fire up two tmux panes (one to hold Vim and the other to be a terminal running my tests -> this makes the 'red, green, refactor' feedback loop nice and tight).

Vim windows

When I create a new window in Vim (same as a tmux pane), the new window holds a copy of the current file. I then just use the Ctrl-p plugin to open another file (see the below section on plugins if you're not sure what Ctrl-p is).

If I want to run a command I will typically push Vim into the background and run the command, simple (it doesn't need to be more complicated than that).

To do this you press Ctrl-z which will take you out of Vim and back into the shell where you can run your commands. You then press fg to bring Vim back to be the (f)ore (ground) process.

Long running commands

If you have a long running command (e.g. grunt watch) then this is where the tmux pane would be really handy, because I could open a new pane and leave it running alongside working in Vim. This isn't possible in Vim, but the solution is just as easy: open a new tab!

If you have a long running command such as a grunt task which watches files and then compiles them when they are updated, then you're not going to really be interested in looking at that output (well, majority of the time you're not). So just have it run in a separate tab and you can easily switch back over to it to see the output if you want. You can then just easily switch back to the Vim tab when you're ready.

Is this a perfect solution? Of course not.
Does it mean I can drop a dependency? Absolutely.

If I can make life simpler (within reason) then I think that's a better situation to be in.

UPDATE:

As pointed out by @kenturamon, he uses Guard to run his Ruby tests and for proper TDD (test-driven development) he needs a constant feedback loop rather than switching tabs all the time. In situations like that then using tmux is the best bet. You don't have to use tmux all the time but I have no issue with using the best tool for the job when the circumstances dictate it.

Managing windows

The default keys for moving around and manipulating Vim's windows are a bit ugly and awkward to use.

I find that I use the <leader> key \ all the time. It's in the perfect spot for my fingers to hit it whenever I need it. So I map a few of the window keys to use the leader key instead...

" Make handling Vim windows easier
map <leader>w- <C-W>- " smaller
map <leader>w+ <C-W>+ " larger
map <leader>w[ <C-W>= " equal
map <leader>w] <C-W>_ " fill screen

" Make splitting Vim windows easier
map <leader>; <C-W>s
map <leader>` <C-W>v

...as you can see, if I want to create a horizontal split window then I just press: \; and if I want the vertical equivalent I just press: \`

If I want the current window to fill the screen I press: \w] and if I want all windows to be equal size again then I press: \w[.

Finally if I want the current window to be slightly larger, then I press: \w+ or \w- if I want it slightly smaller.

If you have lots of split windows open and you want to close them all then :q wont work that well as it means you'll have to close each window individually. Instead run :only to close all windows except the current one and then run :q to close the last one.

If you split the current screen into too many windows you may find the full screen feature is no longer very effective (because there are so many split screens, the current window doesn't have much space left over to fill up), then you can instead move that window out into a separate Tab by executing Ctrl-w followed by Shift-T.

But be aware of two things:

  1. this moves the split window completely into a new tab (so doesn't stay as a split window as well)
  2. this is rarely needed for me any way (I hardly have more than 4 files open at once, if I do I'm clearly doing too much)

So there you have it. Nice, simple and quick solutions which mean I don't require the full range of tmux features.

This gives me the majority of the functionality I need when dealing with files.

Tabs

Vim's tab feature is something I very rarely use but like I say, if you're using Vim's window features like I am, and once in a while when you do find full screening a window pane isn't working out, then extracting that window out into a tab is the only way to go (in tmux you can just press Ctrl-z and that would properly full screen the current pane - but not using tmux any more isn't really much of an issue for me nowadays and so I can live with the standard full screen feature available to Vim windows).

In case you're wondering you can create a new tab with the command :tabnew and you can move between tabs using gt which moves forward through your tab list and gT to move backwards through the tab list.

You can also close all tab instances except the current one using :tabo (as a shortcut for :tabonly).

To move to a specific tab then just use ngt where n is the number of the tab you want to switch to. So for example if you have four tabs open then 4gt will switch you to the fourth tab.

Finally you can rearrange tabs if you want to. I'm not sure why I'm going into so much detail about tabs when it's very rare that I use them, but because they do crop up every once in a while it's nice to know what's possible (i.e. the better you understand your craft and your tool of choice the more efficient you can be). To move a tab simply execute :tabmove n where n is the space you want it to occupy. If you don't specify a number then the tab will be moved to the end of the tab list. But be aware that the tab list is zero-indexed so moving to the first space would be :tabmove 0.

Plugins

So there are quite a few plugins I use, some of the most vital ones I'll list below:

I'll discuss just a couple of them in more detail...

Ctrl-p

Opening multiple files

Although Ctrl-p is execellent for fuzzy searching for a particular file and opening it really quickly, most people don't take advantage of all its features such as the ability to open multiple files at once.

When you open Ctrl-p (I have it mapped to \t for quicker access) you can press Ctrl-z multiple times for each file you want to open and then press either Ctrl-x to open them in horizontal split window panes, or Ctrl-o to open them in vertical split window panes.

Refreshing the list of files

This is a simple tip but I'm sure some people aren't aware that when you add a new file whilst Vim is still open then Ctrl-p would have cached the intial set of files in that directory (and sub directories) and so it wont have any new files created within its cache.

To refresh the cache simply press the F5 key when Ctrl-p is open.

Ack

I wont go into the details of how to use Ack as I've covered this in a previous Vim post (so go read that instead). I will say that being able to carry out global searches is incredibly useful and something I do on a regular basis and so if you're not taking advantage of vimgrep, Ack or Ag or whatever search tool then you're missing a trick.

NERDTree

Again, I've covered NERDTree in a previous post so if you're after the basics then go read that first.

Bookmarks

There are some useful things you can do with NERDTree outside of simple file system viewing and one of those is "Bookmarks".

When your cursor is on a particular directory or file then enter the command :bookmark my_bookmark_name.

Next time you open NERDTree you can press B to show your bookmarks and then hit enter on my_bookmark_name and it'll take you directly to the bookmarked directory/file.

Modifying files and folders

Press m to bring up a menu that lets you add, edit or delete the currently highlighted file or folder. Just follow the instructions on the screen.

Easy toggling

I've mapped \' to the command :NERDTreeToggle<cr> so it is a lot quicker and easier to toggle the NERDTree open and closed.

Searching

If you have a very long list of directories which you have to scroll through, then because NERDTree is essentially just another Vim window you can use the / search feature to quickly skip ahead to the item you're interested in.

Surround

This is an awesome plugin that does one thing and does it well. It allows you to quickly change the surrounding tabs or quotation marks of a selection or word.

The basic command is cs followed by either t for tag or " or ' or whatever the surround syntax is.

So for example, to change <p>text</p> to <div>test</div> just run cst<div>.

If you have "test" and you want 'test' instead then just run cs"'.

You can also delete the delimiters (surrounding syntax) using d instead of c.

So for example, if you have "test" and you want to remove the quotations then just use ds".

You can also add syntax to a word that doesn't have it by doing ysiw followed by the punctuation you want to surround the word with (e.g. ysiw] to have square brackets around the word).

Note: when adding surrounding syntax be aware that the right side bracket is what you should use if you want no space, and the left side bracket if you want a space included. For example, if you wanted [ abc ] then run ysiw[. But if you want [abc] then use ysiw] instead.

The standard syntax for adding surrounding syntax is ys followed by your selection command (e.g. this could be $ to select to the end of the line) followed by the punctuation you want to use or iw to select the current word.

You can also visually select a piece of text and then use Shift-S followed by the punctuation you want to insert.

Configuration

For the full configuration set-up have a look at my "Fresh Install" repo. Below are just a few different vim settings (most are outright stolen from my colleague Simon Thulbourn so do take a look at his dotfile set-up).

Settings

" switch syntax highlighting on, when the terminal has colors
syntax on

" use vim, not vi api
set nocompatible

" no backup files
set nobackup

" no write backup
set nowritebackup

" no swap file
set noswapfile

" command history
set history=100

" always show cursor
set ruler

" show incomplete commands
set showcmd

" incremental searching
set incsearch

" highlight search
set hlsearch

" ignore case in search
set smartcase

" make sure any searches /searchPhrase doesn't need the \c escape character
set ignorecase

" a buffer is marked as ‘hidden’ if it has unsaved changes, and it is not
currently loaded in a window
" if you try and quit Vim while there are hidden buffers, you will raise an
error:
" E162: No write since last change for buffer “a.txt”
set hidden

" disable folding because it is evil
set nofoldenable

" turn word wrap off
set nowrap

" scroll with more context
set scrolloff=10

" allow backspace to delete end of line, indent and start of line characters
set backspace=indent,eol,start

" convert tabs to spaces
set expandtab

" set tab size
set tabstop=4

" the number of spaces inserted for a tab
set shiftwidth=4

" turn on line numbers
set number

" highlight tailing whitespace
set list listchars=tab:\ \ ,trail:·

" get rid of the delay when pressing O (for example)
" http://stackoverflow.com/questions/2158516/vim-delay-before-o-opens-a-new-line
set timeout timeoutlen=1000 ttimeoutlen=100

" always show status bar
set laststatus=2

" set the status line to something useful
set statusline=%f\ %=L:%l/%L\ %c\ (%p%%)

" hide the toolbar
set guioptions-=T

" utf encoding
set encoding=utf-8

" autoload files that have changed outside of vim
set autoread

" use system clipboard
"
http://stackoverflow.com/questions/8134647/copy-and-paste-in-vim-via-keyboard-between-different-mac-terminals
set clipboard+=unnamed

" don't show intro
set shortmess+=I

" better splits
set splitbelow
set splitright

File types

" turn indentation on
filetype indent on

" enable filetype plugins
filetype plugin on

Commands

" jump to last cursor
autocmd BufReadPost *
  \ if line("'\"") > 0 && line("'\"") <= line("$") |
  \   exe "normal g`\"" |
  \ endif

fun! StripTrailingWhitespace()
    " don't strip on these filetypes
    if &ft =~ 'markdown'
        return
    endif
    %s/\s\+$//e
endfun
autocmd BufWritePre * call StripTrailingWhitespace()

" file formats
autocmd Filetype gitcommit setlocal spell textwidth=72
autocmd Filetype markdown setlocal textwidth=80
autocmd FileType cucumber,ruby,yaml setl sw=2 sts=2 et

" specify syntax highlighting for specific files
au Bufread,BufNewFile *.spv set filetype=php
au Bufread,BufNewFile *.md set filetype=markdown " Vim interprets .md as
'modula2' otherwise, see :set filetype?

Plugins

" Declare bundles are handled via Vundle
set rtp+=$HOME/.vim/bundle/vundle
call vundle#rc()

" Let Vundle manage Vundle
Bundle 'gmarik/vundle'

" CtrlP
Bundle 'kien/ctrlp.vim'
map <leader>t <C-p>
map <leader>y :CtrlPBuffer<cr>
let g:ctrlp_show_hidden=1
let g:ctrlp_working_path_mode=0
let g:ctrlp_max_height=30
set wildignore+=*/.git/*,*/.hg/*,*/.svn/*.,*/.DS_Store

" Tomorrow Night Theme
Bundle 'jlangston/tomorrow-night-vim'
:silent! :colorscheme tomorrow-night-bright

" Markdown
Bundle 'tpope/vim-markdown'

" Markdown (allow piping of markdown files to the browser)
au BufEnter,BufNew *.md map <enter> :wa\|!rbfu rdiscount % \| bcat<cr>

" Cucumber
Bundle 'tpope/vim-cucumber'

" Tags
" First run `ctags -R` within the root directory (this is installed via
Homebrew)
" Second within your file, on a method/class/object (whatever) press `Ctrl+]`
Bundle 'xolox/vim-misc'
Bundle 'majutsushi/tagbar'
let g:tagbar_ctags_bin='/usr/local/bin/ctags'

" Tags
" Open Tagbar when pressing <leader>b
" And automatically close it after selecting something
:map <leader>b :TagbarOpenAutoClose<cr>

" Tab completion
Bundle 'ervandew/supertab'

" Enable repeating supported plugin maps with '.'
Bundle 'tpope/vim-repeat'

" Comment out stuff
Bundle 'tpope/vim-commentary.git'

" Ack (uses Ag behind the scenes)
Bundle 'mileszs/ack.vim'
let g:ackprg = 'ag --nogroup --nocolor --column'

" Applies `end` keyword to relevant lines of ruby code
Bundle 'tpope/vim-endwise'

" Status line design improvements
Bundle 'Lokaltog/powerline'
set rtp+=~/.vim/bundle/powerline/powerline/bindings/vim

" Gists
Bundle 'mattn/webapi-vim'
Bundle 'vim-scripts/Gist.vim'
Bundle 'tpope/vim-fugitive'

" Gists (Github settings)
let g:github_user = $GITHUB_USER
let g:github_token = $GITHUB_TOKEN

" HTML generation (in NORMAL mode Ctrl+y then , <C-y,>)
Bundle 'mattn/emmet-vim'

" Rename variables and files in your code
Bundle 'vim-scripts/rename.vim'

" tmux switcher
"
http://robots.thoughtbot.com/post/53022241323/seamlessly-navigate-vim-and-tmux-splits
Bundle 'christoomey/vim-tmux-navigator'

" Git gutter
Bundle 'airblade/vim-gitgutter'
let g:gitgutter_enabled = 1
let g:gitgutter_eager = 0
let g:gitgutter_sign_column_always = 1
highlight clear SignColumn

" File System
Bundle 'vim-scripts/The-NERD-tree'
map <leader>' :NERDTreeToggle<cr>

" Snippets
Bundle 'MarcWeber/vim-addon-mw-utils'
Bundle 'tomtom/tlib_vim'
Bundle 'garbas/vim-snipmate'

" SCSS, Sass & Haml Syntax Support
Bundle 'tpope/vim-haml'

" Surround text with HTML or punctuation
Bundle 'tpope/vim-surround'

" HTML5 syntax
Bundle 'othree/html5.vim'

" Tabularize
Bundle 'godlygeek/tabular'
map <Leader>e :Tabularize /=<cr>
map <Leader>c :Tabularize /:<cr>

" JS Hint
Bundle 'Shutnik/jshint2.vim'

Useful Vim features/commands

Part of my Vim workflow is to use Vim as efficiently as possible. To try and take advantage of all the things it does well (such as short key commands to help make mundane tasks quicker and easier) and to find solutions to problems that Vim might not handle so well.

Here follows are some such tips and tricks...

Search and Replace across multiple files

Surprisingly this is quite a difficult task to achieve and is one of Vim's greatest failings.

There are two ways this can be done, and neither is perfect.

You've got the Vim way and the Unix way.

The Vim Way

There are a couple of potential work-arounds in Vim. One way is to use either multiple files already open (so multiple buffers are open) or multiple files specified as arguments when opening Vim.

This relies on either the bufdo or argdo command (depending on whether you're going to use buffers or arguments)..

bufdo executes a command for all buffers open, and argdo does the same for files specified via arguments when opening Vim.

There is also windo if you have multiple windows open.

The command to run would be (I'm going to use bufdo as I almost never open Vim with files specified via arguments, I always use Ctrl-p to open files):

:bufdo %s/search/replace/ge | update

...the trick is the e flag which tells Vim to ignore any errors (which could occur if a file you're searching doesn't find a match).

The first half of the command tells Vim to do the search and replace and updates the buffers, but we don't write to the buffer! That's why we then pipe over to the update command to write to the files (this only writes to the file if it has been modified).

If you want to use the argument list but not have to pass all those names as arguments when opening Vim then you can just use :args *.txt to add all txt files to the argument list (note: doing this will open each of those files, again one of the downsides of using Vim for this task).

Problems?

Again, search and replace across multiple files is really difficult for Vim sadly.

One of the main issues is that Vim will open all the specified files (which could be a lot of files!). You could limit the number of files it searches by specifying a directory or subset of files to check, but if you don't know where to search then your only option is to search the entire code base and that's a crazy number of files (it would be for me working on the BBC News code base) to have open within Vim.

There are alternatives but they also aren't as great as you'd hope, such as not using Vim at all...

The Unix Way

sed -i -- 's/search_pattern/replacement/' *.txt && rm *.txt--

...this uses sed along with the 'edit in place' -i flag (which tells sed to apply the changes to a temp file first and then overwrite the original file).

Typically the -i flag will be followed with a file extension so sed knows what type of temp file needs to be saved to (e.g. -i.bak would save the changes temporarily to a test1.txt.bak file), so I opted for --.

After that you pass in the search pattern and the replacement and then what files to check against.

Finally we need to remove the temp files that have been created rm *.txt--.

Not completely ideal, I know, as it effectively has similar issues to the Vim way in that you have to try and filter down files searched (although I'd argue doing this via the shell should/could be more efficient than from within Vim).

The GNU Way

The very last way is the same as the previous solution but is the one I use now...

gsed -i 's/search_pattern/replacement/' **/*.txt

...this is the GNU version of the sed command which you can install using brew install gnu-sed.

Notice that you don't need to specify a temporary file to write to (and so no extra files to have to remove).

This for me is the best way to handle this type of issue.

All of the above should cover the majority of solutions you'll find on the internet for this problem.

Moving between brackets

It can be useful sometimes to be able to jump between opening and closing brackets (especially when working on code), this is where Shift-% comes in.

Auto indenting

This is one of those Vim commands most people (even experienced Vim users aren't aware of). It's an essential tool for me when programming now and since discovering it I find I use it all the time.

If we want to auto indent all content inside a code block then we can do this one of two ways:

  1. whilst cursor is placed on either the opening or closing code block bracket
  2. whilst cursor is somewhere inside the code block

For the first scenario you can use: =%

For the second scenario you can use: =i{ or =i}

Changing content

Another small tip that really does save we a lot of time is when I'm in the middle of a word and I want to either edit or select that word.

What I used to do was move b to the start of the word and then either ce or ve.

But I discovered recently that I can skip the first b command. I can do what I need to whilst my cursor is placed anywhere inside the word using: ciw (change inside word) or viw (select inside word).

Also, I recently discovered that you can delete a specific number of characters using something like c2l or d2l (change or delete 2 characters). In this command l means 'letter'. That can be quite useful as well.

Selecting content

Most Vim users probably know this but just in case you don't, to be able to select content inside of a set of punctuation (such as a brackets or quotations) then use: vi( or vi' or vi" (you get the idea).

Using the register

One of the real annoying issues I have is when I have some content I want to copy and paste to another place in my code. Imagine you have the following code...

/**
 * @param abc
 */
function someThing (def) {
    //
}

...I want to replace def with abc so the first thing I do is yank/copy the abc, then move to the parenthesis, but rather than manually delete def and then paste my content I'll do a di( to delete the content first.

This causes me a problem because it updates the register list (which tracks everything that has been yanked). Any time you change or delete content it gets copied to the register list. So if I was to paste now I'd just end up pasting def as the delete command has placed that at the top of my register list.

So I'll end up having to go back and re-copy abc and then head back again to the parenthesis to paste it in.

My colleague showed me this alternative better workflow: copy abc and still delete inside the parenthesis, but if you execute :reg and look at the list there you'll see something like "1 abc. I can then reuse that particular item by typing "1p (so I grab what's held at "1 and then use the paste command).

It might sound like I'm doing more work by looking up what's in the register list, but really I'm saving myself time compared to moving my cursor back to the original location and re-copying abc and then moving back to parenthesis and pasting.

Buffer management

This should be common knowledge for Vim users: when you open a file then Vim places the contents of that file inside of a buffer. When you edit the buffer then the original file is left unchanged until the buffer itself is written back to the file (e.g. :w).

When you have multiple files open then you have multiple buffers. To close the current buffer you can run the command :bd.

You can also view all open buffers with :ls.

But the one trick I find most useful is to close all open buffers and this again relies on bufdo which we saw earlier when looking at a global search and replace solution.

If you run the command :bufdo bd then it'll simply run the close buffer command bd for every buffer currently open. Simple.

Within my .vimrc file I've mapped those last two items to more easily accessible keys...

" List Buffers
map <leader>yt :ls<cr>

" Delete all Buffers (runs the delete buffer command on all open buffers)
map <leader>yd :bufdo bd<cr>

Jump List

The 'jump list' keeps a record of all your cursor positions/movements. It came in handy whilst I was writing this post actually and I'll explain how in a moment.

To view all cursor positions/movements just run the :jumps command.

To move backwards through each jump item use Ctrl-o and to move forward use Ctrl-i. Straight forward enough.

The reason this was useful to me was I wanted to create a 'Table of Contents' for this post and so I already had the headers (e.g. ### Jump List) written out and so what I was doing was using the / find command to locate all ### and then copying the title and moving back to the top of the document to paste it into a list.

The problem I was having was after I pasted the item at the top of this post's source file, I couldn't remember the line number I had just come from. So instead of pressing n to start moving back through all highlighted ### headers I instead just pressed Ctrl-o and it too me back to the last ### I had just moved from. Meaning I could continue on from where I left off.

As you can see, it's knowledge such as this that makes Vim users more efficient. I might not use this technique often, but because I know it exists I can take advantage of it when I do need it.

Change List

The 'change list' is the same as the 'jump list'. But as I'm sure you've already guessed, it records any changes made to the document.

What might not be clear is that it only records changes made when inside INSERT mode.

So to view all changes run the command :changes.

To move back through the change list use g; and to move forward use g,.

Be aware that this isn't the same as (u)ndo or Ctrl-r (redo) as they move backwards and forwards through changes and actually affect the list. The change list just moves the cursor's position to the place of a change.

Case Insensitive Searching

Although you can set a case-insensitive search (e.g. /mySearchTerm) via your .vimrc, you can also use the \c flag at the end of your search term /mySearchTerm\c.

Regular Expressions

If you look at http://vimregex.com/ you'll realise that Vim only supports a subset of modern Regex features.

To make things more awkward Vim also has an odd default engine which means things like capturing groups (stuff to be captured) needs to be escaped like so: \(stuff to be captured\) which is ugly and hard to have to remember (considering nearly all programming languages don't require this type of syntax modification).

So to resolve that you can tell Vim to use "very magic mode" (there are other modes for Vim to use with Regular Expressions but this is the only one of importance to me - and likely to you as well).

To use "very magic mode" just add \v to the beginning of your regex.

So imagine you want to capture the words "very magic" in standard Vim regex mode you'd need to write :%s/\(very magic\)//gc but we don't want to have to escape the capturing group syntax so we do the following instead :%s/\v(very magic)//gc

Note: referencing captured groups differs between programming languages. Some use $1 and others use \1 (which makes them consistent with 'back references'). In Vim they use the latter \1 style.

Removing line spaces

Pressing Shift-J will remove a line break for you.

This doesn't sound like much of a tip but this is another of those commands I end up using a lot.

So it'll convert...

Here is some text
that is split by a line break

...into...

Here is some text that is split by a line break

Switching case

One thing I used to hate doing is going into INSERT mode to change either a single character or word (or worse still, an entire sentence) into different case.

The ~ tilda command does that for you.

So if your cursor is on a single character such as the 't' of the word 'today' and you press ~ (you'll likely need to hold down the Shift key if you're on a Mac) then the casing will switch to uppercase and become 'Today'.

This can be done letter by letter or chunks of selected text.

Moving forward and backwards by code not words

Something I didn't realise for a long time was that I could use the capitalised version of most commands for them to do the opposite of what they normally do.

For example, fa will move the cursor to the first instance of the a character. But F will move backwards for the first instance of a it can find.

The reason this is important is when I'm programming and I want to move backwards or forwards I typically use the w and e keys, but programming syntax can be a pain to jump through like that.

Consider (and this is a contrived example, so forgive me, I realise there are better ways)...

this.handlePrevImageCalculations = _.debounce(function() {

...if I want to get my cursor to just before = then pressing e would take about three presses as it would stop at the end of this and then . and finally at the end of handlePrevImageCalculations.

But using E just the once moves there by ignoring punctuation between words.

This is the same for W and B.

Repeating yourself

Using the . command can be really useful for saving yourself time repeating yourself. Whether you've made an edit or you've indented a line of code (whatever it happens to be), pressing . will repeat that change. Try and get into the habbit of using it.

To give you an example, I used the Surround plugin (described above) to wrap my table of contents in square brackets using ys$] and for each line I just pressed . and it meant I didn't have to think about which four characters I needed to type out multiple times.

Appending to end of a line

This tip really does save me a lot of time.

When I wanted to add some content to the end of a line I would typically use $ and then a until I realised I could just press A and that would do the same thing.

OK so it saves you one key stroke. But I do this type of movement ALL THE TIME and so that's a lot of savings you end up making.

Searching for current word

If you want to search for the word your cursor is currently on, don't do this:

...instead just press Shift-8 and that'll do all of that for you.

Conclusion

So there you have it. This is my attempt to explain my Vim workflow and to hopefully have shared some useful Vim tips and tricks.

If you want to see my full dotfile set-up (this includes my .vimrc and other Vim configurations) then check out my public GitHub repo "Fresh Install" which should tell you everything you need to know (I update this a lot as I find better ways of doing things).


Links