Thursday, October 16, 2008

Remap Ctrl and Caps Lock

I used to think that I was the only person who did this, but as my horizons have widened slightly I've realized I'm just one in the crowd. But it's still a minority group to be sure, so I'm doing my part to evangelize.

The standard keyboard layout puts the Caps Lock key to the left of the A key and it puts the right Ctrl key in the bottom left. This means Caps Lock is basically on the home row while Ctrl is behind and almost under your hand. This seems backwards to me as I never use Caps Lock, but I use Control about 10,000 times a day (Ctrl+S, Ctrl+click in Firefox, Ctrl+C, Ctrl+V, Ctrl+Z, etc).

So, as I briefly mentioned in a post about Keyboards almost a full year ago, it would seem to make sense to swap the Caps Lock and Control keys so that the key you use frequently is on the home row.

When I first did this a very long time ago I muddled around deep in the Windows registry and came up with a .reg file you could use. But I recently stumbled on a much easier way: just use SharpKeys. If you use an operation system other than Windows, hit up Google and you'll find tutorials on how to do it for your OS.

Tuesday, October 14, 2008

Vim Learning

This is the ninth post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

At this point we have a very flexible, fast, and relatively easy to use environment for editing, all within Vim. As you can see, Vim is not the type of editor that does everything you want out of the box. The Vim philosophy seems to be: be capable of doing everything, but make no decisions on behalf of the user. In other words, where other software would have picked a bunch of defaults that they thought were best, Vim does nothing and lets you pick what you want. The downside is it takes time, and it can be hard to even know features exist. The upside is you can configure it just how you want it, and I get 9 blog posts out of it.

This post is about how you find out what Vim can do, and how to setup it up. Basically, this is how I figured out all the things in the last 8 posts.

#1 Vim Help
The best way to learn about Vim, what it has to offer, and how to configure it is to browse around the help. Just do :help and start navigating around. Make sure you read the first section of help.txt as it teaches you how to navigate the help. The most important thing to know is that CTRL-] follows a link ("tag") and CTRL-T takes you back.

Also, read :help help_context as it teaches you how to find help on the commands in a certain Vim mode (normal, visual, insert, etc).

If you're looking for something specific, but you don't know what vim calls it my best advice is to just not get discouraged. Keep fishing with :help , trying different possible words. Don't be in a hurry. Stay in the mind set of browsing around. Read what you land on, if it doesn't look right keep looking for clues before giving up. Frequently all you need to know is Vim terminology.

#2 Google
When fishing through Vim Help fails you, try Google. This may teach you the terminology you needed. If so, dive back into the Vim help.

#3 Vim Tips
The Vim Tips Wiki is the next best place to go. Here you'll find all kinds of stuff people have come up with that might be helpful for you. Most of the scripts I've written are simply adaptations of scripts I found on the Vim Tips Wiki. These can be somewhat scattered. You'll frequently have to read through all the "duplicates" because each will have slight variations. Generally you can get what you want by picking between the variations.

#4 Vim Scripts
The Vim Scripts page is similar to the Vim tips but contains more robust scripts rather than simple tweaks and tips. This is where you'll find things like the Snippets script.

#5 Real People
Sometimes you just can't get an answer on the web or from the help. In those cases, it's best to ask someone who may have more experience. I've had a lot of help from the guys on the Vim IRC channel (server: freenode, channel: #vim). If you don't have an IRC chat program I recommend ChatZilla which is an AddOn to Firefox.

Armed with this, you should be able to get Vim to do anything it's capable of. So if you come up with (or come across) any cool or useful scripts/tips/etc, please let me know!

Thursday, October 9, 2008

Vim File Editing

This is the eighth post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

In Visual Studio you have a solution which contains all of your files. You simply locate the file by clicking around through the tree structure, then double click to open it. When editing more than one file, Visual Studio puts each file in a tab.

In Vim you open files to be edited with
:e path
You can use the tab key to auto-complete directory and file names as you type them. This will open the file to be edited. If you don't know the name of the file and you need to click around a file browser to find it, do
:browse :e
This will open a standard file browser dialog and then open the file you select.

Vim uses the concept of a buffer when editing multiple files. Buffers aren't visible like tabs, but otherwise they're basically the same. To see what buffers are open do
:ls
You'll see a numbered list. To go to one of those do
:b2
where 2 is the number from the list of the buffer you want to switch to. Or if you'd rather use the name of the file do
:b file
where file is the name. Use the tab key to auto-complete from all the open buffers. This auto-complete will even work if the file doesn't begin with what you typed. For example, type "gram" and it will find "program.cs". This is tremendously helpful!

If you're looking for alt-tab like functionality so you can keep switching back and forth between the same two buffers do
:b#
This is another really useful command to remember.

