Show all matching grep results in new tab in Vim - regex

I am attempting to map a hotkey to do the following in Vim:
Match the current c-word currently marked by the cursor
Generate a list of all found occurrences in current project
Open a new tab showing the results
So, one example I have that uses CTAGS opens the declaration of a variable/function in a new tab like so:
map <C-\> :split<CR>:exec("tag ".expand("<cword>"))<CR>
When it hit CTRL-\, a new tab is opened with the declaration of the variable/function the cursor is on.
The command I am trying to map is shown below:
:lvim /\<\(text_i_want_to_find\)\>/gj *.c
:lw
When I run this command, a new tab is opened showing a list of all .c files containing the text text_i_want_to_find. I need to modify this to do two things different from what it does now:
Search all files with extensions of .c, .h, .cpp, .mk, instead of just .c, and also search files named "Makefile"
Search for the c-word under the cursor like the CTRL-\ mapping I have shown above, as opposed to having to manually type in the text text_i_want_to_find
Here is the code in my .vimrc file for the mapping. I'm not entirely sure if CTRL-/ can be mapped at all, so there's one more problem for me to solve.
map <C-/> :split<CR>:lvim /\<\(.expand("<cword>")\)\>/gj *.c *.h *.cpp *.mk Makefile
Does anyone have any tips on fixing this Vim mapping?
EDIT:
After reviewing the answers provided to me, here's the final version of my code:
command! -nargs=1 SearchAll execute " grep -srnw --binary-files=without-match --exclude={*~,tags} --exclude-dir=.svn . -e " . expand("<args>") . " " <bar> cwindow
map <C-g> :SearchAll <cword><CR>
I mapped it to CTRL+g. I can also invoke it like so as a colon command:
:SearchAll my_text_to_search_for
Hope this helps others as well!

