Vim highlight a word with * without moving cursor - vim

I would like to be able to highlight the word under cursor without going to the next result.
The solution I found uses a marker:
noremap * mP*N`P
Is there any better solution ?
I noticed vim is not really good to keep the position of its cursor after the execution of commands. For instance, when I switch buffer, the cursor go back to the begining of the line.
I might be interesting to have a global setting for this.

There's unfortunately no global setting for that.
One common solution to the "highlight without moving" problem is:
nnoremap * *``
One solution to the "keep the cursor position when switching buffers" problem is:
augroup CursorPosition
autocmd!
autocmd BufLeave * let b:winview = winsaveview()
autocmd BufEnter * if(exists('b:winview')) | call winrestview(b:winview) | endif
augroup END

As detailed here, you can define a map as follows:
:nnoremap <F8> :let #/='\<<C-R>=expand("<cword>")<CR>\>'<CR>:set hls<CR>

My SearchHighlighting plugin changes the * command, so that it doesn't jump to the next match; you can still jump by supplying a [count]. It also extends that command to visual mode (another frequently requested feature not in Vim), and some more.

Related

How to come back to INSERT mode with the cursor at the same place from SELECT mode and (insert) SELECT mode? [duplicate]

Is it possible to cancel the said behavior?
A task for extra credit: Figure out a way to force Vim to refresh the cursor position immediately after exiting Insert mode.
Although I would not recommend changing the default cursor mechanics,
one way of achieving the behavior in question is to use the following
Insert-mode mapping.
:inoremap <silent> <Esc> <Esc>`^
Here the Esc key is overloaded in Insert mode to additionally
run the `^ command which moves the cursor to the position where it
had been the last time Insert mode was left. Since in this mapping it
is executed immediately after leaving Insert mode with Esc,
the cursor is left one character to the right as compared to its
position with default behavior.
Unlike some other workarounds, this one does not require Vim to be
compiled with the +ex_extra feature.
Although there are tricks to deal with this (such as the ESC mappings mentioned in the previous two posts), there's no consistent way to do this. The reason is that there is no way to determine the method that was used to enter insert mode. Specifically, given the string abcDefg with the cursor on the D:
If you press i, the insert mode location will be between the c and D. A normal ESC will put the cursor on c; <C-O>:stopinsert<CR> (or the backtick method) will put the cursor on D.
If you press a, the insert mode location will be between the D and e. A normal ESC will put the cursor on D; <C-O>:stopinsert<CR> will put the cursor on e.
If you REALLY want to do this, you could fudge it with something like this:
let insert_command = "inoremap <ESC> <C-O>:stopinsert<CR>"
let append_command = "iunmap <ESC>"
nnoremap i :exe insert_command<CR>i
nnoremap a :exe append_command<CR>a
BUT: remember that this will only deal with i and a as methods of entry: if you use visual block mode, I, or A or whatever, you'll need to come up with new commands to match (and there are a lot of them). Therefore, I'd strongly recommend you don't do this.
Personally, I'd recommend getting used to the default behaviour. You can easily make it logical for i OR logical for a. If you change the default to logical for i at the expense of logical for a, you'll just get confused when you use a standard vi/vim install.
Based on Nathan Neff's comment, the best approach I've found is
autocmd InsertLeave * :normal! `^
set virtualedit=onemore
autocmd moves the cursor back to where it was when insert mode ended (i.e. one forward compared to the default).
virtualedit makes it act consistently at end of line (so it can be one forward of the last character on the line).
(Edited: normal! to avoid recursive mappings)
inoremap <silent> <Esc> <C-O>:stopinsert<CR>
in your .vimrc.
I do believe the proper way to do this is
au InsertLeave * call cursor([getpos('.')[1], getpos('.')[2]+1])
There is an approach from the Vim Tips wiki that has worked well for me for...I don't know how many years:
" Leave insert mode to the *right* of the final location of the insertion
" pointer
" From http://vim.wikia.com/wiki/Prevent_escape_from_moving_the_cursor_one_character_to_the_left
let CursorColumnI = 0 "the cursor column position in INSERT
autocmd InsertEnter * let CursorColumnI = col('.')
autocmd CursorMovedI * let CursorColumnI = col('.')
autocmd InsertLeave * if col('.') != CursorColumnI | call cursor(0, col('.')+1) | endif
What about:
:imap <Esc> <Esc><Right>

Vim command Scroll Up and down - Does a plugin exist for this?

I have been using vim for a couple of months now however my current workflow involves continuously scrolling down and up. For that i use Ctrl+f and Ctrl+b
So whenever I use the Ctrl+f combination the new text appears on the center of the screen. I wanted to know if there was a way for vim to always have a light coloured line in the center of screen (so i could use the line as a reference to the new content whenever i press ctrl+f (scroll half screen)). I know this request sounds odd but I am curious if such a feature exists?
You can try this smooth scroll plugin: https://github.com/terryma/vim-smooth-scroll I think it may solve your problem.
Put this in your .vimrc or in a script:
augroup HlMid
autocmd!
autocmd CursorMoved * :call HighlightMiddle()
augroup END
function! HighlightMiddle()
normal! M
execute "match search /\\%".line('.')."l/"
normal! ^O
endfunction!
EDIT: As rgoliveira stated in the comment that could interfere with match command. You need only to remove the autocommand and make it back whenever you use it:
Remove:
:autocmd! HlMid CursorMoved *
Reload:
:autocmd HlMid CursorMoved * :call HighlightMiddle()
For the last command in the function normal! ^o you get ^o by typing ctrl+v ctrl+o

