I have a folder with a few header .h files and the .c application file. Many of the #define's in the header file contain lower case names that I would like to replace with capitalized names. I would like it to search through all the files in the directory for an instance of that defined constant and replace it as well.
I could write a macro to do it in the header file alone by selecting all instances of the word, setting to uppercase and going through the file and forcing the rest to be uppercase (also not great because I'm assuming a maximum number of versions of the word in a file with however many n.n.n.n.'s I have)
*NveUn.n.n.n.n.
Desired output is....
Example BEFORE,
//test.h
#define test 0
//test.c
int main(void) {
printf("%d\n\r",test)
}
Example AFTER,
//test.h
#define TEST 0
//test.c
int main(void) {
printf("%d\n\r",TEST)
}
I think this is the case for a refactoring plugin capability, otherwise will be very difficult to tell if a word found in other file places is actually the word we used in #define. This is just an assumption, but there are many videos on youtube about refactoring. Neovim now has treesitter support, which is a different way to parse code, instead of using regex for it.
I am just giving you these links related to the subject:
Refactoring in Vim
https://github.com/autozimu/LanguageClient-neovim
https://www.youtube.com/watch?v=Qb7v1MZSrFc
You can grep all files creating a quickfix list and run something like:
:vimgrep '\v(.define |,)\zstest' **/*.c
:cfdo %s/\v( |,)\zstest/\U&
:cfdo update
Explaining the above commands:
:vimgrep ........ grep a pattern
**/*.c ......... recursive search
\v .............. very magic (avoid many backslashes)
(.define |,) .... search for define + space or comma
\zs ............. start actual matching from this point
test ............ literal test
cfdo ............ Execute {cmd} in each file in the quickfix list.
cfdo update ..... write changes to all files
I hope this information could be any useful.
Related
I found here and here how to force Vim spell checker to ignore words with capital letters from being check. But my case is quite opposite. I want to ignore words that in corrected form include capital letters.
So in sentence:
europe was chozen best
only word chozen is the wrong one.
How to achieve that?
Thanks for any hint.
This answer was posted first by Rich on vi&vim stackexchange:
I don't think that Vim has a setting for this. One workaround is to
create a new spellfile that contains everything in your current spell
file(s) but with lowercase letters only:
Create a new buffer containing everything from the spell file(s) currently in use:
:spelldump
Delete lines that don't contain any upper-case characters. This isn't strictly necessary, but there's no point keeping duplicate
entries for lower-case words:
:v/\u/d
Convert the entire file to lower-case, ignoring lines that contain the locations of the spell files:
:v/^#/norm gu$
Save the file:
:w ~/.vim/spell/lowercase.utf-8.add
Start using this file in addition to the standard files in Vim's $VIMRUNTIME directory. Note that Vim uses a default 'spellfile'
value internally if the setting is empty, so if you already have any
existing spell files, you will need to ensure that they are included
in this setting (which accepts a comma-delimited list):
:set spellfile=~/.vim/spell/lowercase.utf-8.add
Note that if you set this option in a running instance of Vim, it
doesn't seem to take effect for spell-checking until you interact with
it (by, e.g. using the zg command.)
The above doesn't affect the way that Vim detects lower-case words at
the start of a sentence as spelled incorrectly. You can disable this
with the 'spellcapcheck' option:
:set spellcapcheck=
Apologies if this has been posted already, for I cannot find an answer, even on the vim wiki.
Is there a way I can run multiple commands in vim command-line mode off of a single :g search?
For example,
:%g/foo/ s/bar/\=#a/g | exe "norm /cat\<enter>\"ayiw"
Which (for what I intend it to do) should, on every line matching foo, replace bar with the contents of register a, and then find the next iteration of cat (even if it is many lines ahead), and put the surrounding word into register a.
Instead, this specific syntax completes the subsitution command using the current contents of the initial a register, and then executes the normal mode command on a single line (after the substitution has been completed).
This example is not my specific use-case but shows one instance where this functionality is useful. I realize I could put it all into a single exe, i.e., %g/foo/exe "norm :s/bar/\\=#a/g\<enter>/cat\<enter>\"ayiw", but I would like to do it the first way, as I feel it is more flexible.
I would prefer to do this using vanilla vim, but if a plugin exists for this, that is an okay alternative. Does anybody know if there is syntax to do such a thing?
Okay a "little bit" dirty, but does this work for you?
:let list = split(execute('g/cat/p'), '\n') | g/foo/ s/bar/\=matchstr(remove(list, 0), '\s\d\+\s\zs.*')/g
It first reads all occurences of cat save them in a list.
Then replace the first bar with the first cat... and so on.
The dirty part ist the matchstr command. the g//p also returns a number for the result so the list looks like this:
1 cat
2 cat
3 cat
...
that's why we have to remove a bit from the front. I would love to hear if someone knows a clean solution for that (I am also interested in a clean vimscript solution, does not have to be a oneliner).
You can do this (at least for multiple :s commands applied to a single :g). Example:
" SHORT STORY TITLES to single word of CapitalizedWords within <h3>s
.,$g/^\L\+$/s/[^A-Z0-9 ]\+//ge|s/\u\+/\L&/ge|s/\<\l\+\>/\u&/ge|s/ \+//ge|s/.*/<h3>&<\/h3>/
What I am trying to do is add #ifdef and #endif before and after of puts.
There are hundreds of puts in the code. The string inside of puts is different in each case. I'm working on this problem with text editors like vim and sublime text 2.
Is there a smarter way of doing such task?
#ifdef SOMETHING
puts("blah blah blah"); ========> puts("blah blah blah");
#endif
Sublime Text:
AFAIR you could use multiple cursors functionality in ST like:
">find_all<, puts, then ctrl+shift+l (or something like that which will give you individual cursor for each highlighted line), then go type required modifications (which will do exact same movement/typing for each line)"
Of course it wouldn't work that well with different indentation and stuff, im afraid...
VIM:
In substitute it should look more or less like this:
:%s/puts(.\{-});/#ifdef SOMETHING\n &\n#endif/g
(though im not sure if something wouldn't need escaping here)
basically it means:
% - for whole file
s - substitute
/first_part/second_part/ - substitute occurence of first_part with second_part
g - globally - meaning for each line found among % (whole file)
and first part is:
normal: 'puts(', then non-greedy (if you don't know what that mean - google for it, really worth to know) regex for any character, then normal: ');' which should match your puts'
and second:
normal: '#ifdef SOMETHING', then newline, then four spaces, then & which means 'found pattern' (basically this puts of yours), then newline, then normal: '#endif'
I wrote it of top of my head so please take into account that some things may need correction (shortcuts in ST or escaping some characters in substitute formula).
Thanks for understanding
I had a situation where I wanted to replace FOO with BAR through out a file. However, I only want to do it in certain places, say, between lines 68–104, 500–537, and 1044–1195. In practice, I dropped markers at the lines of interest (via ma, mb, mc, etc.) and ran the following:
:'a,'b s/FOO/BAR/g | 'c,'d s/FOO/BAR/g | 'e,'f s/FOO/BAR/g
I had to repeat this dozens of times with different search and replace terms s/CAT/DOG, etc., and it became a pain to have to rewrite the command line each time. I was lucky in that I had only three places that I needed to confine my search to (imagine how messy the command line would get if there were 30 or 40).
Short of writing a function, is there any neater way of doing this?
On a related note. I copied FOO to the s (search) register, and BAR to the r (replace) and tried running
:'a,'b s/\=#s/\=#r/ | 'c,'d s/\=#s/\=#r/ | 'e,'f s/\=#s/\=#r/
This would have saved me having to rewrite the command line each time, but, alas, it didn’t work. The replace bit \=#r was fine, but the \=#s bit in the search pattern gave me an error.
Any tips would be appreciated.
If you need to perform a set of line-wise operations (like substitutions) on a bunch of different ranges of lines, one trick you can use is to make those lines look different by first adding a prefix (that isn't shared by any of the other lines).
The way I usually do this is to indent the entire file with something like >G performed on the first line, and then use either :s/^ /X/ commands or block-visual to replace the leading spaces with X on the lines I want.
Then use :g in conjunction with :s. eg:
:%g/^X/s/FOO/BAR/g
:%g/^X/s/BAZ/QUUX/g
Finally, remove the temporary prefixes.
In order to get rid of the necessity to retype the same search
pattern, substitution string and flags, one can simply use the
:& command with the & flag:
:'a,'bs/pat/str/g | 'c,'d&& | 'e,'f&&
(See :help :& for details.)
Instead of using marker use this one :
:68,104s/FOO/BAR/g << substitue from line 68 to 104
This should make your job a little bit easier and clearer.
inspired by #Vdt's answer:
I am not sure but you could write all the substitutions down in a file and source that file i think.
substitutions.vim:
68,104s/FOO/BAR/g
168,204s/FOO/BAR/g
618,644s/FOO/BAR/g
681,1014s/FOO/BAR/g
.
.
.
68,104s/BAZ/BOOO/g
168,204s/BAZ/BOOO/g
and then :so substitutions.vim maybe you can also use this for multiple files of same structure. you can add an e to add an ignore error message, if it is not clear that the substitutions are found on the corresponding line blocks.
With q:, you can recall previous command lines and edit them as a normal Vim buffer, so you can quickly replace FOO and BAR with something else, then re-execute the line with Enter.
The s/\=#s/\=#r/ doesn't work; as you said, this only works in the replacement part. But for the pattern, you can use Ctrl + R Ctrl + R s to insert the contents of register s, instead of \=#s. Preferably use the default register, then it's a simple s//, but you probably know that already.
When performed over a closed fold, substitutions are limited to that fold.
fold each region
put the cursor on one closed fold
perform the substitution: :s/foo/bar<CR>
move to the next closed fold with zj or zk
use the command-line history: :<C-p><CR> or :<Up><CR> to perform the same substitution
repeat…
You can also add the c flag at the end of your substitution so that Vim asks you for a confirmation before actually performing it. This can be tedious if you have lot of matches.
Here's the simplest way to do it
:5,10s/old/new/g
5,10 : startlinenum,endlinenum
I have an XML file like this:
<fruit><apple>100</apple><banana>200</banana></fruit>
<fruit><apple>150</apple><banana>250</banana></fruit>
Now I want delete all the text in the file except the words in tag apple. That is, the file should contain:
100
150
How can I achive this?
:%s/.*apple>\(.*\)<\/apple.*/\1/
That should do what you need. Worked for me.
Basically just grabbing everything up to and including the tag, then backreferences everything between the apple begin and end tag, and matches to the rest of the line. Replaces it with the first backreference, which was the stuff between the apple tags.
I personally use this:
%s;.*<apple>\(\d*\)</apple>.*;\1;
Since the text contain '/' which is the default seperator,and by using ';' as sep makes the code clearer.
And I found that non-greedy match #Conspicuous Compiler mentioned should be
\{-}
instead of "{-}" in Vim.
However, I after change Conspicuous' solution to
%s/.*apple>(.\{-\})<\/apple.*/\1^M/g
my Vim said it can't find the pattern.
In this case, one can use the general technique for collecting pattern matches
explained in my answer to the question "How to extract regex matches
using Vim".
In order to collect and store all of the matches in a list, run the Ex command
:let t=[] | %s/<apple>\(.\{-}\)<\/apple>\zs/\=add(t,submatch(1))[1:0]/g
The command purposely does not change the buffer's contents, only collects the
matched text. To set the contents of the current buffer to the
newline-separated list of matches, use the command
:0pu=t | +,$d_