ChatGPT解决这个技术问题 Extra ChatGPT

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.

I haven't found a really satisfactory way of navigating files and buffers, that uses no external aids at all. The built in stuff is pretty bad (I mean, changing to a buffer by its number? Who goes around remembering temporary buffer numbers ...)
@svend: you can refer to buffers by name as well as number - see my answer below
have you mapped caps-lock to ctrl? It makes most things with ctrl much nicer... You can use something like gnome-tweaks or setxkbmap -o ctrl:nocaps

佚名

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

:Sex

I'm not making this up :)


and from help I see that :Vex is also great.
And :Vex if you want to split the screen vertically instead of horizontally
Wow, never knew either of these. I'm finding :Vex more practical, but :Sex just made my day.
for the record, :Se works too (same for the Ve, Te variants). No need to make it weird :)
A
Andrew Hendrie

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:

:cd into the toplevel directory of my project. To open file foo/bar/baz: Simplest scenario: type :e fbb. If there are more than one file starting with b in one of those directories you might have to do a or or another 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 * to drill down. Open 2 or 3 windows and open files in all of them as needed. 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. Then, use :b to cycle through buffers that are already open in the background. If you type :b foo 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.


Tip of the hat for the awesome explenation. Wag of the finger for the skillz++ you already need to have to understand the explenation.
If you add set path+=** to your configuration you basically enable fuzzy search as explained here
E
Emil Rehhnberg

:Sex,:Vex, :Tex and :Ex are all useful commands for ex(ploring) the files on your system if you want to use something different from :e

(where S/V/T are short for Split/Vertical/Tab)


d
dlimeb

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

e
eclipse

By far the best and fastest plugin I found for file navigation is fzf.vim. You can very quickly fuzzy search all your files, the open buffers and even the files contents.

Since we have a very large codebase at work I specified a couple of directories I use most as the directories fzf searches. Fzf even has a rich git integration. So you can search only tracked files.

https://i.stack.imgur.com/KcwmH.gif

https://i.stack.imgur.com/grGuv.gif


V
Vini.g.fer

It is surprising to see that :find command has not been mentioned in any of the answers. I usually work with rails projects where I need to drill down deep into the directory hierarchy. So for a file application.css, located in app/assets/stylesheets/ all I have to type is :find applica and then press tab to autocomplete and enter to open.


:find doesn't work that way for me? It won't find anything not in the current directory.
@TomRossi, your vim dot file must be missing a configuration, see this post.
b
bitprophet

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.)


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".
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.
vim-titlecase screws with the gt/gT mappings, but there is a work-around.
h
hasen

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


I made some extensions to this awesome addon. svendtofte.com/wp-content/uploads/2009/08/… 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.
H
Hotschke

Check out the plugin ctrlp as an alternative to the plugin Command-T. It's better than this in that it is a 'native' Vim script and doesnt need Vim to be compiled with ruby (or other support) while it runs very fast and unobtrusive.


D
Dave Kirby

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.


u
uniquesnowflake8

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.


A
Ayman

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


J
John Topley

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


x
xinghua

NerdTree is best for file navigation in vim.

The link below is a good introduction to nerdtree.

http://www.catonmat.net/blog/vim-plugins-nerdtree-vim/


B
Brian Agnew

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).


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.
A
Armin Ronacher

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)


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.
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.