How do you do an incremental search across multiple files in VIM? - vim

Vim already does incremental search within the currently open file but can you do
an incremental search across multiple files?

AFAIK this is not possible. However you can start to type a word that is in an opened buffer and hit ctrl-xctrl-n to start searching for such a word in all opened buffers.

from :help grepadd
*:grepa* *:grepadd*
:grepa[dd][!] [arguments]
Just like ":grep", but instead of making a new list of
errors the matches are appended to the current list.
Example: >
:call setqflist([])
:bufdo grepadd! something %
The first command makes a new error list which is
empty. The second command executes "grepadd" for each
listed buffer. Note the use of ! to avoid that
":grepadd" jumps to the first error, which is not
allowed with |:bufdo|.
An example that uses the argument list and avoids
errors for files without matches: >
:silent argdo try
\ | grepadd! something %
\ | catch /E480:/
\ | endtry"

Related

Deleting all buffers except first one with one command

I'm using the perlsupport plugin to do syntax checking on my code. When it does the syntax checking, it places the files with warnings and errors into buffers. Sometimes I want to quickly close out those other buffers except for the first one because it is the script I'm currently working in.
I've tried 2,:bd and 2,$:bd and :bd 2 Quickfix\ List and :bd 2 [Quickfix\ List] and other variations without success. Thanks.
I should add that I know I can list out the buffers, find the last buffer number and do something like 2,N:bd but I'd rather have just one command I can turn into a shortcut.
You could write a command that uses exec to build the correct bd command:
command! Bd exec '2,' . bufnr("$") . 'bd'
bufnr("$") is the number of the last buffer.
As a test:
:badd foo
:badd bar
:Bd
Gives:
2 buffers deleted

How to efficiently execute a substitution command across multiple files in Vim?

I want to perform a number of substitutions of the following kind across several files:
"\includegraphics{all.png}" → "\includegraphics[width=\linewidth]{all.png}"
I would like to do that without Sed, using only Vim. However, when I do it, I always replace the buffer by accident with something like space so wasting a lot of keys. How can I do it fast?
Smallest amount of keys wins!
Start inside Vim: getting the matches to buffers
:grep -r "includegraphics" Sections/*
A flexible way of performing some actions in a group of files using
Vim is to collect the list of their names into the argument list (see
:help arglist), and then iterate through it executing the desired
command.
In order to do the first step, use commands :args, :argadd, and
:argdelete. For instance, to set the argument list to the names of
all files that have the .tex extension in the current directory and
its subdirectories, run:
:args ./**/*.tex
To perform the second step, use the :argdo command:
:argdo %s/\\includegraphics\zs\ze{all.png}/[width=\\linewidth]/g
Replace in all buffers
:bufdo %s/\\includegraphics\{all\.png\}/\includegraphics[width=\linewidth]{all.png}/ge

How to store grep results in a buffer in Vim?

I want to debug a process, hence I attached strace to the process and redirected the output to a file and then performed the operation. During the process it has created a lot of processes. So here is what I want to do, I want to select all the system calls executed by a process. To do that I used grep command with pattern as pid:
:grep pid %
It shows the result but I am not able to traverse through the result, it promts
Press ENTER or type command to continue
and returns to the file. What I would like to do is store the result in a buffer and then have a look into it and if required save it into a file or else discard it and return to the original file. Is there a way to do this with out exiting from the vim editor? Thanks in advance.
I would like to search with the result and store that in a buffer.
Over the years of reading all kind of logs, I learned this little trick:
:%!grep pattern
It simply replaces the current buffer contents with grep output (so to go back to the original logs you have to simply press u).
You can also use it with other tools:
:%!ack pattern
:%!ag pattern
:%!rg pattern
Note that you can also run these commands on other files then the current one. The following 2 commands would replace the current buffer with results of grepping over the current file (second % character, which would be redundant for grep in this case) and otherfile.txt respectively:
:%!grep pattern %
:%!grep pattern otherfile.txt
For me it's the simplest and the best solution for fast grepping of big files in Vim and I'm pretty surprised no one ever mentioned it.
You can go to older searches, and back easily:
:copen
:colder " goes to older
:cnewer " newer
You can have another search using lvimgrep (uses location window):
:lopen
:lnext
etc...
It also has history:
:lolder
:lnewer
You can read into any buffer:
:r!grep bla **/*.cs
Finally, any command that gives output, can be redirected with the redir command:
:redir >> file
:grep bla **/*.cs
:redir END
See :he redir for the many ways to use it (redirect into registers or variables).
I thought that :grep results were stored by default in the quickfix window.
Try to use :copen after running a grep command. I expect that you'll find your results there.
( :cclose to close the quickfix window)
It is not really a buffer, but as long as you are not starting another search your result list will stay intact.
You can "yank" the content of the quickfix window to a new buffer.
Go into quickfix with :copen
Yank its content with yG
open a new buffer with :new
Paste the content with p
Save it with :w Process1.txt
Repeat and rinse for multiple search/process.
#romainl 's answer on how grep results into separate buffer or split window gives a much cleaner answer than quickfix/location lists.
:vnew | 0r!grep foo #
:tabe | 0r!grep foo #
but Quickfix lists are sort of intended for what you are doing but not the way you are doing it; however, it's tedious to set up unless it's a recurrent task.

