I'll mostly second @janos's answer.
I learned vim by
- Running
vimtutor
- Deciding I would program exclusively in vim
- Reading
:help
top-to-bottom
- Continuing to program exclusively in vim
- Reading Practical Vim by Drew Neil
- More programming in vim
- &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 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 +"%%" }