Moving Your Mind Into Vim Mode
- Thursday, July 29, 2010
I read a great post today from Yehuda Katz - Everyone Who Tried to Convince Me to use Vim was Wrong. I liked this post - it reminded me of a conversation I had just the other day - trying to explain what I like about Vim.
You Won't Like It
If you haven't used Vim before and you're looking to learn it - it's kind of like a first taste of coffee. Or beer. It's bitter, not particularly sweet, and you get pretty damn tired of people talking about how much they love it rather quickly.
But then the buzz kicks in. The buzz of "hey - you know when you get used to it - you kind of like it... and HOLY SH** I can sling some text now!". That's what I read in Yehuda's post, at least.
See there - I did it again - even while writing about that very aspect that you (if you're new to Vim) will probably not like: me crowing about how much I like it. Sorry - let's start again.
No Really - You Won't Like It. Unless...
Here's how typical coversations go with friends who code Ruby in TextMate:
Them: "So I see you're getting into Vim. What do you like about it so much?"
Me: "Well - Vim's focus is on editing, not text entry and–"
Them: "Huh? What does that even mean?"
Me: "That you spend more time editing than you do writing"
Them: "Oh. Well I'm pretty happy with TextMate. You should write a blog about Vim."
Me: "I have."
Them: "Well maybe write about what you like about it."
Me: "I have"
Them: "Hmm - well I didn't get it. Maybe write a better one."
... which lands us at the feet of Yehuda's post. Vim is a hard thing to talk about - it's not terribly pretty, has a pretty hard-core "geek legacy", and is probably the most unwelcoming first experience you could want to have. Imagine trying to explain just how good Racer 5 IPA is (or better yet Deschutes Inversion IPA) to a person who's never tasted beer!
Yes, I just compared Vim to beer. In fact I've done it twice. I know that for the Vim-curious users out there this is going to sound strange - but it's the mindset I'm going to get into today - so let's get to it.
Sit back while I open up the tab - I have a frosty pint of Vim comin your way...
Vim Smells Weird
It's not like any text editor you've used. It's not like TextMate, it's not an IDE. It looks like the terminal (or console if you're on windows) and indeed - typing "vim" into the terminal will launch it - right inside the terminal!
The best description I've heard with regards to Vim is from Dan Benjamin in the Peepcode "Smash into Vim" screencast:
"It's precise: you'll feel like a text surgeon"
I remember hearing that and thinking "what a weird thing to say" - but it's where I think I'd like to focus first.
Most programmers understand that the bulk of coding an application comes after the application is first written. Debugging, refactoring, adding new functionality - this is the bulk of our work. This is what Vim is all about.
Vim's focus is on editing - and the mode you work in (I'll talk more about modes in a minute) most of the time is Normal mode. In this mode you don't enter text - but you can deftly edit it.
With the exception of Emacs - just about every code editor out there (including IDEs) focuses on text entry. The editing of the text is lumped into the entering of the text.
Vim turns this entire concept around - the entry of the text is set aside for when you need to do it - editing it comes first. I'm sure this sounds weird - let's dive into some examples. I'll be using GVim on windows - everything will work using MacVim as well if you're on a Mac.
Your First Drag of Vim
To say that Vim is not very welcoming is a bit of an understatement:
When windows devs see this - well let's just say it's the last impression they have of Vim. What to do next is just not apparent, the tildes, old-skool icons, and blocky Lucida Console font send most people running for their familiar IDEs.
Assuming you're still reading - let's try another sip and see what happens.
Another Sip - Not as Bad as The First
This is where it becomes apparent that we're not working in a typical code editor. There's no "project drawer" - no indication of other files, let alone where the hell you are.
Yet Vim works (sort of) with the concept of a "project" if you want it to. When you first open Vim, you'll be in a "Working Directory" - the "root" if you will in which all commands will run (like making directories, files and so on - more on that in a bit). If you've opened GVim using the icon on your desktop - you'll be in C:\Windows\system32. To verify this - enter ":pwd" (Present Working Directory) - the status window will tell you where you are.
Yah - weird. That's OK we can change that really quickly. It's worth noting here that Vim doesn't want to be opened with an icon; it's built to be opened from a terminal by entering "gvim" (or "mvim" if you're on a Mac). Doing it this way will auto-set your working directory to the current directory.
First - let's change the default startup. System32 is a bit ridiculous - right-click on the icon on the desktop and go to Properties. In there, set "Start in" to be something that makes sense - a "Projects" directory - or wherever you keep your code. Restart Vim.
Hey that wasn't so bad! We're moving forward... and feeling a bit light-headed (and after only 2 sips - Vim is fun!)
A Bigger Drink: Working With the File System
This is one thing I really like about Vim - you can manage files and directories rather easily right from within Vim. Now that you have Vim reopened in a directory that makes sense, let's do something fun.
First - let's confirm where we are: ":pwd". If you get stuck, ever, and can't enter commands and get lost - just hit ESCAPE. This will put you into normal mode where you can enter commands into Vim. You enter commands by pre-pending a colon - whenever you see ":" in front of something - I'm in normal mode and you should be to. It's a good habit to hit ESCAPE often to be sure of this.
Now let's create a directory
:!mkdir my_projectIf you feel like getting funky - and you have Rails installed:
You should see the console pop up (if you're on windows) and some stuff happening - that's Vim executing some commands for you. Let's take a look at what happened:
You'll use this command a lot - when you want to see the files and directories in your working directory (or a subdirectory therein). Notice that you also have some handy commands at the very top
Take a second to read those commands - you can do a lot here. Deleting and Renaming are something you'll do quite often - so get to know those straight away. Already we've picked up a bit of speed over conventional editing - there's no mouse involved here! No right-click/add file, no file explorer to organize your project.
I know that a few people will want to tell me about NERDtree. I happen to like the built in file manager - but many people like the visuals of the NERDTree plugin. Investigate!
Now, let's drop into our project and start editing it. Move the cursor down to "my_project" and hit enter. This will open up the directory which is either empty - or filled with a Rails project depending on what you did. Now hit "c" - this will change our working directory to the current directory, and we're ready for more.
Round 2 - Editing Some Text
Well that one went down pretty easily didn't it! I know I know - it's hard to stop at just one :). Let's move on here and do a bit more - let's write some Ruby code.
To create a file - simply use ":edit" again - but this time enter the name of the file:
:edit hello.rbWhen you entered "." before you told Vim you wanted to edit the current directory - which you did! Well done. Now let's work some Ruby code.
The first thing you'll notice is that it's probably a bit hideous looking. If you're using the default settings - well it will be. Let's work the code for now, and I'll show you all kinds of magic in a bit (code-completion, snippets, highlighting, etc).
What you should see is an empty file, and your cursor should be a big block (which is a visual cue that you're in Normal mode):
In the status bar down below is the name of the file, to the right of it is where your cursor is in the file itself. Let's enter some code in here - to do this we need to change modes (more on modes in a minute) to INSERT mode. Do this by entering "i" - you should now see "-- INSERT --" in the status bar. If you don't, hit ESCAPE and "i" one more time. Now enter this:
class Hello puts "hello there" end Hello.new
When you're done typing, a good habit to develop is to reflexively hit ESCAPE, putting you back into Normal mode. This has many benefits - such as when you say "oops!" and realize you need to change something - as you'll see in a minute.
To save this, you can do a number of things. You can do it the "Vim" way by telling Vim to write it to a file - ":w". You can also do it the "Windows" way by using Ctrl-s. If you're in MacVim you can use Command-S. Whichever one you like is up to you.
Now let's view our handy work:
This command is going to execute our new file for us - the "!" hands the command off to the console. What you should see next is our groovy "hello there" demo:
Hey that was pretty fun! Vim's starting to go down a bit easier now - what the hell let's do it again! If you want to rerun the last command - enter ":" to put you on the command line, then up-arrow to bring up the last command.
This Stuff Is Strong! Getting Your Vim Editing Buzz On...
Now we have some text, we've seen how we can manage files and work the command line - but this isn't at all what Vim is good at. Let's take a look at some editing.
Before we do, however - I'd like to talk about something Yehuda mentioned in his post:
Carl convinced me to use vim for the first couple of days pretty much exactly as I use Texmate ... I installed NERDTree on MacVIM, grabbed the most common vim “packages”, and was off to the races... For the first day, I clunked around by using my mouse’s scroll wheel, clicking and highlighting things, and spending most of my time in insert mode. It was slightly less productive than Textmate, but mostly in the range of what I’d expect switching to a new tool. In short, while I felt a bit out of sorts, I was able to get plenty of work done that first day.
That's right where we are - you've seen how to do basic things with Vim and also how to enter text. With a reasonable set of plugins - you'll be right where you were with TextMate in no time.
But we don't want to go home yet! We just ordered another round! And this one is going to be a ton of fun as we've realized we screwed up a bit when we first wrote out code. When do we not? Almost no one gets it right the first time - and this is where Vim shines.
We've also just received word from the client - they want something to say "goodbye" as well as hello - so let's get crackin!
Let's create the new file - a little faster this time (make sure to hit ESCAPE first):
and then our code...
class Goodbye puts "goodbye to you!" end Goodbye.new
and save with Ctrl-s.
Now let's fix our screwup. The client noticed that we said "hello there" instead of a proper demo - which says "Hello World". We have to fix the casing and a word - so let's do it.
As with most things, there are many ways to accomplish this - and I'm sure in the comments below someone will offer something more efficient - which is great! I'll show the 3 or 4 things I'd try... would love to hear from others with respect to their tricks.
OK - now that we grok modes a bit - we need to shift out of INSERT and into NORMAL - so hit ESCAPE. You're looking at goodbye.rb - but we need to get back to hello.rb! This is step one.
Navigation is pretty simple with Vim - it's one of the reasons people love it. I'll show you three ways to work this now...
- type ":edit h" and hit TAB and then ENTER. This will tab-complete the filename, putting you back into hello.rb
- type ":b h" and hit TAB and then ENTER. This works with the "buffer" - a place where all the documents you've opened are hanging out in memory.
- type "CTRL-wv". This will open up a vertically-split window. "CTRL-ww" will move your cursor there, and ":b h" TAB/ENTER (as above) will open up hello.rb in the second window.
Programming Your Text
Many people have said this - in fact Dan Benjamin echoes it in the Peepcode screencast linked above - often times, when editing, it feels like your programming your code. For some people this is an extra mental step that's ridiculous - for others, who are used to it, it's as simple as... well coding in the first place.
The key to it is to plan your move. At first this is going to seem silly - but as you get used to it, you realize that the time it takes to recite the proper incantation and execute it is far less than the total time it takes to move your mouse, select your text and rewrite. And it only gets faster!
Let's fix the casing on "hello" first. We do this by using Vim's search ability - which is a simple forward slash "/":
/h [ENTER] n rH
The search here is case-insensitive so it will highlight all the h's it finds once you enter the pattern (a single "h") and hit enter. You can move between the results by hitting "n" - or "next". Shift-N will move you backward. You can replace text you're sitting on by using "r" - in this case we'll replace it with an "H".
Next, I need to change the word "there" to "World". I take a second, plan my move, and execute. I'll do it in one of three ways:
2gg 3w cw "World"
This is the longer way of doing it - but it's pretty quick nonetheless. "2gg" moves the cursor to the beginning of the text on the second line (if you can't see line numbers enter ":set number" to turn them on) - think "2 go go". "3w" moves you to the 3rd Word. "cw" is "Change Word" and it automatically puts you in INSERT mode - where you can enter "World".
A slightly less mechanical way would be:
Again - moving to the second line, but this time we're using ":s" which means "Substitute". This is followed by a regex pattern to match, and the replacement text.
Finally - the easiest way to do this would be to remove the need to go to the line - and just do a global replace. This can be problematic if the file is large - you could end up matching more than you like - I'll show you a way around that in a second:
The only difference in this one command, versus the others, is the "%" wildcard, which tells Substitute to search over everything in the file.
Vision Is Getting Blurry
That last operation can be a bit destructive if we're not careful - so sometimes it's easier to match over a given range. To do this, we need to go into VISUAL mode - and we'll use a plugin to help us.
Matchit is installed by default with Vim and allows us to match the "natural" start and end of blocks of code - be it Ruby, HTML, XML, or whatever. To see this in action let's undo our last changes by pressing "u" (make sure to hit ESCAPE first to go back into NORMAL mode). You can also use CTRL-z/Cmd-z.
Head to the beginning of the method or class you want to change. You can do this by line number as above or, since the line we want is the first - use "gg" (Shift-G will take you to the bottom).
Now that we're here - enter VISUAL mode by using Shift-V and select the entire block (class or method - in our case it's a class) by hitting "%". Matchit will find "end" and select the block for you. If this isn't working for you - Matchit might not be installed (I've seen this with GVim). As an alternative you can enter "3gg" to go to line 3.
Now you can enter the same substitute command as above (without the "%") - and it will apply over the range.
I Need a Cab
I could go on - but this post is really long already. What I hope I have conveyed (aside from learning Vim is not unlike having your first beer) is that loving Vim builds on itself - and it does so with practice and reworking what you know.
Many people wonder why you would work so hard at a tool like this - and I'd like to end on that note:
- Vim is everywhere. My main machine here is a Mac, running MacVim. I have a Windows 7 VM running GVim, and I have an Ubuntu VM running straight up Vim. I also have an Apache server up on Amazon with vi that I can use over SSH! Each (aside from my server) uses my same plugin/configuration set so I'm at home on any one of them, coding in an environment I know and love.
- Vim is forever. The damn thing has been around since the dawn of time - and it will no doubt be around long after we're dust. The skills you pick up now will last you for many, many years - and you'll only get faster.
- There's a plugin for that. Code formatting, automatic comments, Rails-specific navigation and generation. Unit testing with RSpec or Cucumber. Git and Github. Syntax highlighting and code completion (using CTRL-n - check it out it's awesome!), and Code snippets. All of this, and a whole lot more can be mixxed and matched to create an environment that's just right for you.
- Help is Everywhere Aside from Emacs, you won't find an editor with a better help system - either through the builtin ":help" or online. It will be hard to get up to speed - but it won't be for lack of documentation.
Great! I can't possibly fit everything into one post - my goal was to get your head into a good spot. The next thing to do is kick up the vimtutor (open a console and enter "vimtutor") - it will walk you through some basics.
Next, head over to Peepcode and watch both of their Vim screencasts. It's $18 well-spent as they're made to be watched over, and over, and over again.