views:

1349

answers:

12
+10  Q: 

Vim file navigation

I'm trying really hard to learn vim after using TextMate for the last few years. I've started to commit some of the in-file navigation to memory, but I'm struggling with navigating between multiple files. In my workflow, it is pretty common that I'm flipping between a handful of files pretty regularly (enough files such that split-pane windows become too small).

I'm currently using NERDTree, but find drilling down into directories cumbersome as well as constantly using CTRL+W h/CTRL+W l to hop back and forth. I think I would do better with tabs I can easily toggle between, but maybe I need to use a different workflow.

I'd also like a "Go to File..." shortcut like CMD+T in TextMate. I've found fuzzy_file_finder, but it requires vim to be built with Ruby bindings which isn't the case the native installs I've worked on. While I could rebuild, the main reason I want to switch to vim is so I can have one editor environment that I know will easily work across any platform.

The options out there are overwhelming, any on what works for you are much appreciated!

A: 

Here's something fairly trivial that I stick in my .vimrc. It will load a file from any subdirectory.

" load from an unspecified subdirectory 
function! LoadFromSubdirectory(filespec) 
  let filename = glob("`find . -name '" . a:filespec . "' -print`") 
  exe ':e '.filename 
endfunction 
:command -nargs=1 Er :call LoadFromSubdirectory(<f-args>)

So I can just say:

:Er Main.java

and it will search subdirectories, find Main.java and load it. It's not well behaved for multiple files of the same name, but it's quick and simple.

The other tool I use is VTreeExplorer, which provides a tree-based window of files/directories, and doesn't require any special build options from VIM (i.e. it's a vanilla plugin).

Brian Agnew
I'd like to be able to load from a sub-directory, but the multiple files issue would be a deal breaker for me. I'm a Django developer, so I typically have a bunch of sub-directories that all have a `models.py`, `views.py`, etc.
Pete
A: 

My workflow for finding files is the wildmenu, autocwd and :e.

Relevant parts in the .vimrc:

set wildmenu
set wildignore=*.dll,*.o,*.pyc,*.bak,*.exe,*.jpg,*.jpeg,*.png,*.gif
set wildmode=list:full
set autochdir
let g:netrw_list_hide='^\.,.\(pyc\|pyo\|o\)$'

And how to use it:

:e myf^D

That gives all the files in the current directory that start with myf. You can also <Tab> through them. Use return to open :)

^D will always give you all the matches. Because autocmd always goes to the folder of the current file it's easy to work with. If you are in foo/bar.py and you want to go to foo/baz.py you only do :e baz.py and you're there. That also works with buffers (:b foo^D lists all buffers starting with foo)

Armin Ronacher
How about getting to other directories? For example, I'll often be working between my Python view, HTML template, and JavaScript files which all live in different sub-directories? In TextMate, I start typing the name of the file and all the matches in my "project" (aka cwd) show up.
Pete
It does not recurse into subfolders, no. But I adapted my workflow to that. Also once the file i open, i can just mention the name of the buffer and am fine. You can tell Vim to remember the open buffers, then you usually don't need that feature at all.
Armin Ronacher
+2  A: 

I think I would do better with tabs I can easily toggle between, but maybe I need to use a different workflow.

Are you aware of Vim's tabs? Not sure if you were referring to Vim's own tabs there, or pining for TextMate's. It's unclear what Vim version you're using but it's had tabs since at least 7.0 (which seems to be installed everywhere I look lately), and they're awesome.

:tabe opens a new one (short for "tab edit", so e.g. :tabe for empty or :tabe path/to/file for opening a file in a new tab,) you can move between adjacent tabs with gt/gT, and there's a bunch of other tab-related nav commands too, as you might expect from Vim (:help tabs)

My workflow for large projects tends to involve a bunch of tabs, each with between 1 and 3 windows depending on what sort of context I need. This works even better if I have a doublewide terminal window since I can vertically split with :vs, so then a single tab can easily show me 4 files at once with plenty of room for each.

Final tip: I sometimes use the "switch buffer" command (:sb <partial_buf_name>) which is sorta-kinda like TM's fuzzy finding, in that it works pretty well but only for already-open buffers. Still great for when I have a dozen or more files open at once. (N.B. I needed to :set switchbuf=usetab in my vimrc for this to work across tabs, but once that's set it's great.)

bitprophet
My understanding of tabs is that it's more of a layout preserver, not really a method of having one buffer open in each tab (check out Bram Molenaars own views on tabs in the video "7 habits of effective text editing".
Svend
Then once you've figured out commands like these which work for you, you can bind them to a key. I have control-tab flip between open buffers (a la firefox), but you could switch tabs instead.
Tartley
+2  A: 

I find LustyExplorer the best so far.

You can open a file by typing only a part of its name.

You can open a file from the directory of the current file, or the current pwd, or from the buffer list.

If you open a file from the buffer list, you don't have to navigate through the directory tree, though unfortunately for the other two modes, you still have to navigate through the tree. The good thing is you don't have to start from the first character.

If you have:

dir_a/
    ...
dir_b/
    file.js
    file.html

and you want to open dir_b/file.html you can generally find it by typing b<Tab>h

hasen j
I made some extensions to this awesome addon.http://www.svendtofte.com/wp-content/uploads/2009/08/lusty-explorer-mod.vimhttp://www.svendtofte.com/other/vim-stuff/Basicly allows me to just enter the name of a recently used file, whether its loaded already or not doesn't matter. This means you only need to browse the FS when you're opening a file for the first time.
Svend
+3  A: 

If you haven't found them already, you might want to check out:

  • the original fuzzy finder plugin -- which IIRC doesn't have the Ruby binding issues
  • the Project plugin -- similar to NERDTree
  • the buffer explorer plugin -- shows a list of open buffers