Of course, it does not work: you forgot :execute, :lvimgrep command on its own does not accept expressions, so you are searching for expand("<cword>") that is not followed by a keyword character (\>) and preceded by any character that does not follow keyword character (\<.). \( and \) are useless here. Other notes:
Don’t use map: you need neither this mapping working in visual and operator-pending modes nor ability to use other mappings.
Some patterns can be merged: *.[ch] *.cpp *.mk Makefile or even *.{[ch],cpp,mk} Makefile.
<C-\> can be mapped, but not <C-/> (I hope only currently, but no real work on fixing it is done): \ is 0x5C and <C-\> is 0x5C-0x40=0x1C. But / is 0x2F and 0x2F-0x40<0. On my system pressing <C-/> in terminal transforms into <C-_>, so does <C-->.
:split command does not open a new tab, it opens a new window. Prepend it with :tab to do this.
:lvimgrep is not going to show you the results. It is not either going to jump to the first result unless you remove the j flag.
You forgot final <CR> as well as :lw<CR>. I use :lopen below, in this context they produce just the same result.
You forgot <C-u> after first : or <C-\><C-n> before: it is needed to discard count.
You don’t really need :execute in either of your mappings because there is <C-r>=expand("cword")<CR>, or a default shortcut <C-r><C-w>.
Don’t write :exec(str): it is confusing because :execute is not a function and this syntax encourages others to think it is. Use :execute str.
Thus the final mapping is:
nnoremap <C-\> :<C-u>tab split \| lvimgrep /\V\<<C-r><C-w>\>/gj *.{[ch],cpp,mk} Makefile \| lopen<CR>
. Replace it with
nnoremap <C-\> :<C-u>lvimgrep /\V\<<C-r><C-w>\>/gj *.{[ch],cpp,mk} Makefile \| tab lopen<CR>
if you don’t want to see the current file in a newly opened tab.
Both mappings assume you have neither / nor \ in 'iskeyword' option, if you do replace <C-r><C-w> with <C-r>=escape(expand('<cword>'), '/\')<CR>.

Related

Search for multiple strings in several files with Sublime 3 using AND

This previous (similar) question of mine Search for multiple strings in several files with Sublime 3 was answered with a way to search for multiple strings in multiple files in SublimeText, using the regex OR operator:
Find: (string1|string2)
Where: <open folders>
This works perfectly for searching files where either string1 OR string2 is present. What I need now is to search in lots of files for both strings present. I.e., I need to use the AND operator.
I looked around this question Regular Expressions: Is there an AND operator? and also this one Regex AND operator and came up with the following recipes:
(?=string1)(?=string2)
(?=.*string1)(?=.*string2)
(string1 string2)
(string1\&string2)
but none of them work.
So the question is: how can I search multiple strings in several files at once with SublimeText?
(I'm using SublimeText 3103)
Add: the strings are not necessarily in the same line. They can be located anywhere within each file. For example, this file:
string1 dfgdfg d dfgdf
sadasd
asdasd
dfgdfg string2 dfgdfg
should trigger a match.
Open sublime Text and press
Shift+Ctrl+F
or click on the Find in Files options under Files tab. The above is keyboard shortcut for this option. When you press above key, these are following options
When you select ... button from above, you get 6 options which are Add Folder or Add Open Files or Add Open Folders
To search strings that occur in the same line
Use the following regex for your and operation
(?=.*string1)(?=.*string2)
I am using the following regex
(?=.*def)(?=.*s)\w+ <-- \w+ will help in understanding which line is matched(will see later)
and I am searching within current open files
Make sure the Use Buffer option is enabled (one just before Find). It will display the matches in a new file. Also make sure the Show Context (one just before Use Buffer) option is enabled. This will display the exact line that matches. Now Click on Find on the right side.
Here is the output I am getting
See the difference in background color of line 1315 and 1316(appearing in left side). 1316 is matched line in designation file
This is the image of last part
There were total 6 files that were opened while I used this regex
For finding strings anywhere in file
Use
(?=[\s\S]*string1)(?=[\s\S]*string2)[\s\S]+
but it will kill sublime if number of lines increases.
If there are only two words that you need to find, the following will work super fast in comparison to above
(\bstring1\b[\S\s]*\bstring2\b)|(\bstring2\b[\S\s]*\bstring1\b)

bulk file renaming in bash, to remove name with spaces, leaving trailing digits

Can a bash/shell expert help me in this? Each time I use PDF to split large pdf file (say its name is X.pdf) into separate pages, where each page is one pdf file, it creates files with this pattern
"X 1.pdf"
"X 2.pdf"
"X 3.pdf" etc...
The file name "X" above is the original file name, which can be anything. It then adds one space after the name, then the page number. Page numbers always start from 1 and up to how many pages. There is no option in adobe PDF to change this.
I need to run a shell command to simply remove/strip out all the "X " part, and just leave the digits, like this
1.pdf
2.pdf
3.pdf
....
100.pdf ...etc..
Not being good in pattern matching, not sure what regular expression I need.
I know I need something like
for i in *.pdf; do mv "$i$" ........; done
And it is the ....... part I do not know how to do.
This only needs to run on Linux/Unix system.
Use sed..
for i in *.pdf; do mv "$i" $(sed 's/.*[[:blank:]]//' <<< "$i"); done
And it would be simple through rename
rename 's/.*\s//' *.pdf
You can remove everything up to (including) the last space in the variable with this:
${i##* }
That's "star space" after the double hash, meaning "anything followed by space". ${i#* } would remove up to the first space.
So run this to check:
for i in *.pdf; do echo mv -i -- "$i" "${i##* }" ; done
and remove the echo if it looks good. The -i suggested by Gordon Davisson will prompt you before overwriting, and -- signifies end of options, which prevents things from blowing up if you ever have filenames starting with -.
If you just want to do bulk renaming of files (or directories) and don't mind using external tools, then here's mine: rnm
The command to do what you want would be:
rnm -rs '/.*\s//' *.pdf
.*\s selects the part before (and with) the last white space and replaces it with empty string.
Note:
It doesn't overwrite any existing files (throws warning if it finds an existing file with the target name).
And this operation is failsafe. You can get back the changes made by last rnm command with rnm -u.
Here's a list of documents for rnm.

Can Notepad++ save out search results to a text file?

I need to do quite a few regular expression search/replaces throughout hundreds and hundreds of static files. I'm looking to build an audit trail so I at least know what files were touched by what searches/replaces.
I can do my regular expression searches in Notepad++ and it gives me file names/paths and number of hits in each file. It also gives me the line #s which I don't really care that much about.
What I really want is a separate text file of the file names/paths. The # of hits in each file would be a nice addition, but really it's just a list of file names/paths that I'm after.
In Notepad++'s search results pane, I can do a right click and copy, but that includes all the line #s and code which is just too much noise, especially when you're getting hundreds of matches.
Anyone know how I can get these results to just the file name/paths? I'm after something like:
/about/foo.html
/about/bar.html
/faq/2012/awesome.html
/faq/2013/awesomer.html
/foo/bar/baz/wee.html
etc.
Then I can name that file regex_whatever_search.txt and at the top of it include the regex used for the search and replace. Below that, I've got my list of files it touched.
UPDATE What looks like the easiest thing to do (at least that I've found) is to just copy all the search results into a new text file and run the following regex:
^\tLine.+$
And replace that with an empty string. That'll give you just the file path and hit counts with a lot of empty space between each entry. Then run the following regex:
\s+\n
And replace with:
\n
That'll strip out all the unwanted empty space and you'll be left with a nice list.
maybe you need power of unix tools
assume you have GNUWin32 installed in c:\tools\gnuwin32
than if you have replace.bat file with that content:
#echo off
set BIN=c:\tools\gnuwin32\bin
set WHAT=%1
set TOWHAT=%2
set MASK=%3
rem Removing quotes
SET WHAT=###%WHAT%###
SET WHAT=%WHAT:"###=%
SET WHAT=%WHAT:###"=%
SET WHAT=%WHAT:###=%
SET TOWHAT=###%TOWHAT%###
SET TOWHAT=%TOWHAT:"###=%
SET TOWHAT=%TOWHAT:###"=%
SET TOWHAT=%TOWHAT:###=%
SET MASK=###%MASK%###
SET MASK=%MASK:"###=%
SET MASK=%MASK:###"=%
SET MASK=%MASK:###=%
echo %WHAT% replaces to %TOWHAT%
rem printing matching files
%BIN%\grep -r -c "%WHAT%" %MASK%
rem actual replace
%BIN%\find %MASK% -type f -exec %BIN%\sed -i "s/%WHAT%/%TOWHAT%/g" {} +
you can do regex replace in masked files recursively with output you required
replace "using System.Windows" "using Nothing" *.cs
The regulat expression I use for this kind of problem is
^\tLine.[0-9]*:.
And it works for me
This works well if you have Excel available and want to avoid using regular expressions:
Ctrl+A to select all the results
drag & drop the selected results to Excel
Create a Filter on the 1st row
Filter out the lines that have "(Blank)" on the 1st column
Select the remaining lines (i.e. the lines with the filenames) and copy/paste them to another sheet or any wanted destination
You could also Ctrl+A, Ctrl+C the search results, then use the Paste Option "Use Text Import Wizard" in Excel, say that the data is "Fixed width" and put one single break line after the 2nd character (to remove the two leading spaces in the filename during import), and use a filter to filter out the unwanted rows.

Compounding switch regexes in Vim

I'm working on refactoring a bunch of PHP code for an instructor. The first thing I've decided to do is to update all the SQL files to be written in Drupal SQL coding conventions, i.e., to have all-uppercase keywords. I've written a few regular expressions:
:%s/create table/CREATE TABLE/gi
:%s/create database/CREATE DATABASE/gi
:%s/primary key/PRIMARY KEY/gi
:%s/auto_increment/AUTO_INCREMENT/gi
:%s/not null/NOT NULL/gi
Okay, that's a start. Now I just open every SQL file in Vim, run all five regular expressions, and save. This feels like five times the work it should be. Can they be compounded in to one obnoxiously long but easily copy-pastable regex?
why do you have to do it in vim? how about sed/awk?
e.g. with sed
sed -e 's/create table/\U&/g' -e's/not null/\U&/g' -e 's/.../\U&/' *.sql
btw, in vi you may do
:%s/create table/\U&/g
to change case, well save some typing.
update
if you really want a long command to execute in vi, maybe you could try:
:%s/create table\|create database\|foo\|bar\|blah/\U&/g
Open the file containing that substitution commands.
Copy its contents (to the unnamed register, by default):
:%y
If there is only one file where the substitutions should be
performed, open it as usual and run the contents of that register
as a Normal mode command:
:#"
If there are several files to edit automatically, open those
files as arguments:
:args *.sql
Execute the yanked substitutions for each file in the argument list:
:argdo #"|up
(The :update command running after the substitutions, writes
the buffer to file if it has been changed.)
While sed can handle what you want (hovewer it can be interactive as you requestred by flag 'i'), vim still much powerfull. Once I needed to change last argument in some function call in 1M SLOC code base. The arguments could be in one line or in several lines. In vim I achieved it pretty easy.
You can open all php files in vim at once:
vim *.php
After that run in ex mode:
:bufdo! %s/create table/CREATE TABLE/gi
Repeat the rest of commands. At the end save all the files and exit vim:
:xall

removing m_ prefix from variable names

Initially we planned to have old convention of having m_ prefix for class variables. But now requirement has come to replace all the m_VaribaleName to this.variableName, i.e. remove the m_ and make the first character after m_ lowercase.
I can search and replace m_ with this. but this doesn't rename the variable's first character to lowercase. After search and replace if I use re-factoring tool to rename VariableName to variableName this also renames the property already exists with VariableName.
I am wondering is there any regex, tool, macro to make this task automated.
Resharper will highlight all such errors in a solution, and fix them individually, but I don't think it can fix all of them with a single command. Still, it's easy enough to navigate between errors that it finds.
You can do this in emacs.
Open your file (C-x C-f) and do M-x replace-regexp.
Let's say the name of the variable is Variable.
Your regexp query would replace \(V\)ariable for \,(downcase \1)ariable.
The \, tells emacs the following statement is a lisp expression.
Additionally, if you wanted to replace the m_ at the same time you could do replace m_\(V\)ariable for \,(downcase \1)ariable.
This will take care of all instances in a file at the same time and emacs does remember your last replace-regexp query so you do not have to retype it for multiple files. Furthermore, there is a way using DIRED mode to do the replace-regexp on multiple files at the same time.
Open up a directory on DIRED mode (C-x C-f DIR_NAME), mark the files you want by going over them (you can navigate using n and p) by pressing m. Once the files you want to process are marked press Q (capital-case). You will get the same regexp prompt as if you did a single file, enter the regexp, RET, the replacement, and RET. It will open up each file at a time, press ! for every file to replace all reg-exps in that file.
After that, you still have to save the files. Which you can do with C-s and then !.