ChatGPT解决这个技术问题 Extra ChatGPT

vim, switching between files rapidly using vanilla Vim (no plugins)

vim

I understand that limiting myself to vanilla Vim (not using plugins) limits the power of the editor, but as I switch between different machines frequently, it is often too much trouble to move my environment around everywhere. I want to just stay in vanilla Vim.

Something that holds me back is the ability to quickly switch between files. I (believe at least) have a good understanding of buffers, windows, tabs, as well as netrw (Vex, Ex, etc).

But in an editor such as Sublime Text, I can just type ctrl-p and instantly I am at the file.

I know that I can drop down to the shell, but I wonder if there are any other "hidden" secrets to rapidly switching between files in Vim based off more than just the filename.

This doesn't answer your question, but it might persuade you to consider using plugins: dudarev.com/blog/keep-vim-settings-and-plugins-in-git-repo
I personally sync my settings with Dropbox. It's clumsy but it more or less works without having to think about it. The one plugin I use and know works well for what you want is Command-T (github.com/wincent/Command-T). Ctrl-P could be an alternative (vim.org/scripts/script.php?script_id=3736).
Have you seen danielmiessler.com/study/vim? He has the very smart practive of putting his vimrc + all the plugns he needs into Github ... anmywhere he goes he can clone it and voila, Vim is exactly as he likes. Brilliant
@bobox, tens of thousands of people do that; there's nothing extraordinary about that.

r
romainl

The closest equivalent ("closest", not "exact") to ST2's Ctrl+P is a plugin called, get ready… CtrlP. There are other similar plugins like Command-T or FuzzyFinder.

I use CtrlP and I love it but I wholeheartedly support your decision to go "plugin-free". It's not the easiest way to go but it will pay off in the long run.

Opening files

The most basic way to open a file is :e /path/to/filename. Thankfully, you get tab-completion and wildcards: the classic * and a special one, **, which stands for "any subdirectory".

Combining all of that, you can do:

:e **/*foo<Tab>

to choose from all the files containing foo in their name under the working directory or:

:e **/*foo/*bar<Tab>

to choose from all the files containing bar in their name under any subdirectory containing foo in its name, anywhere under the working directory.

Of course, that works for :tabe[dit], :sp[lit] and :vs[plit], too.

Those commands are limited to one file, though. Use :next to open multiple files:

:next **/*.js

and take a look at :help arglist.

Jumping between buffers

:b[uffer] is the basic buffer-switching command:

:b4         " switch to buffer number 4
:bn         " switch to next buffer in the buffer list
:bp         " switch to previous buffer in the buffer list
:bf         " switch to first buffer in the buffer list
:bl         " switch to last buffer in the buffer list
:b foo<Tab> " switch by buffer name with tab-completion
:b#         " switch to the alternate file

Note that many of these commands and their relatives accept a count.

The :ls command shows you a list of loaded buffers. It is a bit "special", though: buffers are assigned a number when they are created so you can have a list that looks like 1 2 5 if you delete buffers. This is a bit awkward, yes, and that makes switching to a buffer by its number a bit too troublesome. Prefer switching by partial name, :b foo<Tab> or cycling, :bn :bp.

Anyway, here is a cool mapping that lists all loaded buffers and populates the prompt for you, waiting for you to type the number of a buffer and press <enter>:

nnoremap gb :ls<CR>:b<Space>

With this mapping, switching to another buffer is as simple as:

gb
(quickly scanning the list)
3<CR>

or:

gb
(quickly scanning the list)
foo<tab><CR>

The idea comes from this image taken from Bairui's collection of Vim infographics:

https://2.bp.blogspot.com/-d1GaUBk-Y10/TyFhskmCYRI/AAAAAAAAARQ/CIEx1V7FLqg/s1600/vim-and-vigor-004-flying_is_faster_than_cycling.png

Vim also has <C-^> (or <C-6> on some keyboards)—the normal mode equivalent of :b#—to jump between the current buffer and the previous one. Use it if you often alternate between two buffers.

Read all about buffers in :help buffers.

Go to declaration

Within a file, you can use gd or gD.