Execute shell command without filtering from Vim

I want to select a block of text (for example, V%) and use the text as input to a shell command (for example, wc or pbcopy) - but I don't want to alter the current buffer - I just want to see the output of the command (if any) then continue editing without any changes.
Typing V%!wc translates to :'<,'>!wc and switches the block of text for the output of the wc command.
How do you pipe a chunk of text to an arbitrary shell command without affecting the current buffer?
Select your block of text, then type these keys :w !sh
The whole thing should look like:
:'<,'>w !sh
That's it. Only took me 8 years to learn that one : )
note: typing : after selecting text produces :'<,'> a range indicating selection start and end.
Update 2016: This is really just one use of the generic:
'<,'>w !cli_command
Which basically lets you "send" arbitrary parts of your file to external commands and see the results in a temporary vi window without altering your buffer. Other useful examples would be:
'<,'>w !wc
'<,'>w !to_file my_file
I honestly find it more useful to alter the current buffer. This variety is simply:
'<,'>!wc
'<,'>!to_file my_file
One possibility would be to use system() in a custom command, something like this:
command! -range -nargs=1 SendToCommand <line1>,<line2>call SendToCommand(<q-args>)
function! SendToCommand(UserCommand) range
" Get a list of lines containing the selected range
let SelectedLines = getline(a:firstline,a:lastline)
" Convert to a single string suitable for passing to the command
let ScriptInput = join(SelectedLines, "\n") . "\n"
" Run the command
let result = system(a:UserCommand, ScriptInput)
" Echo the result (could just do "echo system(....)")
echo result
endfunction
Call this with (e.g.):
:'<,'>SendToCommand wc -w
Note that if you press V%:, the :'<,'> will be entered for you.
:help command
:help command-range
:help command-nargs
:help q-args
:help function
:help system()
:help function-range
Update: my answer is nonsense.
#pixelearth's answer is good, but I had a little trouble understanding what he did exactly, so I wrote the following. This sequence of commands let's you execute wc -l on your visual selection. wc -l simply counts the number of lines passed to it.
In Vim go into Visual Mode using v
Select a few lines by going down: jjjj
Type : which Vim will translate to :'<,'>
Type w !wc -l, your complete commandline should now be :'<,'>w !wc -l
Press Enter to get the result of your command (in this example it would be 4)
Press Enter to continue editing
I don't understand what exactly happens at step 3 and 4 but I do know that it works.
I know it's not the ideal solution, but if all else fails, you could always just press u after running the command to undo the buffer change.

Variable that holds "list of all open buffers" in Vim?

:vimgrep looks like a really useful thing.
Here's how to use it:
:vim[grep][!] /{pattern}/[g][j] {file} ...
:help says that you can essentially glob {file} to name, say, *.c for the current directory. I may have started Vim with a list of files that is complicated enough that I don't want to manually type it in for {file}, and besides Vim already knows what those files are.
What I would like to do is vimgrep over any of:
:args
:files
:buffers
What variable(s) would I use in place of {file} to name, respectively, any of those lists in a vimgrep command?
Can't you catch the result in these commands into a register (:h :redir), and insert it back into :vimgrep call (with a :exe).
Something like:
:exe "vimgrep/pattern/ " . lh#askvim#Exe(':args')
Notes:
lh#askvim#Exe is just a wrapper around :redir ; nothing really complex
some of these results may need some processing (see :args that adds square brackets)
Sometimes there is a function that returns exactly what you are looking for, see join(argv(), ' ') in :args case
Regarding :buffers, may be something like:
.
function BuffersList()
let all = range(0, bufnr('$'))
let res = []
for b in all
if buflisted(b)
call add(res, bufname(b))
endif
endfor
return res
endfunction
:exe 'vimgrep/pattern/ '.join(BuffersList(),' ')
You can do this:
:bufdo vimgrep /pattern/ %
% substitutes the buffer name.
To [vim]grep the list of files in the argument list, you may use ## (see :help cmdline-special).
:vimgrep /re/ ##
I am unaware of a similar shorthand for the buffer list, but you may be able to do something like:
:argdelete ##
:bufdo argadd %
... and then use ##. Or use :n to open new files (which will be added to the arg list) instead of :e.
Here is a slightly refined version of one of the answers. The following command searches for the pattern in all opened tabs and remembers results in quickfix list:
:cex [] | tabdo vimgrepa /pattern/ %
cex [] sets contents of quickfix list to empty list. You need to call it first because vimgrepa accumulates search results from all the tabs. Also, you can replace tabdo with argdo, bufdo and windo.
To view search results execute:
:cope
This method, however, has limitation: it can only search in tabs which already have file names assigned to them (% would not expand in a new tab).
EDIT:
You can also shortcut the command into function in your ~/.vimrc like this:
function TS(text)
exe "cex [] | tabdo vimgrepa /" . a:text . "/ %"
endfunction
command -nargs=1 TS call TS(<q-args>)
cnoreabbrev ts TS
With last line you can call your function like this:
:ts from game import
where words after ts is a search pattern. Without last line you have to type function name in upper case.
Very helpful script !
A minor fix: The search finds one of the buffers twice - first time as the numbered buffer, second as buffer #0 => alternate buffer.
Hence, we shall change the line to "range(1, bufnr('$'))" to skip the alternate buffer and show the search results once.

Resources