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

3 comments:

  1. If you use ctages with the --extra="+f" option (which one of the commenters mentioned in a previous post)
    there is a simpler way to jump to files when only part of the name is known. Simply do:
    :tag /part
    and hit the tab for suggestions until the file is found.
    Note that part could even be a regex here.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Have you ever seen a Vim Plugin called FuzzyFinder? It does almost the same and much more.

    []s,

    Vinicius Canto
    Brazil

    ReplyDelete