Execute :nohlsearch on InsertEnter

I can do <C-O>:noh<CR> when I'm in insert mode, but it doesn't work when done automatically:
autocmd InsertEnter * :nohlsearch
This works, but it behaves differently:
autocmd InsertEnter * :set nohlsearch
To clarify, what I want is to run :nohlsearch if I enter insert node, but I still want to keep the ability to do /<CR>N to search for another item.
I think, what you want can be accomplished by setting the search register directly:
:autocmd InsertEnter * :let let #/=''
If you want to restore the highlighting when returning from insert mode, you would need to save and restore the pattern, something like this should do it:
:autocmd InsertEnter * :let b:_search=#/|let #/=''
:autocmd InsertLeave * :let #/=get(b:,'_search','')
This saves and restores the current search pattern in the buffer local variable b:_search.
You should write a function calling :nohl and then redraw:
function DisableHL()
nohl
redraw
endfunction
and then autocmd InsertEnter * :call DisableHL()
I think I came up with a smart-ish way of accomplishing exactly the same effect (at least it does exactly what I want and I seem to want what you asked for).
I have this in my vimrc:
Disable highlighting when entering Insert mode
autocmd InsertEnter * set nohlsearch
Re-enable highlighting when pressing any of the nN?/ keys before sending the key, then send the key
for s:k in ['n', 'N', '?', '/']
execute('nnoremap ' . s:k . ' :set hlsearch<cr>' . s:k)
endfor
to hide last search's hightlighting
(I like to be able to quickly disable it without entering insert mode)
nnoremap <silent> <bs> :set nohlsearch<cr>
It basically sets [no]hlsearch on the fly as you use the commands.
I also checked, and at least on my setup it doesn't mess if using nN?/ as normal mode command (for vim's default commands at least) arguments (like dtN to delete until next N), although this might be a concern if you ever remap any of those keys, or if a plugin does it without you noticing it.

VIM: How to turn off search highlight after timeout (X seconds)

I know about :nohl and use it all the time, I also use easy motion so the highlight is not in my way when just moving to the search location. It gets in my way after pressing n or N.
I am looking for a way to disable the search highlight after 3 seconds of pressing n or N, also for completeness sake I would like a way to also disable it after searching e.g. /search_word<CR>.
Finally, it has to be a non-blocking command.
Thanks, I am slowly getting into vimscript but this one is out of my league since I haven't seen many examples of commands with timeouts out there.
EDIT:
After some of the comments and online research there are lots of indications there isn't a good way to do this with vimscript.
I am looking for a way to do this in a stable way with any language, e.g. Perl, Python, Ruby.
EDIT 2:
This is my solution based on #dhruva-sagar's response:
(I marked his answer as correct because he gave me the skeleton for it).
augroup NoHLSearch
au!
autocmd CursorHold,CursorMoved * call <SID>NoHLAfter(4)
augroup END
function! s:NoHLAfter(n)
if !exists('g:nohl_starttime')
let g:nohl_starttime = localtime()
else
if v:hlsearch && (localtime() - g:nohl_starttime) >= a:n
:nohlsearch
redraw
unlet g:nohl_starttime
endif
endif
endfunction
If you check :h :nohl, you will see that the command :nohl does not work within an autocmd, the reason being that vim saves & restores the search & search highlighting state after executing an autocmd. Hence technically it is not feasable to do so. The best way is to create a mapping like nnoremap <C-l> :nohlsearch<CR> and use it when you want to temporarily disable the search highlighting.
However there is a slight hack that i'd like to demonstrate that does work in a way like you expect by using set nohlsearch instead of nohlsearch, the downside of course is that it turns off search highlighting completely and you need to re-enable it using set hlsearch, so it isn't really a solution but it makes for a good example to demonstrate how one could perform time based operations within vim.
NOTE: This is more for educational purposes to demonstrate how you could do time based non-blocking tasks in vim. The performance of these could vary depending on what you do within the event triggered function.
augroup NoHLSearch
au!
autocmd CursorHold,CursorMoved * call <SID>NoHLAfter(3)
augroup END
function! s:NoHLAfter(n)
if !exists('g:nohl_starttime')
let g:nohl_starttime = localtime()
else
if v:hlsearch && (localtime() - g:nohl_starttime) >= a:n
set nohlsearch
unlet g:nohl_starttime
endif
endif
endfunction
IMHO, a simpler and more predictable technique is the following:
noremap <silent><esc> <esc>:noh<CR><esc>
You're always hitting escape anyway, so it's a no-brainer to hit it when you want to clear hlsearch. In addition, you can choose to leave the matches highlighted if you want by not hitting an extra in normal mode.
The following will clear the search highlight after 'updatetime' milliseconds of inactivity. 'updatetime' defaults to 4000ms or 4s but I have set mine to 10s. It is important to note that 'updatetime' does more than just this so read the docs before you change it.
function! SearchHlClear()
let #/ = ''
endfunction
autocmd CursorHold,CursorHoldI * call SearchHlClear()
Kevin Cox's answer was on the right track except for a couple problems.
Modifying #/ is a heavy handed approach to disable highlighting of the existing search
Vim saves/restores the search highlighting state before/after calling a function, so trying to change that in a function isn't very useful.
The solution is to simplify. There's no need for a function call.
autocmd CursorHold,CursorHoldI * let v:hlsearch = 0 | redraw
A little bit of necromancy, but I hope it's useful:
I tweaked #DhruvaSagar's answer to improve performance by deactivating the autocmd when it's not needed. Also I removed the CursorHold event: I like to look at my results in peace.
I'm using this together with the second answer from here to automatically deactivate the highlight after a while when I'm not searching (via / or n).
My code:
function! s:NoHLAfter(n)
if (localtime() - g:nohl_starttime) >= a:n
call <SID>Onnohl()
endif
endfunction
function! s:Onnohl()
set nohlsearch
augroup AutoNohl
au!
augroup END
endfunction
function! s:Onsearch()
set hlsearch
nohlsearch
let g:nohl_starttime = localtime()
augroup AutoNohl
au!
" autocmd CursorHold,CursorMoved * call <SID>NoHLAfter(4)
" only do it on CursorMoved: We sometimes 'hold' and look at the
" findings.
autocmd CursorMoved * call <SID>NoHLAfter(4)
augroup END
endfunction
noremap n :call <SID>Onsearch()<cr>n
noremap N :call <SID>Onsearch()<cr>N
noremap / :call <SID>Onsearch()<cr>/
noremap ? :call <SID>Onsearch()<cr>?