Vim can also split the window and show you multiple buffers simultaneously, or the same buffer at two different locations. There are tons of ways to do this (see :help windows.txt). I'll show you the way I like to do it because I find it to be the easiest to remember.

To open a new horizontal split do Ctrl+w s. For a vertical split do Ctrl+w v. Then just use :e or :b to work on whatever file you want in that split (by default it will open to whatever was in the window when you opened the split).

To close a split do Ctrl+w q. To move between splits do Ctrl+w {h,j,k,l}. h,j,k,l move the cursor around when you're in command mode: left, down, up, right respectively. When you use them with Ctrl+w they move between splits instead of moving the cursor, but the direction stays the same so it's easy to remember. For example, if you have two open splits and you're working in the bottom one, Ctrl+w k will move you to the top one. Then Ctrl+w j will move you to the bottom one.

Vim also has support for normal visible tabs, but I find it's buffer support to be easier to use in the long run. Especially since you can only have so many tabs open before they become useless, and since file names (and paths) can be too long to display reasonably on a tab (just look at MS SQL Management Studio...). If you're interested, :tabe opens a new tab, see :help tabpage.txt for more details.

The last major feature is one that Resharper adds to Visual Studio (and is also available in TextMate I hear) which allows you to search for a file you want to open when you only know part of it's name and you don't know exactly where it is. I have found this to be unbelievably useful, so I wanted to have the same ability in Vim. To do this I adopted a script from Vim Tips to Windows (and removed the Perl dependency). Add the following to your vimrc:
function! Find(name)
let l:_name = substitute( a:name, "\\s", "*", "g" )

let l:files = system( "dir *".l:_name."* /B /S" )
let l:list = split( l:files, '\n' )
let l:len = len( l:list )

if l:len < 1 echo "'".a:name."' not found" return elseif l:len != 1 let l:i = 1 let l:cwd = substitute( getcwd(), '\\', '\\\\', "g" ) for line in l:list echo l:i . ": " . substitute( l:line, l:cwd, "", "g" ) let l:i += 1 endfor let l:input = input( "Which ? (=nothing)\n" )

if strlen( l:input ) == 0
return
elseif strlen( substitute( l:input, "[0-9]", "", "g" ) ) > 0
echo "Not a number"
return
elseif l:input < 1 || l:input > l:len
echo "Out of range"
return
endif

let l:line = l:list[l:input-1]
else
let l:line = l:list[0]
endif
let l:line = substitute( l:line, "^[^\t]*\t./", "", "" )
execute ":e " . l:line
endfunction

command! -nargs=1 Find :call Find("")

Note: this script depends on the DOS dir command. It would have to be modified to work on a different system.

To use it simply type
:Find part of file
This will search recursively from your current directory (:cd) for files whose names contain *part*of*file*. It will then display a numbered list of matches and ask you which you'd like to open. Simply type in the number and hit enter, and the file opens.

With these techniques at your disposal you can now edit many files in a way which I believe to be much superior to what Visual Studio has to offer.

Update 5/4/2010:
Added :b# for alt-tab like functionality

Wednesday, October 8, 2008

Vim to and from Visual Studio

This is the seventh post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

Now that we've got Vim setup to a point where it's quite useful for doing C# development, we need to start actually using it. As I've discussed in the past, there will still be lots of times when you'll want to use Visual Studio. Whether it be for the Designer, or for Exploring APIs you're unfamiliar with through Intellisense, or for manipulating resources, settings, project, or solution files, or for debugging.

VS -> Vim
The key is to be able to get back and forth between them easily. To get from Visual Studio to Vim is the easiest. Simply add an "external tool" which launches Vim and opens the current file. In VS go to Tools -> External Tools. Click Add and enter the following:
Title: Vim
Command: C:\Program Files\Vim\vim70\gvim.exe
Arguments: +$(CurLine) "$(ItemPath)"
Initial directory: $(SolutionDir)

There will now be a "Vim" item in your Tools menu which will open Vim to the current file AND the current line.

You can assign a shortcut key to this command as follows.
  1. Note exactly where the "Vim" command appears in the Tools menu (How many items from the top or bottom is it?)
  2. Go to Tools -> Customize -> Toolbars
  3. Click on the Tools menu so it opens and find where the Vim tool was, it will now say External Command X where X is some number. Remember X.
  4. Back on the Customize window, click "Keyboard..."
  5. Type "ExternalCommandX" into the "Show commands containing" box, where X is the number you just found
  6. Choose your shortcut key and assign it. I use Ctrl+Shift+V, Ctrl+Shift+V
Now you can open Vim from Visual Studio with a simple shortcut key sequence.

Vim -> VS
To get from Vim to Visual Studio is pretty easy as well. Assuming that your current path (:cd) in Vim is the path containing the .sln file, you can simply type the following:
:! *.sln

