Is there a equivalent to search the string in the current line similar to * or # which search the current word?
No, but it's easy to make it.
:nnoremap <silent> <Leader>f :execute '/\V\^' . escape(getline('.'), '\\/') . '\$'<CR>
This should give you \f (or whatever you remapped as leader instead of the backslash) that should start the search for the next instance of the current line.
Related
Often when I'm using f to search for characters in the current line, I'll run into more occurrences of the character than I expected so highlighting each search match would be nice.
In the example below, let's say I'm starting at the beginning of the line and am trying to get to e in vowels. It would be helpful to highlight each of those occurrences so that I could get some context on the number of times to press ; after the initial search
# Here is a comment with a lot of vowels and I have passed it now
How does Vim's current implementation of f know how to wait for only a single character instead of a newline?
I would prefer to overwrite the builtin f functionality so I'm using a remap similar to this, but one of the problems is that it expects me to press enter at the end.
nnoremap f :call HighlightFSearches(input(''))<CR>
Currently have some issues with implementing my function HighlightFSearches as well, but one problem at a time.
Also, not really looking for a plugin and yes I know I can just do a search instead of using f but my brain seems to prefer going with f first in a lot of cases.
Update
Here's my final solution with much thanks to #filbranden below!
function! HighlightFSearches(cmd)
" Get extra character for the command.
let char = nr2char(getchar())
if char ==# ''
" Skip special keys: arrows, backspace...
return ''
endif
" Highlight 'char' on the current line.
let match_str = 'match Visual "\%' . line('.') . 'l' . char . '"'
execute match_str
" Finally, execute the original command with char appended to it
return a:cmd.char
endfunction
" highlight searches using 'f'
nnoremap <expr> f highlighting#HighlightFSearches('f')
nnoremap f<bs> <nop>
vnoremap <expr> f highlighting#HighlightFSearches('f')
vnoremap f<bs> <nop>
" highlight searches using 'F'
nnoremap <expr> F highlighting#HighlightFSearches('F')
nnoremap F<bs> <nop>
vnoremap <expr> F highlighting#HighlightFSearches('F')
vnoremap F<bs> <nop>
Note that I chose the Highlight Group used for visual selects. You could choose a different one or make your own too
The short answer is that you should use getchar() to get a single character from the user.
The long answer is that this gets somewhat complicated pretty quickly, since you need to deal with special keys and corner cases while handling getchar().
Note that getchar() may return a number (for a normal keypress, which you can convert to a character with nr2char()), or a string, starting with a special 0x80 byte for special keys (backspace, arrows, etc.)
A simplistic approach (but somewhat effective) is that running nr2char() on the strings returned for the special keys will return an empty string, so we can use that to skip those.
The next advice is that you can use <expr> in your mappings to return the new command as a string. That, together with non-recursive mappings, allow you to return the actual f command itself at the end of the function, so that part of emulating it is taken care of!
Finally, one more trick you might want to use is to create a "dummy" mapping for f followed by an invalid character. The fact that such a 2-character mapping exists makes it so that your f mapping won't trigger until a second character has been entered, and this will prevent Vim from moving the cursor to the last line while waiting for a character, making the f emulation more seamless.
Putting it all together:
function! HighlightFSearches(cmd)
" Get extra character for the command.
let char = nr2char(getchar())
if char ==# ''
" Skip special keys: arrows, backspace...
return ''
endif
" Here you'll want to highlight "char"
" on the current line.
" Finally, execute the original command.
return a:cmd.char
endfunction
nnoremap <expr> f HighlightFSearches('f')
nnoremap f<bs> <nop>
The function is written in a way that you can easily reuse it for F, t and T.
For highlighting the matches, you can either use :match (or :2match, :3match) or maybe you could set #/ and let 'hlsearch' do the highlighting...
You'll probably want to anchor the regexp on the current line, so only those matches are highlighted, see :help /\%l for what you can use for that.
Finally, you'll probably want to clear the highlighting if you move to a different line. Take a look at the CursorMoved event of autocmd for that purpose.
There are quite a few details to iron out, but hopefully this will clarify how to emulate the command part of getting the character to search for.
The short and sweet answer is to substitute input() for getchar()
I have this script to search for the word under cursor in the current project:
nnoremap <leader>K :grep! "\b<C-R><C-W>\b"<CR>:cw<CR>
It works just fine except when the word starts with b.
This is due to <C-R><C-W> only completing the remaining of the word. For example, if I'm searching for "branch", my pattern gets something like this:
\branch\b
Which is equivalent to search for the work "ranch".
Any thoughts on how to figure this out?
Try this: nnoremap <leader>K :execute 'grep! "\b"'.expand("<cword>").'"\b"'<CR>:cw<CR>.
<cword> will expand to the current word under the cursor, as :help :<cword> explains, along with others:
<cword> is replaced with the word under the cursor (like |star|)
<cWORD> is replaced with the WORD under the cursor (see |WORD|)
<cfile> is replaced with the path name under the cursor (like what|gf| uses)
Check the help for more info.
When searching string with notepad++, new window opens and shows find
results. I want to use this feature in vim. After googling I found out some suggestions:
vimgrep /<pattern>/ %
copen
It is possible to create mapping which do those two commands. Pattern should be the current word: may be cword keyword in vim?
The requirement is actually easy. but to get user inputted pattern, you need a function.
function! FindAll()
call inputsave()
let p = input('Enter pattern:')
call inputrestore()
execute 'vimgrep "'.p.'" % |copen'
endfunction
if you want to have a mapping, add this line:
nnoremap <F8> :call FindAll()<cr>
but as I commented under your question. % may not work for unamed buffer.
I suggest lvimgrep (so you can use quickfix for :make)
:nnoremap <F6> :lvimgrep /\M\<<C-R><C-W>\m\>/ **/*.[ch]pp **/Makefile | lopen<CR>
Also, if you just wanted to find in the current file:
:g/<pattern>/
will invoke 'print' (default command) on each matching line.
:v// " non-matching lines
:g//-1 " lines preceding the matching line
:g//-1,+1 " lines around the matching line
etc.
:global is far more useful:
:g/foo/ join " join all lines containing foo
etc.
Those two commands can be shortened and chained: :vim foo %|co. You can pull the word under the cursor like this: :vim <C-r><C-w> %|co.
Here is a quick normal mode mapping that you can use to list all the occurrences of the word under your cursor in the quickfix window:
nnoremap <F6> :vimgrep /<C-r><C-w>/j % <bar> cwindow<cr>
You can also use :il[ist] foo to display a list of all the occurrences of foo or [I to display the same list for the word under your cursor.
When the list is displayed, use :{line number} to jump to the corresponding line.
I've enjoyed using # to highlight and search for a word (variable) but I would love if I could hit a single command that would simply tell me how many occurrences are in the current file. I've found the following
:%s/dns_name_change_flag/&/gn
But that's too much typing. Is there anyway to maybe map the above one-liner to use the word under cursor?
I don't know how to do this without execute. The following maps F5 to count occurrences of the word under the cursor using <cword> and word boundary patterns (\\< and \\>):
:map <f5> :execute ":%s#\\<" . expand("<cword>") . "\\>\#&#gn"<CR>
:map <F2> "zyiw:exe "%s/".#z."//gn"<CR>
add this line (without the ":") to your .vimrc and F2 will be mapped every time you start vim.
It yanks the 'inner word' to the z register and then performs a search in the whole buffer outputting the number of appearances.
This approach differs to the one given by Thor in that way, that it also counts appearances of the word that are not a word themselves, but only part of a word. For example: looking for 'an' will also count 'and'.
This might be helpful too:
"A quick way to list all occurrences of the word under the cursor it to type [I (which displays each line containing the current keyword, in this file and in included files when using a language such as C)."
source: http://vim.wikia.com/wiki/Word_count
Map Execute to Grep
You can map a sequence to an external grep command. For example:
:nmap fg :execute '!fgrep --count <cword> %'<CR>
This maps a normal-mode command to fg. The command will run fgrep on the current file in an external process, counting the instances of the word under the cursor.
Minor Caveat
This operates on the current file, not the current buffer. You need to make sure the file is written to disk (e.g. :write) before the word count will be accurate.
I have written a plugin for that: SearchPosition; it provides mappings for the current search pattern and current word / selection, and also lists where the matches occur:
1 match after cursor in this line, 8 following, 2 in previous lines;
total 10 for /\<SearchPosition\>/
:nmap <Leader>* *<C-o>:%s///gn<CR><C-o>
I have a function that does not change search register #/
fun! CountWordFunction()
try
let l:win_view = winsaveview()
exec "%s/" . expand("<cword>") . "//gn"
finally
call winrestview(l:win_view)
endtry
endfun
command! -nargs=0 CountWord :call CountWordFunction()
nnoremap <F3> :CountWord<CR>
If you alredy have searched for the word you can just type
:%~n
I mapped key F2 to refresh (:edit) currently opened file. I'm using this when watching a log file to update the screen when file has been updated outside (new lines added at the end of a log file).
nnoremap <silent> <F2> :edit<CR>
I would like to jump to the end of the file after it has been refreshed.
How do I create key mapping which does :edit and jump to end of the file (shortcut G) at the same time?
An idiomatic way to position the cursor in the just opened (or reopened) file
is to use the +-argument of the :edit command (see :help +cmd).
Although the general syntax allows to execute any command, there are special
cases for navigating to a certain line by a pattern matching text on that line
(+/ followed by the pattern), or by a line number (+ followed by the
number). If the number is omitted in the latter form, it is assumed to be the
last line of the file.
In such a way, to reload the current file positioning the cursor on the last
line, one can use the command
:edit +$
or
:edit + %
It is possible to shorten these commands by using :e instead of :edit and
leaving out an optional space before the +-argument.
:e+$
or
:e+ %
The corresponding mappings would take the form
:nnoremap <silent> <F2> :edit +$<CR>
and
:nnoremap <silent> <F2> :edit + %<CR>
Note that this +-argument syntax is also valid for opening a file from the
command line, so
$ vim + filename
works as well.
This is what I'd use:
nnoremap <silent><F2> :edit<bar>$<CR>
You can chain commands in a map by using <bar>. This mapping does what you want:
:nnoremap <silent> <F2> :edit <bar> :normal! G<enter>
It's important to use normal! instead of normal in mappings/scripts because the prior will not take user defined mappings into account. Even if there is a mapping for G in this case, vim will treat G as if it were not mapped at all.
You can use :normal to use the normal-mode G motion:
:nnoremap <silent> <F2> :edit<CR>:norm! G<CR>
Perhaps better would be to use the :$ command to go to the end of the file:
:nnoremap <silent> <F2> :edit<CR>:$<CR>
In Vim '|' can be used to separate commands, much like many flavors of Linux/Unix. For more information about the use of the bar check out :help bar
Example:
:edit | normal! G
If you wish to use this in a key mapping You may find that your ~/.vimrc doesn't like maps utilizing |, or \|. In order to make this work use the equivalent <bar> instead.