Indent multiple files with vim from command line - linux

I am trying to indent multiple files with vim. Can I do this without manually opening the files one by one? The following is not working:
for f in `ls`; do vim -c 'gg=G' -c 'wq' $f; done

Related

How to nest commands in -c option of vim

I'm trying to open file with the first line containing foo highlighted, for this I'm using the following command:
vim -c ":execute "normal! gg/foo\<cr>V"" file
Which gives me the output:
Vim: Warning: Output is not to a terminal
Is there any way to fix it? Thanks in advance.
The simplest way would be to use 2 different kinds of quotation marks:
vim -c ':exe "norm! gg/foo\<cr>V"' test.txt
However, for your specific usecase it is even simpler:
vim -c ':1' -c '/foo/norm! V' test.txt

Execute a command within Vim from the command line

Is there a way to execute a Vim command on a file from the command line?
I know the opposite is true like this:
:!python %
But what if I wanted to :retab a file without opening it in Vim? For example:
> vim myfile.c
:retab | wq
This will open myfile.c, replace the tabs with spaces, and then save and close. I'd like to chain this sequence together to a single command somehow.
It would be something like this:
> vim myfile.c retab | wq
This works:
gvim -c "set et|retab|wq" foo.txt
set et (= set expandtab) ensures the tab characters get replaced with the correct number of spaces (otherwise, retab won't work).
I don't normally use it, but vim -c ... also works
The solution as given above presumes the default tab stop of eight is appropriate. If, say, a tab stop of four is intended, use the command sequence "set ts=4|set et|retab|wq".
You have several options:
-c "commands" : will play Ex commands as you entered them in the command line.
In your example : vim myfile -c 'retab | wq'. This is what Firstrock suggested.
-S "vim source file" : will source given vim script
(like running vim -c "source 'vim source file'"):
If you have a file script.vim containing:
retab
wq
Then you can use vim myfile.c -s script.vim (the extension does not really matter)
-s "scriptin file": will play contents of file as it contains normal mode commands: If you have script.txt containing:
:retab
ZZ
with end of lines consisting of a single ^M character (for example you saved the script using the :set fileformat=mac | w), then you can run: vim myfile.c -S script.txt (ZZ is another way to exit vim and save current file).
Note that you can record those scripts with vim my_file -W script.txt, but it suffers a bug if you happen to use gvim (the GUI).
Not a direct answer to your question, but if you want to replace tabs with spaces (or do any other regex search/replace) for a list of files, you can just use in-place sed search/replace:
sed -i 's/\t/ /g' foo1.txt foo2.txt
or
ls *.txt | xargs sed -i 's/\t/ /g'
(In this example I am replacing each tab character with three spaces.)
NOTE: the -i flag means operate in-place.
From the sed man page:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension
supplied)

taking diff between two named files in vim

In my project regression settings, output file have statement like
"diff between foo.txt and bar.txt found"
Now I need to take vimdiff between foo.txt and bar.txt. Can I do it from output file opened in vim only?
currently I need to first open my output file in vim. Then I need to select line specifying diff found. after it return to shell. then take vimdiff b/w this files.
You can do it without opening any new vim instance using the following function:
function s:OpenDiff()
let line=getline('.')
let match=matchlist(line, '\v^\ {4}\"diff\ between\ (.{-})\ and\ (.{-})\ found\"\ $')[1:2]
if empty(match)
throw 'Incorrect line:' line
endif
execute 'tabedit' fnameescape(match[0])
execute 'diffsplit' fnameescape(match[1])
endfunction
nnoremap ,od :<C-u>call <SID>OpenDiff()<CR>
If you add set bufhidden=wipe after each of execute statements you will be able to get rid of opened buffers by running :tabclose.
If you had no file opened or an unmodified buffer:
:edit file1.txt
:vert diffsplit file2.txt
To open diffs in a new tab,
:tabedit file1.txt
:vert diffsplit file2.txt
would be very convenient
To get things automated, I'd consider
diffprogram | grep -w '^diff between' | grep 'found$' |
while read diff between file1 and file2 found;
do
gvim -d "$file1" "$file2"
done
Notes:
doesn't work for filenames with speciall characters (notably whitespace)
To open all these vims simultaneously, just add &: gvim -d "$file1" "$file2"&
You can also get all diffs to open in separate tabs in a single vim:
gvim --servername GVIM --remote-silent +"tabedit $file1" +"vert diffsplit $file2"

Text replace over number of files