Within a project, Vim's "tags" feature is your friend but you'll need an external code indexer like ctags or cscope. The most basic commands are :tag foo and <C-]> with the cursor on a method name. Both tools are well integrated into Vim: see :help tags, :help ctags and :help cscope.

For what it's worth, I use tag navigation extensively to move within a project (using CtrlP's :CtrlPTag and :CtrlPBufTag commands, mostly, but the buit-in ones too) and my favorite "generic" buffer switching method is by name.

Deploying your config

A lot of Vim users put their config under version control which makes it very quick and easy to install your own config on a new machine. Think about it.

EDIT

A few months ago, I had to work on a remote machine with an outdated Vim. I could have installed a proper Vim and cloned my own beloved config but I decided to travel light, this time, in order to "sharpen the saw". I quickly built a minimalist .vimrc and revisited a couple of half forgotten native features. After that gig, I decided CtrlP wasn't that necessary and got rid of it: native features and custom mappings are not as sexy but they get the job done without much dependencies.

Juggling with files

set path=.,**
nnoremap <leader>f :find *
nnoremap <leader>s :sfind *
nnoremap <leader>v :vert sfind *
nnoremap <leader>t :tabfind *

:find is a truly great command as soon as you set path correctly. With my settings, ,ffoo<Tab> will find all the files containing foo under the current directory, recursively. It's quick, intuitive and lightweight. Of course, I benefit from the same completion and wildcards as with :edit and friends.

To make the process even quicker, the following mappings allow me to skip entire parts of the project and find files recursively under the directory of the current file:

nnoremap <leader>F :find <C-R>=expand('%:h').'/*'<CR>
nnoremap <leader>S :sfind <C-R>=expand('%:h').'/*'<CR>
nnoremap <leader>V :vert sfind <C-R>=expand('%:h').'/*'<CR>
nnoremap <leader>T :tabfind <C-R>=expand('%:h').'/*'<CR>

WARNING! The path option is extremely powerful. The value above—.,**—works for me, as a default fallback value. In the real world, the exact value of the option will differ from project/language/framework/workflow to project/language/framework/workflow, so the proper value depends entirely on your needs. Don't blindly copy that line and expect it to solve all your problems.

Juggling with buffers

set wildcharm=<C-z>
nnoremap <leader>b :buffer <C-z><S-Tab>
nnoremap <leader>B :sbuffer <C-z><S-Tab>

The mappings above list the available buffers in the "wildmenu" with an empty prompt, allowing me to either navigate the menu with <Tab> or type a few letters and <Tab> again to narrow down the list. Like with the file mappings above, the process is quick and almost friction-less.

nnoremap <PageUp>   :bprevious<CR>
nnoremap <PageDown> :bnext<CR>

Those mappings speak for themselves.

Juggling with tags

nnoremap <leader>j :tjump /

This mapping uses regex search instead of whole word search so I can do ,jba<Tab> to find tag foobarbaz().

Yes, fuzzy matching is addictive but you can be just as productive without it. And for a fraction of the cost.

MORE EDIT

A couple of additional tips/tricks…

Wildmenu options

The "wildmenu", enabled with set wildmenu, makes file/buffer navigation easier. Its behavior is governed by a bunch of options that are worth investigating:

wildmode tells Vim how you want the "wildmenu" to behave:

set wildmode=list:full

wildignore filters out all the cruft:

set wildignore=*.swp,*.bak
set wildignore+=*.pyc,*.class,*.sln,*.Master,*.csproj,*.csproj.user,*.cache,*.dll,*.pdb,*.min.*
set wildignore+=*/.git/**/*,*/.hg/**/*,*/.svn/**/*
set wildignore+=tags
set wildignore+=*.tar.*

wildignorecase allows you to search for foo and find Foo:

set wildignorecase

File marks

augroup VIMRC
  autocmd!

  autocmd BufLeave *.css  normal! mC
  autocmd BufLeave *.html normal! mH
  autocmd BufLeave *.js   normal! mJ
  autocmd BufLeave *.php  normal! mP
augroup END

I recently found this gem in someone else's ~/.vimrc. It creates a file mark at the exact position of the cursor whenever you leave a buffer so that, wherever you are, 'J jumps to the latest JavaScript buffer you edited. Awesome.


