search for a yanked text and automatically escape special characters - vim

for example, I'd like to yank hello/world and paste that into a search for other instances of hello/world
I've tried yanking, then typing /\v ctr-r 0 and in the search bar it places the entire hello/world but practically, it only searched for hello.
Is there a way to automatically escape special character during paste in the search?

You might be interested in this:
" return a representation of the selected text
" suitable for use as a search pattern
function GetVisualSelection()
let old_reg = #a
normal! gv"ay
let raw_search = #a
let #a = old_reg
return substitute(escape(raw_search, '\/.*$^~[]'), "\n", '\\n', "g")
endfunction
xnoremap <leader>r :<C-u>%s/<C-r>=GetVisualSelection()<CR>/
It uses more or less the same strategy as above but in a slightly cleaner and reusable way.
Select hello/world.
Hit <leader>r.
The command-line is populated with :%s/hello\/world/, ready for you to…
type the replacement text and…
hit <CR>.

Adding this to the vimrc file allows you to visually select something, press *, and it will search with escaped characters
vnoremap <silent> * :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy/<C-R><C-R>=substitute(
\escape(#", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>
vnoremap <silent> # :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy?<C-R><C-R>=substitute(
\escape(#", '?\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>
source

Related

load external command in the same split after repeating it

I want to load some text coming from a command line command into a new vim split. I got this working but if I run the command again it keeps opening new splits.
What I want to achieve is getting this into the same split. How can I do this?
nnoremap <leader>q :execute 'new <bar> 0read ! bq query --dry_run --use_legacy_sql=false < ' expand('%')<cr>
I would suggest using the preview window via the :pedit command.
nnoremap <leader>q :execute 'pedit <bar> wincmd p <bar> 0read ! bq query --dry_run --use_legacy_sql=false < ' expand('%')<cr>
However we can do even better by doing the following:
Making a "query" operator using g# and 'opfunc'
A query command (feels very vim-like to do so)
Using stdin instead of a filename
Example:
function! s:query(str)
pedit [query]
wincmd p
setlocal buftype=nofile
setlocal bufhidden=wipe
setlocal noswapfile
%delete _
call setline(1, systemlist('awk 1', a:str))
endfunction
function! s:query_op(type, ...)
let selection = &selection
let &selection = 'inclusive'
let reg = ##
if a:0
normal! gvy
elseif a:type == 'line'
normal! '[V']y
else
normal! `[v`]y
endif
call s:query(##)
let &selection = selection
let ## = reg
endfunction
command! -range=% Query call s:query(join(getline(<line1>, <line2>), "\n"))
nnoremap \qq :.,.+<c-r>=v:count<cr>Query<cr>
nnoremap \q :set opfunc=<SID>query_op<cr>g#
xnoremap \q :<c-u>call <SID>query_op(visualmode(), 1)<cr>
Note: I am using awk 1 as my "query" command. Change to meet your needs.
For more help see:
:h :pedit
:h :windcmd
:h operator
:h g#
:h 'opfunc'
:h systemlist()

How to have vim highlight color change for the pattern under cursor?

Is there a way to have the search highlight text in vim under the cursor have a different color compared to the search text not under the cursor?
my .vimrc has this codes:
function! HiInterestingWord(n) " {{{2
" Save our location.
normal! mz
" Yank the current word into the z register.
normal! "zyiw
" Calculate an arbitrary match ID. Hopefully nothing else is using it.
let mid = 77750 + a:n
" Clear existing matches, but don't worry if they don't exist.
"silent! call matchdelete(mid)
try
call matchdelete(mid)
catch 'E803'
" Construct a literal pattern that has to match at boundaries.
let pat = '\V\<' . escape(#z, '\') . '\>'
" Actually match the words.
call matchadd("InterestingWord" . a:n, pat, 1, mid)
endtry
" Move back to our original location.
normal! `z
endfunction
"clear all highlighting
function! ClearAllHi()
for i in range(1,6)
let mid = 77750 + i
silent! call matchdelete(mid)
endfor
endfunction
nnoremap <silent> <leader>0 :call ClearAllHi()<cr>
nnoremap <silent> <leader>1 :call HiInterestingWord(1)<cr>
nnoremap <silent> <leader>2 :call HiInterestingWord(2)<cr>
nnoremap <silent> <leader>3 :call HiInterestingWord(3)<cr>
nnoremap <silent> <leader>4 :call HiInterestingWord(4)<cr>
nnoremap <silent> <leader>5 :call HiInterestingWord(5)<cr>
nnoremap <silent> <leader>6 :call HiInterestingWord(6)<cr>
hi def InterestingWord1 guifg=#000000 ctermfg=16 guibg=#ffa724 ctermbg=214
hi def InterestingWord2 guifg=#000000 ctermfg=16 guibg=#aeee00 ctermbg=154
hi def InterestingWord3 guifg=#000000 ctermfg=16 guibg=#8cffba ctermbg=121
hi def InterestingWord4 guifg=#000000 ctermfg=16 guibg=#b88853 ctermbg=137
hi def InterestingWord5 guifg=#000000 ctermfg=16 guibg=#ff9eb8 ctermbg=211
hi def InterestingWord6 guifg=#000000 ctermfg=16 guibg=#ff2c4b ctermbg=195
"}}}
This allows you to press <leader> + 1-6 to high light word under cursor in different colors; pressing it twice to clear the highlighting. (You can change the color in hi def...) commands. And <leader>+0 clear all highlights.
You can just put the codes in your vimrc to try.
It works like this:
People have used solution based on Damian Conway's talk
" Damian Conway's Die Blinkënmatchen: highlight matches
nnoremap <silent> n n:call HLNext(0.1)<cr>
nnoremap <silent> N N:call HLNext(0.1)<cr>
function! HLNext (blinktime)
let target_pat = '\c\%#'.#/
let ring = matchadd('ErrorMsg', target_pat, 101)
redraw
exec 'sleep ' . float2nr(a:blinktime * 1000) . 'm'
call matchdelete(ring)
redraw
endfunction
But personally, I prefer a simple one, though this highlight whole line
"cursorline and it's highlighting
set cursorline
hi CursorLine cterm=NONE ctermbg=NONE ctermfg=green

VIM search forward and back re-select searched text

I currently am using this to function like in Geany (my old editor) when I select text and press F3:
vnoremap <silent> * :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy/<C-R><C-R>=substitute(
\escape(#", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>
vnoremap <silent> # :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy?<C-R><C-R>=substitute(
\escape(#", '?\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>
Of course this is * for search forward for selected text and # for backward search of selected text.
What I can't figure out is how to get both of these to re-select the found word (or whatever is selected) once it find's it so I can continue to press * or # for continued search. So I don't have to re-select what it find's if that's not what I want and want to continue searching.
Your solution of adding v//e<CR> works, but it has the side effect of making the search to the end, which affects other commands like n / N. A better option is to re-establish the previous selection at the current position via 1v (or 1vl when 'selection' is exclusive).
vnoremap <silent> * :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy/<C-R><C-R>=substitute(
\escape(#", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>1v
vnoremap <silent> / :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy?<C-R><C-R>=substitute(
\escape(#", '?\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>1v
GOT IT!!! Found it on another Stackoverflow question kind of related to mine, was hard to find though. Correct usage would be to add this to the end of each query:
<Esc>v//e<CR>
This takes me back out into normal mode, then visual mode, then repeat last search then select to end. So final code would be:
vnoremap <silent> * :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy/<C-R><C-R>=substitute(
\escape(#", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR><Esc>v//e<CR>
vnoremap <silent> / :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy?<C-R><C-R>=substitute(
\escape(#", '?\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR><Esc>v//e<CR>
And that gives the quick fast and easy approach to fast searching of selected region!

How can I search a word after selecting it in visual mode in Vim?

Suppose I have selected a word in visual mode.
Now I want to search that word in the document.
How can I do that?
Thanks in advance.
If it's just a single word, you don't even have to select it. Just place the cursor on the word and press * (or # to search backwards). Note that this search will only match the whole word. To allow a search for foo to match foobar, use g* or g#.
Press y (you'll exit from visual mode after that) then press / Ctrl+r then " end hit enter.
You can use it to bind // for this action:
:vmap // y/<C-R>"<CR>
If you select special chars you better use this
:vmap <silent> // y/<C-R>=escape(#", '\\/.*$^~[]')<CR><CR>
I recommend https://github.com/thinca/vim-visualstar because you can use * for searching but with some selections you can run into problems.
I have this in my ~/.vimrc:
" Search for visually-selected text, forwards or backwards.
vnoremap <silent> * :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy/<C-R><C-R>=substitute(
\escape(#", '/\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>
vnoremap <silent> # :<C-U>
\let old_reg=getreg('"')<Bar>let old_regtype=getregtype('"')<CR>
\gvy?<C-R><C-R>=substitute(
\escape(#", '?\.*$^~['), '\_s\+', '\\_s\\+', 'g')<CR><CR>
\gV:call setreg('"', old_reg, old_regtype)<CR>

Setting to skip over punctuation when moving forwards and backwards words

When I'm using vim I generally never want to move to a punctuation mark when I press w or b to go forwards or backwards. So I'm wondering if there's a setting or something to change this functionality?
e.g. If I've got some code like
object.method(args)
and my cursor is at the [o] in "object" then I want w to move to the [m] in "method", and another w to move to the [a] in "args". I don't want it to land on the [.] or the [(]. If I've ever wanted to move to a punctuation char I've always used f or F to jump straight to it. I've never personally wanted to move to a punctuation char when I move through words and I just realized this is really bugging me.
I too find that I would like a movement that is more inclusive that w, but not as inclusive as W. In particular, I would like a movement that only considers tokens beginning with alphanumeric characters as significant.
So I came up with the following:
" <SPACE> : forward to next word beginning with alphanumeric char
" <S-SPACE> : backward to prev word beginning with alphanumeric char
" <C-SPACE> : same as above (as <S-SPACE> not available in console Vim
" <BS> : back to prev word ending with alphanumeric char
function! <SID>GotoPattern(pattern, dir) range
let g:_saved_search_reg = #/
let l:flags = "We"
if a:dir == "b"
let l:flags .= "b"
endif
for i in range(v:count1)
call search(a:pattern, l:flags)
endfor
let #/ = g:_saved_search_reg
endfunction
nnoremap <silent> <SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'f')<CR>
vnoremap <silent> <SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv/\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <S-SPACE> :<C-U>call <SID>GotoPattern('\(^\\|\<\)[A-Za-z0-9_]', 'b')<CR>
vnoremap <silent> <S-SPACE> :<C-U>let g:_saved_search_reg=#/<CR>gv?\(^\\|\<\)[A-Za-z0-9_]<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
nnoremap <silent> <BS> :call <SID>GotoPattern('[A-Za-z0-9_]\(\>\\|$\)', 'b')<CR>
vnoremap <silent> <BS> :<C-U>let g:_saved_search_reg=#/<CR>gv?[A-Za-z0-9_]\(\>\\|$\)<CR>:<C-U>let #/=g:_saved_search_reg<CR>gv
" Redundant mapping of <C-SPACE> to <S-SPACE> so that
" above mappings are available in console Vim.
"noremap <C-#> <C-B>
if has("gui_running")
map <silent> <C-Space> <S-SPACE>
else
if has("unix")
map <Nul> <S-SPACE>
else
map <C-#> <S-SPACE>
endif
endif
I have had this for a long time now, and I find that I use <SPACE>/<C-SPACE> movements so much more than w and W; it just seems more useful when coding. You can, of course, map the commands to whatever keys you find useful or more appropriate.
Even running the risk of creating a script for something that's built-in (like
I did last time), here is a little function that may help accomplishing
this.
function! JumpToNextWord()
normal w
while strpart(getline('.'), col('.')-1, 1) !~ '\w'
normal w
endwhile
endfunction
Basically, what it does is executing the standard w and repeating it
if the character under the cursor is not in a word character (feel free to
change that pattern.
If you add that and a little map in your .vimrc:
nnoremap <silent> ,w :call JumpToNextWord()<CR>
It should work.

Resources