Vim: Search in Open Buffers - vim

One features I like with Visual Studio is the ability to search in open files only. For example, if I recently did changes to some files and I would like to trace those changes, I might search for a certain word, but only in those files to avoid getting a large list of necessary matches.
Is this possible with Vim?! What I am interested in is being able to open the files I have changed so for using:
gvim `git diff --name-only`
then search those files for what I want.

A nice way to do that is to use vim's internal grep command (:vim):
:vim /pattern/ `git diff --name-only`
:copen
This will open a small window (called quickfix) with the search results and links to open the corresponding files (they don't have to be open).

If you want vim to open up all the files in their own buffers for files that match your diff, you could try this:
gvim $(grep -l pattern $(git diff --relative --name-only))
git diff --relative --name-only shows the changed files in the index but with filenames relative to the current working directory.
grep -l pattern <list of files> will report the filenames that contain a match on pattern. (Note that the pattern just has to exist in the files, not in the git diff output.)
POSIX $() instead of backticks makes using nested commands possible.

Related

I need to rename multiple files by removing the multiple dates prefixing the files

I accidently renamed all of my files by adding a prefix multiple times to each directory. I have tried the "rename" command and some peal scripting but I still can't resolve name changes. Any ideas on how to remove all the dates at once so that I just have directory?
Example
mv 2020-11-30-2020-11-30...2020-11-30-Documents Documents/
mv 2020-11-30-2020-11-30...2020-11-30-Documents Documents/
Assuming your filenames don't contain linebreak, quotes. or other special chars:
\ls -1|sed 's/.*-\(.*\)/mv "&" "\1"/'
You can check the output produced by the above command, if it looks good, pipe the output to |sh
NOTE: the backslash before ls is for ignoring your alias if you had ls alias.
These commands both worked:
ls -1 | sed 's/.*-\(.*\)/mv "&" "\1"/'
rename 's/2020-11-30-//g' 2020-11-30-*
Here is a solution which does not require the use of regex. Based on vimv and the multi-cursor edition in Vscode:
Both packages are shipped in most Linux distributions:
apt install vimv codium
Open a terminal and setup codium as your editor: export EDITOR="codium -w"
Browse the terminal in the appropriate folder and type vimv. Hit enter
Vscodium opens, and shows the list of files and folders
Add cursors where you want. Quoting from the doc:
You can add secondary cursors (rendered thinner) with Alt+Click. Another
common way to add more cursors is with Shift+Alt+Down or Shift+Alt+Up
that insert cursors below or above.
Delete whatever you want, save the file, and exit
The files and folders should be renamed accordingly
Checkout the website of vimv for more informations and screencasts

Find global references to struct element using VIM

I'm working with the Linux Kernel, so I installed ctags and cscope to help me find references. However, there's no way to find references to struct->element.
Then, I installed coc.nvim and ccls to see if that would help, but I'm only getting local references to struct->element.
Is there a way to find global references to a struct element inside of VIM?
Your best bet is probably the quickfix list, which can be set using
:grep
:vimgrep (handy when you only want to search, say, files in the argument list ##)
any tool for which you can configure either the output to match the default quickfix pattern-matching, or vice-versa
In your case, I would either do
vim -q <(git grep '->element')
Or I would use the git-jump script in git’s contrib folder:
git jump grep '->element'
You could also load up certain files you care about with one of
vim my files...
or
:args my files...
And then search those with
:vimgrep /->element/ ##

VIM - Sourcing tags from multiple locations in project

Good day,
I typically work on relatively small (less than 20,000 lines of code) projects that are all self contained within a single directory, have their own Makefile, and are fairly easy to work with.
VIM is my preferred editor, and when I open a project, I typically build the ctags list via a mapping to the F10 key:
map <F10> :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .<CR>
This allows me to jump to the definition of a variable/struct/etc via moving the cursor over the text, and hitting CTRL+], as well as using code completion with a drop-down list via OmniCppComplete.
However, I am now working on a slightly larger project which makes use of LOTS of structures. Furthermore, many of these structures have arrays of other custom structures as members, so code completion is a very useful and important tool for me right now.
I have two paths that include a lot of .C files and .h files, and they may change from machine to machine. On each machine, however, we have an environment variable in our .bashrc file that points to them like so:
SDK_SRC_PLUS_HEADERS=/public/sdk
THIRD_PARTY_SDK=/private/sdk
I would like to be able to have VIM automatically refer to the contents of these additional paths when I attempt to do code completion (via VIM's built-in OmniCppComplete feature), or to jump to the files in these locations when I use CTRL+] in VIM to jump to the definition of a struct, function, variable, etc.
So, for both of the above paths, I cd into them, and generate the tags via ctags -R. Then, I modified my ~/.vimrc file to include additional tags paths, like so:
tags=./tags
tags+=$SDK_SRC_PLUS_HEADERS/tags
tags+=$THIRD_PARTY_SDK/tags
I then cd into my project at /home/user1/projects/test, start VIM, and hit F10 in VIM to index it. However, this does not work at all. In fact, it breaks my ability to even use tags just for the project itself (ie: CTRL+] now does nothing).
Does anyone have any suggestions on how I could have code completion source tags and jump-to-definitions using multiple source directories via environment variables?
Thank you all in advance for your time and assistance!
I wanted to add to the solution provided by #sehe.
This is the final set of changes I made to my .vimrc. The first lines are for adding expanded environment variable paths to my tags variable. The other is for auto-updating tags in the event that I have to update my SDK and don't want to be able to accidentally use out-of-date tags:
" CTAGS tag generation for OmniCppComplete
set tags+=./tags
exec expand("set tags+=$SDK_SRC_PLUS_HEADERS/tags")
exec expand("set tags+=$THIRD_PARTY_SDK/tags")
" Can verify taglist is correct via ":set verbose tags?" command
" Create a mapping to delete the old tags, re-generate them, and use them
map <F10> :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q . \| rm -f $SDK_SRC_PLUS_HEADERS/tags \| ctags -R -f $SDK_SRC_PLUS_HEADERS/tags $SDK_SRC_PLUS_HEADERS/tags \| rm -f $THIRD_PARTY_SDK/tags \| ctags -R -f $THIRD_PARTY_SDK/tags $THIRD_PARTY_SDK/tags \| echo "Done re-generating tags."<CR>
It indeed appears to be the problem that you can't use environment variables inside the tags setting.
I came up with this as a workaround:
:let &tags.=expand(",$SDK_SRC_PLUS_HEADERS/tags")
This might be slightly more friendly:
:exec expand("set tags+=$SDK_SRC_PLUS_HEADERS/tags")

How to do partial search in Linux with locate?

I prefer to seach with locate command but I don't know how to perform a partial search with it.
Suppose I want to search file containing the word libevent. How can I do that?
Locate searches for file names. Not file contents.
The ugly way is to use grep It'll start searching from / directory.
grep -irn 'libevent' /
The better way is to narrow down the suspected directories where this files could exists. Suppose those directories' full paths are /path/to/dir1, /path/to/dir2 etc. Then invoke the following command.
for dir in /path/to/dir1 /path/to/dir2
do
grep -irn 'libevent' $dir
done
The locate command is not searching inside the content of files like grep (and other commands) do. It is simply searching inside file paths.
locate work by using a cache index of file paths, and this index is often updated by the updatedb utility.
addenda
A useful way to search some pattern inside (the content of) some files is to use the ability of zsh or some recent versions of bash to expand the ** file pattern, like e.g.
grep foo ~/gee/**/*.[ch]
with zsh this search inside all files named *.c or *.h under $HOME/gee/ containing foo. I find this feature tremendously useful, and justifying alone the adoption of zsh as my interactive shell. With other shells you might type the much longer
find $HOME/gee -name '*.ch' | xargs grep foo

How can I open several files at once in Vim?

Is there a way to open all the files in a directory from within Vim? So a :command that would say in effect "Open all the files under /some/path into buffers".
Ideally, it would be great to open all the files under a dir recursively.
The command you are looking for is args:
For example:
:args /path_to_dir/*
will open all files in the directory
Why it doesn't work if I want to open all files ending with a certain extension?
I tried
:n ./**.cs
and opens only the files in the currenty directory.
I found the answer.The correct code is :n **/*.cs
For more information :h find
Did you try
:n /some/path/*
It will open all files in /some/path
I don't think it'll open file recursively though.
EDIT
Maybe using ** will open recursively as daf mentionned
A method that doesn't require messing with args is to put the list of files in a text file, and then use the :so command to run the commands in that file.
For example, if you want to open all the files that end in .php in a given directory, first create files.txt containing the list of files, prepended with whatever command you want to use to open them.
sp alpha.php
sp bravo.php
sp charlie.php
Then, within vim:
:so files.txt
If the list of files is large, it's relatively trivial to generate the files.txt file quickly, by redirecting the output of ls to a file, and then using a vim macro to prepend sp before each filename.
This obviously isn't as elegant as using the args and argdo commands, but those commands are also a lot more complicated.
There also might be a way to do this with a single command on the command line, but even after 16 years I still find vim programming to be strange and arcane.
Another way to open files recursively
find . -type f -exec vi {} \;
If you'd like to add to the argument list;
:arga what_you-d_like_to_add
see
:he arga
from/in vim for more information.

Resources