Can I write a script to tell me which files are currently being edited in vim? - vim

I'm using tmux with many windows, and I frequently lose track of which files I'm editing in vim. I'd like to have another shell open that runs a script that tells me the paths of files that vim is currently editing.
I'm running Mac OS.

The way I would tackle the problem is to query all remote Vim processes for their opened buffers. You can use Vim's clientserver functionality for that. The GVIM server names are usually sequentially named: GVIM, GVIM1, ...; for terminal Vim, you'd have to name them with the --servername argument (e.g. via a shell alias).
You can then query the list of open files via the --remote-expr argument. A simple expression to loop over all listed buffers (like what the :ls command shows) is:
map(filter(range(1, bufnr('$')), 'buflisted(v:val) && ! empty(bufname(v:val))'), 'bufname(v:val)')
As you can see, it's a bit involved and might affect your workflow of launching Vim. Think hard whether you really need this!

That I know of there is no way to get every open vim buffer from an external process. Instead of using separate tmux layouts and a separate instance of vim to edit multiple files, you could have one instance of vim and edit multiple separate files using :split and :tabnew. Then in that vim instance you can use :ls to see the paths of all open files relative to the current working directory. :pwd also works.
If this isn't your style and you'd still like to use vim in separate layouts, you can use ps to see the arguments to each vim process and check the cwd of these processes. Something like:
paste <(pgrep vim | xargs pwdx) <(pgrep vim | xargs ps -o %a | sed 1d)
Note that if you use multiple buffers in vim the above won't quite work because it will only list the arguments given to each vim command and not list the actual buffers.

You could tweak around with the piped commands ps -eF | grep vim for your script.
At the end of each line, of the result, you'll see you the different processes dealing with anything related to 'vim'. Therefore you'll find which files are currently being edited by vim('vim foo.txt' for instance), as well as 'grep vim' that was being active to get this result. To have a pretty output, you'd have to filter all of these with a script.
I hope this will help you.

Related

need to write a script to change file format from dos to unix

I have to make a script using vim which opens a file, set the fileformat=unix, and then save the file and exit. Could you please help? Thanks
First, check out whether you have a dos2unix or dos2ux command; it already does this for you.
With Vim, this should do the job:
$ vim -c "wq ++ff=unix" filename
This one in-lines the fileformat change with the :w command; of course, you can also do this separately via -c "set ff=unix".
Notes
You can also do this via a variety of tools, e.g. sed, perl, ...; Vim is a quite heavyweight alternative.
This still starts up a full, interactive Vim instance. Have a look at this answer which additional command-line arguments can turn Vim into batch mode.

How to check if it's still in Vim shell mode

In vim, type :sh will switch to shell, and exit can exit the shell and get back to vim. Is there any command to check if it's in vim shell mode? So that I won't accidentally vim to open the same file again. I want to avoid below scenario:
vim myfile > :sh > exit > vim myfile // get warning of another vim instance is editing the same file
These are the normal scenario:
vim myfile > :sh > exit // keep editing
vim myfile > :wq > vim myfile // keep editing
In addition to #a3nm answer, what you can do is
use pstree -h: it will output process tree with current branch highligted and all you need to check is whether there is vim in the highlight.
Another possibility is ps t: it will show all processes using the current terminal and should show vim in a list when you are inside :sh. ps -oargs t may be more useful in case you want to know arguments you ran vim with.
These methods are more reliable because VIMRUNTIME, VIM and MYVIMRC environment variables may be overrided by you in order to do some customizations (BTW, they are defined by vim for use in vimscripts, not by :sh). They also work for other processes that allow you to run a subshell, but do not define any environment variables.
I would also suggest to consider using <C-z> in normal mode or :suspend/:stop in Ex because these use shell vim was launched from instead of creating new. This behavior gives you access to history of commands you typed before running vim and also makes you able to write more complex and time-consuming shell configuration without needing to wait every time.
In case you use <C-z> both methods still work, but first method won’t highlight vim because it will be at the same level (has the same parent) as pstree itself, likely just below or above pstree in graph. This also enables third method: jobs shell builtin.
In order to restore from <C-z> you should use fg (a single % in zsh and bash also works) which is less to type then exit (but more then <C-d>).
The :sh command in vim seems to define the VIMRUNTIME, VIM and MYVIMRC environment variables, so you can just check if they are defined. To do so, you can run echo $VIM, for instance, which should return an empty line in a normal shell and something like /usr/share/vim in a shell run from vim.