I have gotten comfortable using expressions in Vim to do replaces across large files and would like to know what utility program to learn that will allow me to do such a thing across folders of files in a similar fashion.
What command line program for search and replace is most like vims and works across folders?
sed -i.bak 's/foo/bar/g' *
will replace every foo with bar on every line in every file in the current directory in place and creates a backup file with .bak extension.
So I'd look into sed. But... Vim is very capable:
vim -c "bufdo!%s/foo/bar/g" -c "wqa" *
is almost the same.
bufdo! executes the following command (%s/foo/bar/g in this case => replace every foo with bar on every line (% is a special line address for every line)). wqa means: write all then quit. You can specify at most 10 -c switches to Vim, which will be executed in the specified order. So, basically this is Vim automation:
open every file in the current dir => every file has its own buffer
execute the substitution on every buffer
then write the files and quit
The only difference is the lack of backup file creation (which can be achieved easily with some .vimrc settings). But sed is faster.
probably, you should use vim not external command line program. see :help :find or :help :grep
for example, if you want to grep words across folders, pass **/*.txt.
you could do this by combining perl and bash
for example:
find . -type f -name "*.cpp" -print | xargs perl -i -pe 's/pattern/replace/g'
this will find all '.cpp' files starting at '.' and pass (pipe) each of them (the path) to perl command

Vim: open files of the matches on the lines given by Grep?

I want to get automatically to the positions of the results in Vim after grepping, on command line. Is there such feature?
Files to open in Vim on the lines given by grep:
% grep --colour -n checkWordInFile *
SearchToUser.java:170: public boolean checkWordInFile(String word, File file) {
SearchToUser.java~:17: public boolean checkWordInFile(String word, File file) {
SearchToUser.java~:41: if(checkWordInFile(word, f))
If you pipe the output from grep into vim
% grep -n checkWordInFile * | vim -
you can put the cursor on the filename and hit gF to jump to the line in that file that's referenced by that line of grep output. ^WF will open it in a new window.
From within vim you can do the same thing with
:tabedit
:r !grep -n checkWordInFile *
which is equivalent to but less convenient than
:lgrep checkWordInFile *
:lopen
which brings up the superfantastic quickfix window so you can conveniently browse through search results.
You can alternatively get slower but in-some-ways-more-flexible results by using vim's native grep:
:lvimgrep checkWordInFile *
:lopen
This one uses vim REs and paths (eg allowing **). It can take 2-4 times longer to run (maybe more), but you get to use fancy \(\)\#<=s and birds of a feather.
Have a look at "Grep search tools integration with Vim" and "Find in files within Vim". Basically vim provides these commands for searching files:
:grep
:lgrep
:vimgrep
:lvimgrep
The articles feature more information regarding their usage.
You could do this:
% vim "+/checkWordInFile" $(grep -l checkWordInFile *)
This will put in the vim command line a list of all the files that match the regex. The "+/..." option will tell vim to search from the start of each file until it finds the first line that matches the regex.
Correction:
The +/... option will only search the first file for the regex. To search in every file you need this:
% vim "-c bufdo /checkWordInFile" $(grep -l checkWordInFile *)
If this is something you need to do often you could write a bash function so that you only need to specify the regex once (assuming that the regex is valid for both grep and vim).
I think this is what you are looking for:
http://www.vim.org/scripts/script.php?script_id=2184
When you open a file:line, for instance when coping and pasting from an error from your compiler (or grep output) vim tries to open a file with a colon in its name. With this little script in your plugins folder if the stuff after the colon is a number and a file exists with the name especified before the colon vim will open this file and take you to the line you wished in the first place.
It's definitely what I was looking for.
I highly recommend ack.vim over grep for this functionality.
http://github.com/mileszs/ack.vim
http://betterthangrep.com/
You probably want to make functions for these. :)
Sequential vim calls (console)
grep -rn "implements" app | # Or any (with "-n") you like
awk '{
split($0,a,":"); # split on ":"
print "</dev/tty vim", a[1], "+" a[2] # results in lines with "</dev/tty vim <foundfile> +<linenumber>
}' |
parallel --halt-on-error 1 -j1 --tty bash -ec # halt on error and "-e" important to make it possible to quit in the middle
Use :cq from vim to stop editing.
Concurrent opening in tabs (gvim)
Start the server:
gvim --servername GVIM
Open the tabs:
grep -rn "implements" app | # again, any grep you like (with "-n")
awk "{ # double quotes because of $PWD
split(\$0,a,\":\"); # split on ":"
print \":tabedit $PWD/\" a[1] \"<CR>\" a[2] \"G\" # Vim commands. Open file, then jump to line
}" |
parallel gvim --servername GVIM --remote-send # of course the servername needs to match
If you use git, results are often more meaningful when you search only in the files tracked by git. To open files at the given line which is a search result of git grep in vim you will need the fugitive plugin, then
:copen
:Ggrep pattern
Will give you the list in a buffer and you can choose to open files from your git grep results.
In this particular example:
vim SearchToUser.java +170

Resources