When you hit the tab key Vim will automatically expand to the full name of the sln file. Hit enter and the solution will open in Visual Studio.

Tuesday, October 7, 2008

Vim Code Folding

This is the sixth post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

Visual Studio has a feature called "Outlining" which automatically allows you to collapse and expand regions, comments, methods, classes, namespaces, using statement blocks, etc. Ctrl+M, Ctrl+M will expand and collapse the block that your cursor is in. Ctrl+M, Ctrl+O will collapse all methods and summary comments (but not classes and namespaces).

Vim has this same ability built in but calls it Folding. The difference is simply that it has to be turned on if you want it, and that it doesn't understand your code as well as Visual Studio does (though it can be taught!).

In Vim, there are a number of different ways that folding can be done: syntax based, indent based, marker based, and manual. Syntax based looks for folding to be defined in the syntax file for the language being edited. Indent based folds lines that are at the same indent level. Marker based looks for a given character sequence and folders everything between those characters. Manual allows you to define where the folds should be.

I like to use the Syntax folding that's defined in the default Vim C# syntax file. This will fold #region ... #endregion blocks.

To make sure this is always on when I'm editing C# files I added the following to my vimrc:
if !exists("autocommands_loaded")
let autocommands_loaded = 1

" setup folding
autocmd BufNewFile,BufRead *.cs set foldmethod=syntax
endif

Note: if you've setup an autocmd for C# building as in my earlier post make sure you use the same if !exists()... block.

The following commands are used to open and close folds:
zo - open fold under cursor
zc - close fold under cursor
zR - open all folds
zM - close all folds

You can remember the "z" by thinking of those old accordion reams of paper where each sheet was connected to the next and imagining it from the side as you lift and lower the top sheet. From that profile the paper will appear to form a "z" as you fold and unfold it.

See :help fold.txt for more details.

Monday, October 6, 2008

Vim Snippets

This is the fifth post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

Snippets are code templates that you can have inserted into your code. Its kind of like copying and pasting from a file with a bunch of common code blocks in it, but faster. Visual Studio has support for snippets, but they require bouncing through menus to find what you want, so they're not that convenient. As such, I don't know anyone who uses them. The only snippet Visual Studio does have that I use is the one for summary comments. When you type '///' it expands to a full summary comment block. It even includes your parameter names and everything, which is pretty sweet.

The TextMate editor on the Mac recently brought a lot of attention to the concept of snippets, and so now everyone loves them. Mostly because the way TextMate implemented them was easy to use, and because it came with a lot of good predefined templates for Ruby on Rails.

Not surprisingly, someone wrote a script for Vim that mimics TextMate's snippet support. Follow that link, then follow the instructions and you'll have it all installed.

I then created a cs_snippets.vim file in ...\vimfiles\after\ftplugin to define a few C# snippets. This is what my file looks like now:
if !exists('loaded_snippet') || &cp
finish
endif

" summary comment
Snippet /// ///<summary><CR><{summary}><CR></summary>

" object declaration
Snippet dec <{Type}> <{VarName}> = new <{Type}>();

"foreach
Snippet foreach foreach ( <{Type}> <{Var}> in <{Coll}> )<CR>{<CR><CR>}

"try/catch
Snippet try try<CR>{<CR><{}><CR>}<CR>catch<CR>{<CR>}

With these snippets you can type: ///<Tab> and it will expand to:
///<summary>
///<{summary}>
///</summary>

The summary tag in the middle will be highlighted and you can simply type whatever you want to write over it. Then hit tab to commit the value you typed and move to the next tag, if there is one. If you have the same tag name in more than one place in your Snippet all occurrences will be replaced.

Check out :help snippet for more details.

Let me know of any useful snippets you use too.

UPDATE 12/23/2009:
I recently switched from using the SnippetsEmu plugin I wrote about in this post to using SnipMate.  The main reason I switched is that SnipMate allows you to define your snippets on more than one line, which makes them much easier to get right and keep up to date.  SnipMate also seems to work a little better when you're filling in your snippets.  I highly recommend you check it out.

Friday, October 3, 2008

Vim Help Integration

This is the fourth post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

The last post on Vim Intellisense talked about using ctags to navigate to the definition of a class/method and read the documentation there. This covers any code you, or your company, has written, but it leaves out all of the .NET framework's objects. That's a pretty big oversight.

The problem is we need to know what methods exist on a .NET object, or what parameters a .NET object accepts, or just general help on a certain .NET object. This information is all easily obtained from the MSDN library, a largely under utilized resource as most developers I know depend primarily on Intellisense instead.

