I'd like to run some $RANDOM_COMMAND, and have the results opened in ("piped to") the quickfix window (:copen/:cfile). Is this possible, without having to define some commands in vimrc? (Hopefully in some "simple way", i.e. I'd like to be able to memorize this so I can run this on any new random box with vanilla vim that I'll have to login to.)
edit: initially didn't know how to express "simple way" more precisely, but now I know at least partially: I'd much prefer an answer of 1, max 2 lines.
edit2: tried something like below (from this and this):
:call setqflist(split(system('RANDOM_COMMAND'), '\n'))
:copen
but didn't seem to work anyway :/ (and mucho ugly too)
Hmh, found the simplest solution in the end, by reading through the regular vimdoc for quickfix window:
:cex system('$RANDOM_COMMAND') | copen
(the | copen part is optional).
Still, Ingo Karkat's solution can have usability advantage, as on consecutive runs it's enough to run shorter :grep there.
One way to do this:
:set makeprg=$RANDOM_COMMAND
:make
:copen
Or, execute the command and capture the output in a temporary file:
:! $RANDOM_COMMAND > out
:cfile out
:copen
In any way, the output must match with the 'errorformat' setting, so that Vim can parse the file name and line numbers (if you need those; but otherwise, you could just use a scratch buffer as well the quickfix list).
[edit] Some improvements
To make this a oneliner, then somewhat shortened, you can:
:set mp=RANDOM_COMMAND | make | copen
Whitespaces in command must be escaped with backslash; also, the make command can take arguments, which get expanded in place of a $*; a more full-blown example thus:
:set mp=mycommand\ -d\ $PWD\ $* | make myarg | copen
Alternatively, similar thing can be done with :set grepprg and :grep, giving even shorter line:
:set gp=mycommand\ -d\ $PWD\ $* | gr myarg | copen
Related
Some Vim functions work on a range:
:'<,'>TOhtml
What is the syntax for the first command taking a range, and the latter commands pipe the result?
In the comments on the wiki it suggests a plugin to allow the range to be run on by all the commands; but here I only need the first argument to handle the range.
# These are the commands I am attempting to chain
:'<,'>TOhtml
:w! ~/mylink
:q!
# The last two can chain or be one command
:w! ~/mylink | q!
:wq! ~/mylink
# But these fail
:'<,'>TOhtml | wq! ~/mylink
:execute "'<,'>TOhtml" | "wq! ~/mylink"
Using execute is the way to go, but you only have to quote the command for :execute, not the second one.
That is, replace:
:execute "'<,'>TOhtml" | "wq! ~/mylink"
With this:
:execute "'<,'>TOhtml" | wq! ~/mylink
ClothSword, you are not far off the mark. Depending on your VIM settings, there are three expressions that could potentially be used to chain multiple commands on a single line: |, \| and <bar>, as in:
:echom "test 1" | echom "OK"
:echom "test 2" \| echom "OK"
:echom "test 3" <bar> echom "OK"
The way to test which one of them would work for you, would be to run all three of the above commands, followed by :messages. In the output, you should see error messages for the commands that didn't work: Invalid exprecion, Undefined variable, etc... the actual error message is irrelevant. While, for the command that did work, you will see two lines of the output, similar to:
test [number]
OK
There are a couple of pitfall to watch out for when using command chaining:
| behaves differently to what I described above when used to chain multiple system commands, eg: :read !ls | wc
care must be taken when used with :g, :s and :map commands as it may not do what you expect, eg: :%g/foo/p|>, :%s/foo/bar/|> or :nmap 10\| map \ l
NOTE: You could also use <NL> in the same way you use | (can be inserted with Ctrl-V Ctrl-J, which will output ^#). However, this usage is not recommended as it is more inline with chaining external commands.
SEE ALSO: If you want to get a full picture on how command chaining works in VIM then I would recommend you read VIM's manual on :bar (:help :bar) and have a look at the b flag of the cpoption (:help cpoption).
I want to do the following for multiple files using Vim:
Copy all text in each file
Replace some text
Paste the copied text at the end of the each file
Replace some other text
Here are my commands for one file:
:%y
:%s/old1/new1/g
:G
:P
:%s/old2/new2/g
Can anybody tell me the syntax to do so? Especially that I'm new to Vim!
I found out that argdo can execute commands on multiple files. I found many examples to use argdo in replacing text, but I couldn't find the syntax to use argdo with :%y, :G, or :P
Thanks.
Like #ib mentioned, I'd do this with ex commands1
:argdo %y | %s/old1/new1/g | $pu | %s/old2/new2/g
There's also a good chance that you might want to operate on exclusive ranges (do the first substitution only on the first part, and the second only on the second):
:argdo $mark a | %co$ | 1,'a s/old1/new1/g | 'a,$s/old2/new2/g
To allow non-matching substitutions, add s///e and add silent! to make operation much faster in the case of many files.
:silent! argdo $mark a | %co$ | 1,'a s/old1/new1/ge | 'a,$s/old2/new2/ge
1 (note that argdo expects an Ex command list by default. You'd use e.g. argdo norm! ggyG to use normal mode commands)
UPD: my Vim-fu is not as strong as #ib's or #sehe's ones, so you might want to use the solutions they suggested instead of mine one.
But, my solution is easier to edit and to debug personally for me (as a Vim apprentice), so, let it be here anyway.
You can add the following temporary function in your vimrc:
function! MyTmpFunc()
:%y
:%s/old1/new1/g
normal! G
normal! P
:%s/old2/new2/g
endfunction
Then restart Vim with the files you need to affect (something like vim myfile1.txt myfile2.txt myfile3.txt), and execute the following command:
:argdo call MyTmpFunc()
That's what you described in your question: function MyTmpFunc() will be called for each argument given to Vim.
Now you can delete MyTmpFunc() from vimrc.
Be also aware with :bufdo - it calls some command for each opened buffer. There is also :windo, which executes command for each window, but personally I found :bufdo the most useful.
Also please note that you don't have to create temporary function if you need to execute just a single command in the each buffer. Say, if you need just to replace "old1" to "new1" in the each buffer, then you can execute the following command:
:bufdo %s/old1/new1/g
and that's it.
So far I always used EasyGrep for replacing text in multiple files. Unfortunately it is quite slow when a project gets bigger. One thing that seems to be amazingly fast is Ggrep of fugitive.vim that only search my version controlled files. All results are also stored in the quickfix list.
How can I use the results of Ggrep for doing a simple replace over all those found files? Is it somehow possible to use %s/foo/bar/cg on all files in the quickfix list or are there any better ways?
Update:
Vim now has cdo, see Sid's answer.
Original Answer:
Vim has bufdo, windo, tabdo and argdo, which let you perform the same command in all open buffers, windows or files in the argument list. What we really need is something like quickfixdo, which would invoke a command on every file in the quickfix list. Sadly, that functionality is lacking from Vim, but here's a solution by Al that provides a home-rolled solution. Using this, it would be possible to run:
:QFDo %s/foo/bar/gc
And that would run the foo/bar substitution on all files in the quickfix list.
The bufdo, windo, tabdo and argdo commands have some common behaviour. For example, if the current file can't be abandoned, then all of these commands will fail. I'm not sure if the QFDo command referenced above follows the same conventions.
I've adapted Al's solution to create a command called Qargs. Running this command populates the argument list with all of the files listed in the quickfix list:
command! -nargs=0 -bar Qargs execute 'args ' . QuickfixFilenames()
function! QuickfixFilenames()
" Building a hash ensures we get each buffer only once
let buffer_numbers = {}
for quickfix_item in getqflist()
let buffer_numbers[quickfix_item['bufnr']] = bufname(quickfix_item['bufnr'])
endfor
return join(values(buffer_numbers))
endfunction
Using this, you could follow these steps to do a project-wide search and replace:
:Ggrep findme
:Qargs
:argdo %s/findme/replacement/gc
:argdo update
Edit: (with a hat tip to Peter Rincker)
Or you could join the last 3 commands together in a single line:
:Ggrep findme
:Qargs | argdo %s/findme/replacement/gc | update
cdo command has now been added! After you grep, you can use cdo to execute the given command to each term in your quickfix list:
cdo %s/<search term>/<replace term>/cg
(Take a look at this git commit and this vim developers google group discussion for more information on cdo and the motivations behind adding it.)
nelstrom's answer is quite comprehensive and reflects his brilliant contributions to vimdom. It also goes a bit beyond what is strictly needed here; the quickfix step can be omitted in favor of populating args with the result of a shell command:
:args `git grep -l findme`
:argdo %s/findme/replacement/gc
:argdo update
should be all you need.
Edit: as Domon notes, :set hidden must be done first if it's not already set!
Using quickfix-reflector.vim, you can edit your search results in the quickfix window. The write command will then save the changes to your files.
:copen
:%s/foo/bar/cg
:write
External grep
(uses grepprg, grepformat like in makeprg/errorformat; if grepprg=='internal' this is identical to internal grep)
:grep fopen *.c
:copen
:cnext
Internal grep
:vimgrep /\<myVimregexp\>/ **/*.c
:copen
:cnext
etc.
Location list internal grep
:lvimgrep /\<myVimregexp\>/ **/*.c
:lopen
:lnext
etc.
Bonus: doing external grep for the loaded buffers:
:silent bufdo grepadd fstream %
:copen
:cnext
etc.
External for all arguments:
:silent argdo grepadd fstream %
:copen
:cnext
There's a patch to add the cdo (Quickfix do) command to vim, but it has not been pulled yet (as of 2015-03-25):
https://groups.google.com/forum/#!topic/vim_dev/dfyt-G6SMec
You may want to patch vim yourself to get this patch:
brew install hg # install mercurial, e.g. with homebrew
hg clone https://vim.googlecode.com/hg/ vim
cd vim
# copy/download patch to . folder
patch -b -p1 < cdo.diff
./configure
make && make install
I know that using VIM I can format C++ code just using
gg=G
Now I have to format 30 files, so doing it by hand becomes tedious. I had a look how to do it passing external commands to VIM, so I tried
vim -c gg=G -c wq file.cpp
but it does not work.
Can you give me a hint?
Thanks
Why not load all the files up in buffers and use bufdo to execute the command on all of them at one time?
:bufdo "execute normal gg=G"
Change -c gg=G to -c 'normal! gg=G'. -c switch accepts only ex mode commands, gg=G are two normal mode commands.
I prefer a slight change on the :bufdo answer. I prefer the arg list instead of the buffer list, so I don't need to worry about closing current buffers or opening up new vim session. For example:
:args ~/src/myproject/**/*.cpp | argdo execute "normal gg=G" | update
args sets the arglist, using wildcards (** will match the current directory as well as subdirectories)
| lets us run multiple commands on one line
argdo runs the following commands on each arg (it will swallow up the second |)
execute prevents normal from swallowing up the next pipe.
normal runs the following normal mode commands (what you were working with in the first place)
update is like :w, but only saves when the buffer is modified.
This :args ... | argdo ... | update pattern is very useful for any sort of project wide file manipulation (e.g. search and replace via '%s/foo/bar/ge' or setting uniform fileformat or fileencoding).
My problem is simple. I search a specific pattern in a file (let's say label in a Tex file)
:g/label/#
but there are lots of occurrences. So I'd like to redirect this output to another file to be able to work easily with it.
Do you have a trick or a command that I don't know?
it's not clear from the original post what you mean by "work easily with it" but it's often useful to see and quickly jump between all of the matches in a buffer without "extracting" the matches to a separate buffer.
vim has an internal grep built in. your example would be something like this (in vim, % denotes the current file)
:vimgrep /label/ %
This will take you to the first occurrence and report how many matches there were. What's cool is that you can look at all of the matches listed by opening up the quickfix error list using
:cope
Now you can just scroll around and press enter on a line to jump to the exact position of the match.
The quickfix error list is exactly the same buffer you use if you run make from inside vim and your compiler throws errors: it gives you a list of what and where the errors are.
After you've jumped to one location pointed by quickfix, you can go to forwards and backwards in the list via :cn and :cp. :ccl closes the error list.
You can also expand your "error" list via :vimgrepa /newpattern/ % or :vimgrepadd
The (documented) caveat is that vim's internal grep is slower than most native grep implementations (but you do get it "for free" in windows, for example). If you do have a grep installed, you can use :grep instead of :vimgrep for similar results.
quoting :help grep
Vim has two ways to find matches for a
pattern: Internal and external. The
advantage of the internal grep is that
it works on all systems and uses the
powerful Vim search patterns. An
external grep program can be used when
the Vim grep does not do what you
want.
The internal method will be slower,
because files are read into memory.
The advantages are:
- Line separators and encoding are automatically recognized, as if a file
is being edited.
- Uses Vim search patterns. Multi-line patterns can be used.
- When plugins are enabled: compressed and remote files can be searched.
You can also use the location list if you're already using the error list for dealing with compilation errors. just add l (for location) to the beginning of the grep command (:lvimgrep,:lvimgrepa :lgrep, :lgrepa) and use :lopen :ln :lp :lcl instead of the :c* ones.
For more commands consult
:help grep
:help quickfix-window
:help quickfix
:help quickfix-error-lists
:redir > matches.txt|execute 'g/foo/#'|redir END
See :h :redir, you can also redirect to registers, variables, the clipboard etc.
What you're doing is essentially 'grep -n label file' from command line. So you can run that command and > it into a file easily enough.
The derivation of 'grep' is even from basically the same source.
I've gotten this of the net at some point:
function GoToLine(mainbuffer)
let linenumber = expand("<cword>")
silent bd!
silent execute "buffer" a:mainbuffer
silent execute ":"linenumber
silent nunmap <Enter>
endfunction
command -nargs=1 GoToLine :call GoToLine(<f-args>)
function GrepToBuffer(pattern)
let mainbuffer = bufnr("%")
silent %yank g
enew
silent put! g
execute "%!egrep -n" a:pattern "| cut -b1-80 | sed 's/:/ /'"
silent 1s/^/\="# Press Enter on a line to view it\n"/
silent :2
silent execute "nmap <Enter> 0:silent GoToLine" mainbuffer "<Enter>"
" silent nmap <C-G> <C-O>:bd!<Enter>
endfunction
command -nargs=+ Grep :call GrepToBuffer(<q-args>)
Put it in your .vimrc, then :Grep Foo
Requires external grep program to work properly.
(Just an idea -- untested.)
You can delete all the lines with your pattern in it, write to another file, and undo the delete.
:g/label/d
:w matches
u