Also bear in mind that you can remap key shortcuts in your .vimrc to make them less cumbersome. I do use split windows a lot; I've found the following make dealing with them much easier:

" set your own personal modifier key to something handy
let mapleader = "," 

" use ,v to make a new vertical split, ,s for horiz, ,x to close a split
noremap <leader>v <c-w>v<c-w>l
noremap <leader>s <c-w>s<c-w>j
noremap <leader>x <c-w>c

" use ctrl-h/j/k/l to switch between splits
map <c-j> <c-w>j
map <c-k> <c-w>k
map <c-l> <c-w>l
map <c-h> <c-w>h
dlimeb
http://github.com/jamis/fuzzyfinder_textmate is better
Wahnfrieden
+1  A: 

I use this function for finding files in subdirectories, I didn't write it though. It's from the vim wiki:

function! Find(name) 
    let l:list=system("find . -name '".a:name."' | grep -v \".svn/\" | perl -ne 'print \"$.\\t$_\"'") 
    let l:num=strlen(substitute(l:list, "[^\n]", "", "g")) 
    if l:num 0 
            echo "Not a number" 
            return 
        endif 
        if l:inputl:num 
            echo "Out of range" 
            return 
        endif 
        let l:line=matchstr("\n".l:list, "\n".l:input."\t[^\n]*") 
    else 
      let l:line=l:list 
    endif 
    let l:line=substitute(l:line, "^[^\t]*\t./", "", "") 
    execute ":e ".l:line 
endfunction 

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

One thing I like is it has support for wildcards (*). It's also well behaved for multiple matches.

uniquesnowflake8
+1  A: 

I don't find drilling down into subdirectories via plain old :e to be that cumbersome, given a decent configuration for tab-completion.

Look into the 'wildmenu' option to have Vim show a list of completions (filenames) in the modeline above the commandline. You can change the 'wildmode' option to further configure the kind of tab-completion Vim will do. Personally I use :set wildmode=full.

My workflow is like this:

  1. :cd into the toplevel directory of my project.
  2. To open file foo/bar/baz:

    • Simplest scenario, type :e f<tab>b<tab>b<tab><enter>.

    • If there are more than one file starting with b in one of those dirs you might have to do a <left> or <right> or another <tab> on the keyboard to jump between them. Or type a few more letters to disambiguate.

    • Worst-case scenario, there are files and directories that share a name and you need to drill down into the directory. In this case, tab-complete the directory name and then type *<tab> to drill down.

  3. Open 2 or 3 windows and open files in all of them as needed.
  4. Once a file is open in a buffer, don't kill the buffer. Leave it open in the background when you open new files. Just :e a new file in the same window.
  5. Then, use :b <tab> to cycle through buffers that are already open in the background. If you type :b foo<tab> it will match only against currently-open files that match foo.

I also use these mappings to make it easier to open new windows and to jump between them, because it's something I do so often.

" Window movements; I do this often enough to warrant using up M-arrows on this"
nnoremap <M-Right> <C-W><Right>
nnoremap <M-Left> <C-W><Left>
nnoremap <M-Up> <C-W><Up>
nnoremap <M-Down> <C-W><Down>

" Open window below instead of above"
nnoremap <C-W>N :let sb=&sb<BAR>set sb<BAR>new<BAR>let &sb=sb<CR>

" Vertical equivalent of C-w-n and C-w-N"
nnoremap <C-w>v :vnew<CR>
nnoremap <C-w>V :let spr=&spr<BAR>set nospr<BAR>vnew<BAR>let &spr=spr<CR>

" I open new windows to warrant using up C-M-arrows on this"
nmap <C-M-Up> <C-w>n
nmap <C-M-Down> <C-w>N
nmap <C-M-Right> <C-w>v
nmap <C-M-Left> <C-w>V

It takes me a matter of seconds to open Vim, set up some windows and open a few files in them. Personally I have never found any of the third-party file-browsing scripts to be very useful.

Brian Carper
A: 

In addition to the wildmenu answers, I use BufExplorer plugin, and the following mappings to quickly jump buffers:

nmap <A-1> :b 1<CR>
nmap <A-2> :b 2<CR>
nmap <A-3> :b 3<CR>
...
nmap <A-0> :b 10<CR>
nmap <A-=> \bs

Or you can just replace the buffer explorer with the :ls command, which basically display the same thing.

The last one maps the Alt-= to show the buffer explorer.

I don't use Windows that much, as I generally have one or two windows only.

I also modified the statusline to include the buffer number %2n, so that the I always know which buffer is being edited. See :h statusline

Ayman
+1  A: 

Hello Pete, do you know MacVim application? It is VIM polished for OS X, and one of its feature is support for tabs (CMD+T to open new tab), it have drawer, etc... (read this: http://zerokspot.com/weblog/2008/08/03/macvim-as-textmate-replacement/)

Try it!

Regards Michal

msgre
it has no drawer
Wahnfrieden
+1  A: 

An easy way to browse the file system is the command:

:Sex

I'm not making this up :)

michaelSandahl
+1 Sex made my day! :-)
Petr Peller
A: 

If the file that you want is already loaded into a buffer (which is likely if you are flipping between a handful of files regularly) then you can quickly switch to the buffer with the :b[uffer] command.

:b can either take a buffer number as a parameter, or (more usefully) a string that matches part of the path/filename. If there are multiple matches you can use tab to cycle through them.

If you want to split the window and open the buffer in the new window then use :sb name

If you want to open the buffer in a new tab then use :tab b name

You can also use the :ls command to see a list of currently loaded buffers.

Dave Kirby
A: 

I use NerdTree

kitofr