Is there a way to configure Vim grepprg option to avoid waiting until the external tool has finished searching?

I am a long time Vimmer. However, I keep switching to shell to make searches. This avoids me to use the quickfix functionality.
The main reason for switching to shell is that when I use grep from inside Vim (with :grep), I cannot follow progress.
Because the code base I search is usually wide, I really appreciate immediate feedback.
It gives me a chance to find out that my search expression is wrong before the full results have been displayed.
This allow me to cancel the search, refine the expression then relaunch the search.
Any hint how to reproduce this pattern inside Vim would be appreciated.
I don't see the same vim behaviour as you. When I run :grep, I still see the results in vim (not in the quickfix) before the search completes (but I cannot do anything until the search is done).
I even tried using no vim settings or plugins:
gvim -u NONE -U NONE
If that's not your behaviour, check your grepprg. Mine is the default:
:verbose set grepprg
grepprg=grep -n $* /dev/null
When I use run grep -e "score" -R /etc I see this output in vim:
:!grep -n -e "score" -R /etc /dev/null 2>&1| tee /tmp/voLcaNS/232
It's possible that your system is missing tee or your vim doesn't use it (I'm using Vim 7.2 on Ubuntu 10.10). tee takes the text passed to it and writes it to a file and to stdout.
If you're looking for a way to have the quickfix get updated with your search results and have vim not block while you're searching, then you could write a script that:
searches with grep as a background process and redirects to a file
every second until grep completes, have vim load the file in quickfix (cgetfile) (you can tell vim to do something from another process with --remote-expr)
You can try my AsyncCommand plugin to get your code started. It does the above, except that it only loads the file when the search is complete.
Are you familiar with ack.vim at all? It doesn't use the quickfix window, but uses a separate buffer in a split. However, it's rather faster results come right back to the vim frame.
This may be due to buffering between grep and tee, not vim itself. To test this theory, run grep from the command-line and pipe the output through tee (i.e. grep <pattern> <files> | tee temp.out). If it behaves the same as you observe within vim, then buffering is occurring.
To work around, install expect (sudo apt-get install expect-dev on Ubuntu 10.10) and grepprg to unbuffer grep -n $* /dev/null. (See Turn off buffering in pipe).
Take a look at :vimgrep in the online documentation. It displays the file name being searched and updates as it goes.
There are three ways to do a search in entire projects.
System command grep(fast, but not working well with Ouickfix list)
=>$ grep -n Example *
Vim internal grep(slow, but have a strong pattern support)
:vim[grep] /{pattern}/[g][j] {file} ...
System plugin ack(perfect)
1 install ack
brew install ack
2 add below configs to your .vimrc
:set grepprg=ack\ --nongroup\ --column\ $*
:set grepformat=%f:%l:%c:%m
3 then you can use grep to call ack in vim like
:grep "object\." app/**/*.rb

Search and replace in Vim across all the project files

I'm looking for the best way to do search-and-replace (with confirmation) across all project files in Vim. By "project files" I mean files in the current directory, some of which do not have to be open.
One way to do this could be to simply open all of the files in the current directory:
:args ./**
and then do the search and replace on all open files:
:argdo %s/Search/Replace/gce
However, when I do this, Vim's memory usage jumps from a couple dozen of MB to over 2 GB, which doesn't work for me.
I also have the EasyGrep plugin installed, but it almost never works—either it doesn't find all the occurrences, or it just hangs until I press CtrlC. So far my preferred way to accomplish this task it to ack-grep for the search term, using it's quickfix window open any file that contains the term and was not opened before, and finally :bufdo %s/Search/Replace/gce.
I'm looking either for a good, working plugin that can be used for this, or alternatively a command/sequence of commands that would be easier than the one I'm using now.
The other big option here is simply not to use vim:
sed -i 's/pattern/replacement/' <files>
or if you have some way of generating a list of files, perhaps something like this:
find . -name *.cpp | xargs sed -i 's/pattern/replacement/'
grep -rl 'pattern1' | xargs sed -i 's/pattern2/replacement/'
and so on!
EDIT: Use cfdo command instead of cdo to significantly reduce the amount of commands that will be run to accomplish this (because cdo runs commands on each element while cfdo runs commands on each file)
Thanks to the recently added cdo command, you can now do this in two simple commands using whatever grep tool you have installed. No extra plugins required!:
1. :grep <search term>
2. :cdo %s/<search term>/<replace term>/gc
3. (If you want to save the changes in all files) :cdo update
(cdo executes the given command to each term in the quickfix list, which your grep command populates.)
(Remove the c at the end of the 2nd command if you want to replace each search term without confirming each time)
I've decided to use ack and Perl to solve this problem in order to take advantage of the more powerful full Perl regular expressions rather than the GNU subset.
ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'
Explanation
ack
ack is an awesome command line tool that is a mix of grep, find, and full Perl regular expressions (not just the GNU subset). Its written in pure Perl, its fast, it has syntax highlighting, works on Windows and its friendlier to programmers than the traditional command line tools. Install it on Ubuntu with sudo apt-get install ack-grep.
xargs
Xargs is an old unix command line tool. It reads items from standard input and executes the command specified followed by the items read for standard input. So basically the list of files generated by ack are being appended to the end of the perl -pi -E 's/pattern/replacemnt/g' command.
perl -pi
Perl is a programming language. The -p option causes Perl to create a loop around your program which iterates over filename arguments. The -i option causes Perl to edit the file in place. You can modify this to create backups. The -E option causes Perl to execute the one line of code specified as the program. In our case the program is just a Perl regex substitution. For more information on Perl command line options perldoc perlrun. For more information on Perl see http://www.perl.org/.
Greplace works well for me.
There's also a pathogen ready version on github.
maybe do this:
:noautocmd vim /Search/ **/*
:set hidden
:cfirst
qa
:%s//Replace/gce
:cnf
q
1000#a
:wa
Explanation:
:noautocmd vim /Search/ **/* ⇒ lookup (vim is an abbreviation for vimgrep) pattern in all files in all subdirectories of the cwd without triggering autocmds (:noautocmd), for speed's sake.
:set hidden ⇒ allow having modified buffers not displayed in a window (could be in your vimrc)
:cfirst ⇒ jump to first search result
qa ⇒ start recording a macro into register a
:%s//Replace/gce ⇒ replace all occurrences of the last search pattern (still /Search/ at that time) with Replace:
several times on a same line (g flag)
with user confirmation (c flag)
without error if no pattern found (e flag)
:cnf ⇒ jump to next file in the list created by the vim command
q ⇒ stop recording macro
1000#a ⇒ play macro stored in register a 1000 times
:wa ⇒ save all modified buffers
* EDIT * Vim 8 way:
Starting with Vim 8 there is a better way to do it, as :cfdo iterates on all files in the quickfix list:
:noautocmd vim /Search/ **/*
:set hidden
:cfdo %s//Replace/gce
:wa
Populate :args from a shell command
It's possible (on some operating systems1)) to supply the files for :args via a shell command.
For example, if you have ack2 installed,
:args `ack -l pattern`
will ask ack to return a list of files containing 'pattern' and put these on the argument list.
Or with plain ol' grep i guess it'd be:
:args `grep -lr pattern .`
You can then just use :argdo as described by the OP:
:argdo %s/pattern/replacement/gce
Populate :args from the quickfix list
Also check out nelstrom's answer to a related question describing a simple user defined command that populates the arglist from the current quickfix list. This works great with many commands and plugins whose output ends up in the quickfix list (:vimgrep, :Ack3, :Ggrep4).
The sequence to perform a project wide search could then be done with:
:vimgrep /pattern/ **/*
:Qargs
:argdo %s/findme/replacement/gc
where :Qargs is the call to the user defined command that populates the arglist from the quickfix list.
You'll also find links in the ensuing discussion to simple plugins that get this workflow down to 2 or 3 commands.
Links
:h {arglist} - vimdoc.sourceforge.net/htmldoc/editing.html#{arglist}
ack - betterthangrep.com/
ack.vim - github.com/mileszs/ack.vim
fugitive - github.com/tpope/vim-fugitive
One more option in 2016, far.vim plugin:
1. :grep <search term> (or whatever you use to populate the quickfix window)
2. :cfdo %s/<search term>/<replace term>/g | update
Step 1 populates the quickfix list with items you want. In this case, it's propagated with search terms you want to change via grep.
cfdo runs the command following on each file in the quickfix list. Type :help cfdo for details.
s/<search term>/<replace term>/g replaces each term. /g means replace every occurrence in the file.
| update saves the file after every replace.
I pieced this together based upon this answer and its comments, but felt it deserved its own answer since it's all in one place.
If you don't mind of introducing external dependency, I have brewed a plugin ctrlsf.vim (depends on ack or ag) to do the job.
It can format and display search result from ack/ag, and synchronize your changes in result buffer to actual files on disk.
Maybe following demo explains more
Make sure you’re using Neovim (or Vim 7.4.8+, but really just use Neovim)
Install FZF for the command line and as a vim plugin
Install Ag, so that it’s available automatically to FZF in vim
If using iTerm2 on OSX, set the alt/option key to Esc+
Usage
Search the text you want to change in the current directory and it’s children with
:Ag text
Keep typing to fuzzy filter items
Select items with alt-a
Deselect items with alt-d
Enter will populate the quickfix list
:cfdo %s/text/newText/g | :w
Now you have chabges made inside Vim NeoVim
source
You can do it with shell and vim's ex-mode. This has the added benefit of not needing to memorize other search-and-replace escape sequences.
Any command that can list files will work (rg -l, grep -rl, fd...). For example in bash:
for f in $(rg -l Search); do
vim -Nes "$f" <<EOF
%s/Search/Replace/g
wq
EOF
done
You can use any command, those prefixed with : in command mode, the same way you would inside vim, just drop the : at the start
I think that is because you have a huge amount of files been captured in memory. For my case, I do this by group files in different types, for example:
:args **/*.md
argdo <command>
:args **/*.haml
argdo <command>
Basically, I wanted the replace in a single command and more importantly within vim itself
Based on the answer by #Jefromi i've created a keyboard shortcut, which I had set in my .vimrc file like this
nmap <leader>r :!grep -r -l * \| xargs sed -i -e 's///g'
now from the vim, on a stroke of leader+r I get the command loaded in vim, which i edit like below,
:!grep -r -l <find> <file pattern> | xargs sed -i -e 's/<find>/<replace>/g'
Hence, I do the replace with a single command and more importantly within vim itself

what is the load order of scripts when you start up vim?

If you start up vim with something like this:
vim -S myscript.vim file.txt
What is the load order of scripts? Does myscript.vim get loaded after or before ~/.vimrc.
If you pass in vimscript commands to vim directly on the command line, when do they get executed relative to sourced and default vimscripts?
I believe vimrc is always first. You can run :scriptnames to get a list of sourced scripts in order in which they were first sourced in your Vim instance.
The help entry is way too long to post here, but it lists the order of everything that vim does at initialization. See :help initialization.
The answer is myscript.vim gets loaded dead last.
The vim -V option is a lifesaver here. (Capital -V, because -v starts in vi mode.) Just ran across it, after searching further since although the other answers answered your question, they don't show what wasn't sourced because it wasn't found. If I could send it back in time, I'd save myself a lot of time banging my head against strace output.
This will not only show you all of the scriptnames that it did source in order, but also all of the scriptnames that it would have sourced if they existed in order. So, you can discover what files you can create to load at the appropriate time.
$ vim -V
Adding it to your vim arguments easily answers the question.
$ vim -V -S myscript.vim file.txt
It shows myscript.vim as dead last.
It prints a ton, and winds up at a "Press ENTER or type command to continue" prompt, which lets you step through Autocommands.

Resources