Skip to main content
2 of 2
added 3 characters in body
D. Ben Knoble
  • 27.7k
  • 3
  • 31
  • 68

I'll mostly second @janos's answer.

I learned vim by

  1. Running vimtutor
  2. Deciding I would program exclusively in vim
  3. Reading :help top-to-bottom
  4. Continuing to program exclusively in vim
  5. Reading Practical Vim by Drew Neil
  6. More programming in vim
  7. &c.

I now spend a lot of time on Vi & Vim, as well as writing VimScript.

I'll add that my choice to program in vim led to learning the ins-and-outs of other tools (e.g., make, javac) to facilitate my programming. I also developed a strong value for good CLI tooling and now have a gut instinct for the quality of CLI programs (hint: I always ask myself, "Could I use this from Vim? And would it be easy?"). In the same way, I've developed a gut instinct for the quality of vim plugins: I much prefer those that enhance existing behavior or fit nicely into vim's concepts (e.g., operators and motions) over those that seek to retrofit other concepts on top of vim. (This purism is not for everyone, and is not even the most extreme vi(m)-purism out there. It works for me, though, because I like the language of vim, and want my commands and plugin mappings to make sense in the context of vim.)

I don't live in vim. I live in a terminal (usually in tmux). But I am in-and-out of vim all day long, and that makes a difference for learning how to use it.


One last piece of advice: make it easy to get into vim. Here's a short listing of code that has helped me along the way.

Shell functions

Most up-to-date is always in my Dotfiles

v() {
  vim "$@"
}

vv() {
  vim +'edit $MYVIMRC' "$@"
}

vq() {
  if (($# > 0)); then
    vim -q <("$@" 2>&1)
  else
    printf '%s\n' 'Usage: vq cmd' '' 'Use {cmd} output as quickfix list'
  fi
}

vf() {
  if (($# > 0)); then
    vim $("$@")
  else
    printf '%s\n' 'Usage: vf cmd' '' 'Use {cmd} output as filenames' \
      'Brittle: {cmd} output will be word-split'
  fi
}

vff() {
  if (($# == 1)) ; then
    # equivalent to vf ack -g "$1"
    vim $(ack -g "$1")
  else
    printf '%s\n' 'Usage: vff filename' '' 'Find {filename} to edit' \
      'Relies on ack(1)'
  fi
}

vc() {
  if (($# > 0)); then
    if pushd "$1" >/dev/null ; then
      # ${@[0]} = $0 = name
      # ${@[1]} = $1 = directory
      # ${@:2}  = remaining args
      vim "${@:2}"
      # this must work because pushd succeeded
      popd >/dev/null
    fi
  else
    printf '%s\n' 'Usage: vc dir [args]' '' 'Execute vim in {dir}'
  fi
}

vs() {
  if (($# > 0)); then
    local session="$1"
    shift
    vim "$@" -S "$session"
  else
    vim -S
  fi
}

# Start vim with its last cursor position
lvim() {
  vim +'normal '"'"'0' "$@"
}

vh() {
  vim +"help $*" +only
}

vgrep() {
  local pattern="${1////\\/}"
  for f in "${@:2}" ; do
    if [[ -f "$f" ]]; then
      ex -N -i NONE -n -- "$f" <<<"argdo global/$pattern/print" \
        | sed "s/^/${f////\\/}:/"
    # else
    #   printf '%s\n' "${FUNCNAME[0]}: $f: Is a directory" >&2
    fi
  done
}

vw() {
  if [[ "$(type -t "$@")" != file ]]; then
    printf '%s\n' 'Usage: vw cmd' '' 'edit file defining {cmd}'
  else
    vim "$(command -v "$@")"
  fi
}

Shell variables

EDITOR=vim
VISUAL=vim
MANPAGER=vim -M +MANPAGER -

Tmux bindings

# create a throwaway vim
bind-key v new-window -a vim
bind-key V command-prompt -p 'vim +' { new-window -a vim +"%%" }
D. Ben Knoble
  • 27.7k
  • 3
  • 31
  • 68