To solve this, we'll setup Vim so that you can put the cursor on any word and hit F1 and Vim will automatically open your browser of choice and do a search of the MSDN library for that word. To do this, add the following to your vimrc:
" setup integrated help
function! OnlineDoc()
let s:wordUnderCursor = expand("<cword>")

if &ft =~ "cs"
let s:url = "http://social.msdn.microsoft.com/Search/en-US/?Refinement=26&Query=" . s:wordUnderCursor
else
execute "help " . s:wordUnderCursor
return
endif

let s:browser = "\"C:\\Program Files\\Mozilla Firefox\\firefox.exe\""
let s:cmd = "silent !start " . s:browser . " " . s:url

execute s:cmd
endfunction

map <silent> <F1> :call OnlineDoc()<CR>
imap <silent> <F1> <ESC>:call OnlineDoc()<CR>
Notice that I use firefox, and that the help site to use is determined based on the file extension of the current file. This allows you to set this up for any language you work with. Finally, if the extension isn't defined it'll open up Vim's help.

Thursday, October 2, 2008

Vim Intellisense

This is the third post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

Before you get excited, I can't tell you how to get Intellisense setup in Vim. I can just tell you how to get close. I would say close enough, but you'll be the judge.

Intellisense in Visual Studio can do the following things:
  1. Complete variable, class, and method names as you type them
  2. Show you what methods/properties/etc are available on a given class after you type "class."
  3. Show you summary documentation on methods/properties/classes/parameters
Visual Studio can also take you to the code that defines a class/method/property with "Go To Definition".

In Vim, I can do #1 (sort of) and "Go To Definition." I claim this is "good enough" in most circumstances because Go To Definition takes you to the code where the method documentation resides AND it makes it easy to get right back to where you came from. This is obviously much more work than it is in Visual Studio where all that information is simply at your finger tips, but I found that the majority of the time the information is in my memory. And when it isn't, going to the definition and then coming back isn't so costly that it is a deal breaker, at least for me.

But in the interest of being very plain and transparent about this, Vim can't even come close to touching Intellisense, and there are many times when Intellisense makes life a lot easier. In these times, I work in Visual Studio. With that out of the way, on to how to do this in Vim!

The first part, Word Completion, is built in to Vim and you don't have to do anything at all to turn it on. Simply hit <ctrl+n> and Vim will autocomplete the word you're typing. If there is more than one match, it will show them in a popup menu. Use <ctrl+n> and <ctrl+p> to move forward and backward through that popup. Type anything to select the word. Vim uses every word in every buffer you've opened (in the current session) to match against, so it will always work on variable and method names in the same file and will work on those in other files if you've opened that file.

The second part, Go To Definition, requires more work. First you have to get a program called ctags. When you run ctags (from the shell) it builds a "tags file" which is basically a dictionary of every method and class name in every file you told it to parse. Vim knows how to parse a tags file, so you can then position your cursor on a method name in Vim and type <ctrl+]>, and Vim will take you to the file and line where that method is defined. After you've found what you need and are ready to return to where you came from simply type <ctrl+t>.

To run ctags just go to the top directory of your source code and run:
ctags --recurse
This will parse all the files in that directory and all it's subdirectories and then create a "tags" file in that directory. By default Vim will look for tags files in Vim's current directory and in the directory where the file you are editing is located. The only trick here is that you have to keep the tags file up to date by manually re-running ctags if you add or remove methods.

Wednesday, October 1, 2008

Vim TFS Integration

This is the second post in my series on using Vim to do C# development. You can read the introduction into why someone might want to do that here.

Where I work, we use Microsoft's Team Foundation Server Source Control. It's not very good at merging, but other than that it's a good tool.

Unlike some other source control tools, in TFS a "get" downloads the latest version of a file, a "checkout" lets you edit a file. Basically all a checkout does is make the file not readonly, but you have to do it or else TFS wont let you check the file in when you're done.

Because of this, if you're using Vim to do your work, when you first open a file and try to go into edit mode Vim will warn you that the file is readonly. This reminds you that you need to check it out. It would be very annoying if you had to switch over to the command line (or VS!) to check it out just so you could start editing. So don't do that! Just add this to your vimrc:
" setup TFS integration
function! Tfcheckout()
exe '!tf checkout "' expand('%:p') '"'
endfunction
command! Tfcheckout :call Tfcheckout()

function! Tfcheckin()
exe '!tf checkin "' expand('%:p') '"'
endfunction
command! Tfcheckin :call Tfcheckin()

The "expand" part will expand to the current file with it's full path included (Note: you have to use the execute command instead of running the ! command directly or else you'll have problems with parenthesis not being properly escaped in your file path).

Now you can simply type :Tfcheckout, and the file will be checked out. When you're all done type :Tfcheckin and the TFS checkin dialog will open, allowing you to enter a comment, checkin any other files, associate the checkin with a TFS work item, etc.