+1. I had no idea about the "any subdirectory" in combination with :e but I'll be using it a lot from now on. I marvel at the work that got into Ctrl-P and can learn a lot from it but it didn't work for me. I found it to be a bit slugish and as such interrupting my train of thought while working (could be my system, my settings, myself but I didn't investigate)
I'd love to upvote again for the gb map. Another one I'll use a lot. All buffer plugins I have tried (CtrlP, bufExplorer, ...) are not nearly as fast as this (granted, they offer more functionality but not enough for me to keep using them).
@LievenKeersmaekers, this is where I got it from and this is where the silly picture comes from. Thanks Bairui!
Sometimes it is also handy to go sequentially through a list of files (e.g., if you did something like vim *.php to open several files at once). Then you can use :n[ext] (as well as :prev[ious], :fir[st], and :la[st]).
This might be the single greatest answer ever.
I
Ingo Karkat

The answer depends a lot on your preferences and circumstances. Some examples:

If it's mostly two files (e.g. a C header and implementation file), is very handy. In general, the alternate file is an important concept.

If you use a large editor window, window :splits turn the problem of locating a buffer from locating the window (once you've got all buffers opened). You can use [N] to quickly switch to it.

If you can memorize (a few) buffer numbers, the :[N]b[uffer] and :[N]sb[uffer] commands are quite handy; :ls tells you the numbers.

Plugins (or at least custom mappings) can improve things a lot, and there's a whole variety on this topic on vim.org. There are various mechanisms to distribute your config (Pathogen + GitHub, Dropbox, ...), or you could remotely edit server files through the netrw plugin that ships with Vim.


Would probably worth mentioning ctags, cscope, gtags, id, and friends. I find using uppercase marks to be very helpful. Use mA to store mark A and ````A``` to return. I find netrw much more useful after I learned about :Rex which returns to explorer. :b, :e, and many others can take wildcards like * and **. The :b command can take a partial filename. Combine that with <c-d> or the wildmenu you can get pretty far. As for plugins you can use something domain specific like rail.vim which provides rails specific navigation commands or something more general like CtrlP.
@PeterRincker: +1 for mentioning about marks. I suggest constructing an answer with marks.
What does and [N] mean?
c
chris

Sometimes it is also handy to go sequentially through a list of files (e.g., if you did something like vim *.php to open several files at once). Then you can use :n[ext] (as well as :prev[ious], :fir[st], and :la[st]) for navigation (in addition to what was suggested in the other answers).


D
Dave Kirby

You can do wildcard tab completion on the command line without any plugins. e.g.

:e src/**/foo*<tab>

will let you cycle through all the files starting with 'foo' in the directory tree under ./src and select the one you want to edit.

If you have already edited the file and it is still in a buffer then you can switch to it with:

:b foo<tab>

which will cycle through all the buffers with 'foo' in the path. You may need to set the wildmode and wildmenu options to get the behaviour you want. I have

wildmode=longest:full
wildmenu

in my .vimrc.


g
gpojd

If you are on a filename and want to jump to that file, gf will do it for you. I also like using ctags, which isn't a plugin; you just build the tags and can easily jump around your codebase.


A
Amol Udage

If you want switch between files in vim editor, please see below answer

First press Esc key to exit from edit mode.

Then type :e to check current file path.

if you want to go another file then type :e /path-of-file.txt/ using this you are able to switch.

If you want to go previous file simply type :e# which switch to previous file path.


Y
Yesh

I had the same issue with Vim.

The last thing I want is to depend on plugins for a task as mundane as file switching.

I added the following lines to .vimrc

set path+=**
set wildmenu

And BAM! I can now :find any/filename/in/any/folder/ as long as vim is in the root directory of the project. Tab completion works. Wildcards work!

Once files are opened already, and there are a ton of buffers in the background (you could use :ls to see all buffers), running :b any/file <TAB> will fuzzy search for all buffers and jumps to the required file. In case it is not unique there will be a wildmenu of tabs (hence the 2nd line in .vimrc) which can be selected using tab.

My answer is coming from this awesome video
https://www.youtube.com/watch?v=XA2WjJbmmoM&feature=youtu.be&t=489
There are more tricks in and I recommend watching it.