I am using vim to edit a huge file-I want to replace the 100th occurence of 'Luke' with 'The chosen one'. I searched the Internet for a possible solution and I guess I should do somethink like /Luke and then hitting the 'n' key 99 times, but I find this a bit tedious. Is there any easier way to get this done?
next supports a count
99n
should do
Otherwise, you could play with :global (it's a little bit overkill)
:let c = 0
:g/Luke/let c+=1|if c==100|s//This one!/|endif
You can script something, using feedkeys() function and using :s commadn with the "c" flag. On the mailinglist, this was once suggested.
Related
I'm wondering if there exists an event or option in vim that detects if there are currently words being highlighted as the result of user doing searching (for example, with :/).
Basically, my Vimscript wants to do something like:
if (search highlight is turned on) and (there is at least one match)
find out the total number of matches
find out the index of current match
Any idea? Thanks.
P.S. The reason why I want this is because whenever I do a search, I have to pay attention to the line number change on the side to be able to tell if the search has reached the bottom of the file. I'd like some sort of indication, maybe on the status bar, that the current occurrence (highlighted word) is, for example, 5/20 out of all occurrences in the file.
There's already a plugin that does this: IndexedSearch: shows 'Nth match out of M' at every search (index of match+total # matches).
Also, have a look at my SearchPosition plugin; it has to be triggered via a mapping, but then shows a lot of information about the (current and overall) matches.
:h v:hlsearch
That variable tells you whether search highlighting is on.
if v:hlsearch && search(pattern, 'cn')
// do stuff
endif
Edit: Updating answer
In order to get the number of matches, one crude way of doing it would be :
redir => num_matches
:%s/pattern//n
redir END
Now the variable num_matches holds the output of :%s/pattern//gn, you can parse it.
Another probably more reliable way to get it would be to actually use search(pattern, 'c') and cycle through all the matches within a loop until you come back to the first, which would give you your desired data.
I like your idea and have coded a solution for it. It has to do a fair bit of work in Vimscript, but it actually runs reasonably well on a 8000-line file.
Suggestions if you want to try this yourself:
It triggers a function call on CursorHold. My function checks to see if we are currently on a match line:
let this_line = getline('.')
if match(this_line, #/) >= 0
...
If we are, then I loop through all the lines in the file, using match() to count the number of matching lines, and find the index of the current occurrence. The only other function I had to use was line().
I will push my script up soon, but this might be enough for you to work with. Thanks for the idea!
Update: Although searching the whole file is quite a lot of work, it seems to perform quite well on a modern machine. In the current version, I only trigger the search when the cursor is on the start of a match, and only if the number of lines in the buffer is below a threshold (default 10,000).
Update: My script is at show_search_occurrence.vim
I have numbers in the shape of (a/b) where a and b are integers. I would like to replace them with something like rat(a,b). Is that possible?
I would do:
%s#\v(\d+)/(\d+)#rat(\1,\2)#g
Vim is good at Search and Replace:
:%s/(\(\d\+\)\/\(\d\+\))/rat(\1,\2)/g
Too much backslashs! Yet another command:
:%s#\v\((\d+)/(\d+)\)#rat(\1,\2)#g
We can use # to separate patterns instead of /.
The very magic \v makes life easier.
I suggest you type :help :s to learn more.
The easier way to do this is probably to create a macro and replay it as many times as you need to.
press on qa then make the search & replace stuff
press q when done
then play the macro with #a
If you know regex, then you can go to Search patterns http://vim.wikia.com/wiki/Search_patterns
In a large buffer, I'd like to scroll down to the last occurrence of pattern pattern.
If I am at the first occurrence, it is easy enough to search for the pattern /, reverse the move to next occurrence n with N and get to the last..
If I am in the middle of a sequence of occurrences.. is there a better way to jump?
An easy way to find the last occurrence is to jump to the end and search backwards:
G?foo<CR>
In fact, there's an even easier way if you were already searching for something. Just jump to the end and search backwards for the thing you were just searching for:
GN
Simple as that.
Edit: if your search occurred on the very last line, then GN would skip over it to the second last occurrence. Using ggN would solve this problem. (And gg?foo<CR> for similar reasons.)
A potentially longer solution:
:vim foo % | clast
You can try searching backward via ?
:1?SEARCH_PHRASE
Another solution is:
G/\(.\{-}\zs\(foo\)\)\{1,}<CR>
I'm getting more and more comfortable with Vim after a few months.
BUT, there is only one simple feature I can't get any answer from the web. That is "Search and replace the results". The problem is that I know:
:/keyword to search, and hit enter "keyword" will be highlighted (of course with set hlsearch)
n, or N to navigate
:% s/keyword/new_keyword/g to replace all occurences of keyword with new_keyword.
BUT, I would think that there must be a way to search, and replace the matched keyword (highlighted) with any new_keyword WITHOUT doing ":% s/keyword/new_keyword/g", which is a lot of typing considering search & replace is such a day-to-day feature.
Any answers/comments will be greatly appreciated!
If you've already done a search you can do a substitution for the same pattern by simply leaving out the pattern in the substitute command. eg:
/keyword
searchs for "keyword", and then:
:%s//new_keyword/g
will replace all occurrences of "keyword" with "new_keyword".
Searching and using the dot command (you didn't meantion you are using the dot command, that's why I highlight it) to repeat the last input action is my best bet here.
I use s///g for search and replace.
Well, since #keyword# and #new_keyword# account for most of the characters, and you need some way to differentiate between them (i.e., a character in vim, or tab between entry fields in dialog in a different editor), you're left with maybe four or five keystrokes beyond that.
So I think you're probably overestimating number of keystrokes and also forgetting that (1) it becomes very natural, and (2) working this way allows you also to naturally modify the action performed by specifying a different range or option flag.
But you can cut down on keystrokes. If you want you can map a key to automatically bring up the command line with '%s/' already in place. e.g.:
nmap s :%s/
The command above would remap 's' (I'm not recommending remapping to that key, but it gives the idea) and set you up to insert the keyword.
Also, you can set the 'gdefault' option to default to substituting multiple times per line. This lets you skip the ending '/g' in your keystrokes:
set gdefault
See ':h gdefault' for help section on that option.
In the end I would say just get used to the default way it works, because using it that way allows you to keep same basic operation when you want to specify different ranges or option flags, and creating a new special map is just another thing to remember. gdefault may be worth setting if you think you're going to want it majority of time, adding /g flag at end when gdefault is set has effect of turning /g off. . .
Move to the first highlighted word then record a macro for replacing the word and moving to the next one, e.g:
gg
n
qq
caw new_word^[
n
q
#q
##
##
...
For example if I have some code like:
foo = bar("abc", "def", true, callback);
Is there a nice command to move true to the 1st or 2nd position leaving the commas intact?
P.S as a bonus my friend want to know if this works in Emacs too.
In Vim if you place the cursor at the start of the first word and do dWWP then it will have the desired effect. Here is a breakdown:
dW delete the current word, including the comma and the following whitespace
W move to the start of the next word
P insert the deleted text before the cursor
This will work if there are further parameters after the pair to be swapped - it will need to be modified if there are only two parameters or you want to swap the last two parameters, since it will paste the text after the closing bracket.
Alternatively you could use a regex substitution:
:%s/(\([^,]\+\),\s*\([^,)]\+\)/(\2, \1/
This will find the first two arguments after the open bracket and swap them.
update:
A search of vim.org found the swap parameters plugin, which should do exactly what you want and can handle situations that either of the above methods cannot.
I don't know the answer for vi, but in Emacs, transpose-sexps (C-M-t) will swap two arguments either side of the cursor. Actually transpose-words (M-t) was my first guess, but that leaves the quotes behind.
You need a transpose emacs command. But its limited to not guessing that its transposing in lists, it only considers text (it can't guess the 1st, 2nd word of list). Try this.
Keep your cursor at after comma of true. Use M-x transpose-words. By default it will transpose with next word from the point. Shortcut is M-t.
You can use C-u 2 M-t for transpose with next second word.
Now coming to your question. If you want to move true, to backward 1 word, use C-u -1 M-t, and for backward 2 words C-u -2 M-t.
Am not a VIM guy. So sorry bout that.
If you want to do this as a refactoring, not just as text manipulation, I'd suggest looking into Xrefactory, a refactoring tool for Emacsen (free for C/Java, commercial for C++).
Transposing previous (Ctrl-t p) and next (Ctrl-t n) argument ... add the
following into your .vimrc file:
map <C-t>p ?,\\|(<CR>wd/,\\|)<CR>?,\\|(<CR>"_dw?,\\|(<CR>a, <C-c>?,<CR>P/,<CR>w
map <C-t>n ?,\\|(<CR>wv/,<CR>d"_dw/\\,\\|)<CR>i, <C-r>"<C-c>?,<CR>?,\\|(<CR>w