How to prevent the cursor from moving back one character on leaving Insert mode in Vim?

Is it possible to cancel the said behavior?
A task for extra credit: Figure out a way to force Vim to refresh the cursor position immediately after exiting Insert mode.
Although I would not recommend changing the default cursor mechanics,
one way of achieving the behavior in question is to use the following
Insert-mode mapping.
:inoremap <silent> <Esc> <Esc>`^
Here the Esc key is overloaded in Insert mode to additionally
run the `^ command which moves the cursor to the position where it
had been the last time Insert mode was left. Since in this mapping it
is executed immediately after leaving Insert mode with Esc,
the cursor is left one character to the right as compared to its
position with default behavior.
Unlike some other workarounds, this one does not require Vim to be
compiled with the +ex_extra feature.
Although there are tricks to deal with this (such as the ESC mappings mentioned in the previous two posts), there's no consistent way to do this. The reason is that there is no way to determine the method that was used to enter insert mode. Specifically, given the string abcDefg with the cursor on the D:
If you press i, the insert mode location will be between the c and D. A normal ESC will put the cursor on c; <C-O>:stopinsert<CR> (or the backtick method) will put the cursor on D.
If you press a, the insert mode location will be between the D and e. A normal ESC will put the cursor on D; <C-O>:stopinsert<CR> will put the cursor on e.
If you REALLY want to do this, you could fudge it with something like this:
let insert_command = "inoremap <ESC> <C-O>:stopinsert<CR>"
let append_command = "iunmap <ESC>"
nnoremap i :exe insert_command<CR>i
nnoremap a :exe append_command<CR>a
BUT: remember that this will only deal with i and a as methods of entry: if you use visual block mode, I, or A or whatever, you'll need to come up with new commands to match (and there are a lot of them). Therefore, I'd strongly recommend you don't do this.
Personally, I'd recommend getting used to the default behaviour. You can easily make it logical for i OR logical for a. If you change the default to logical for i at the expense of logical for a, you'll just get confused when you use a standard vi/vim install.
Based on Nathan Neff's comment, the best approach I've found is
autocmd InsertLeave * :normal! `^
set virtualedit=onemore
autocmd moves the cursor back to where it was when insert mode ended (i.e. one forward compared to the default).
virtualedit makes it act consistently at end of line (so it can be one forward of the last character on the line).
(Edited: normal! to avoid recursive mappings)
inoremap <silent> <Esc> <C-O>:stopinsert<CR>
in your .vimrc.
I do believe the proper way to do this is
au InsertLeave * call cursor([getpos('.')[1], getpos('.')[2]+1])
There is an approach from the Vim Tips wiki that has worked well for me for...I don't know how many years:
" Leave insert mode to the *right* of the final location of the insertion
" pointer
" From http://vim.wikia.com/wiki/Prevent_escape_from_moving_the_cursor_one_character_to_the_left
let CursorColumnI = 0 "the cursor column position in INSERT
autocmd InsertEnter * let CursorColumnI = col('.')
autocmd CursorMovedI * let CursorColumnI = col('.')
autocmd InsertLeave * if col('.') != CursorColumnI | call cursor(0, col('.')+1) | endif
What about:
:imap <Esc> <Esc><Right>

Resources