Is it possible to configure vim such that a movement command "wraps around" the vertical (or horizontal) buffer?
In other words, assume I'm on line 2 in a buffer, in visual mode. I press 3k. My cursor is now positioned on the last line of the buffer.
Or more simply, my cursor is on the first line of the file -- I press k. Now my cursor flips to the last line of the file.
Apologies if this has been asked before, but I couldn't find any references searching for "circular scrolling" or "wrap-around scrolling".
It's probably possible with some vimscript hackery, but it's much more universal to become efficient with motions like G to go to the bottom of a file and gg or 1G or <C-Home> to go to the top of the file. Likewise, $ for the end of a line and 0 for the beginning of the line or ^ for the first non-blank character.
You can also set :help whichwrap, which specifies which keys will move of to the next line when moving past the end of the line or move to the previous line when moving past the beginning of the line. Other then that I don't think there's built in functionality for what you're asking. You can could do it with some vimscript but it would require remapping h,j,k, and l to functions and handling whether they are at the end/beginning of the line/file. To me that seems overkill and rather messy.
All that being said, if you must...
nnoremap j :call CheckJ()<cr>
nnoremap k :call CheckK()<cr>
nnoremap h :call CheckH()<cr>
nnoremap l :call CheckL()<cr>
fun! CheckJ()
if line('.') == line('$')
norm! gg
else
norm! j
endif
endfun
fun! CheckK()
if line('.') == 1
norm! G
else
norm! k
endif
endfun
fun! CheckH()
if col('.') == 1
norm! $
else
norm! h
endif
endfun
fun! CheckL()
if col('.') == (col('$') - 1)
norm! 0
else
norm! l
endif
endfun
Vim is a text editor, and text has both physical and logical properties of having a beginning and an end, both in columns and lines. Therefore, the feature you're requesting doesn't exist, and probably won't ever be included in Vim.
It can, however, with some effort be emulated in Vimscript, by binding most movement commands to custom implementations. But that would introduce inconsistencies in the usage model, as ranges (e.g. :42,10) still wouldn't wrap around.
Why would you want such a wrap-around? Is this for a particular file type, or are you used to it from another editor?
Related
Just another vim source code comment question here. I have this mapping for my python source code files:
map <C-C> <Home>i#<Esc>
imap <C-C> <Home>#<Esc> i
On Ctrl-C it puts # in the beginning if the line to comment it out. This improves productivity a lot. But when I want to uncomment lines, I have to do this manually, meaning going to the first character of each commented line and remove it. This is very annoying. At the first glance, I can just bind Home-x to some key, but I can occasionally remove an innocent space or something else in case I misshit and do this on line that has no # character at the beginning of it. I first try to do some replacement with :%s// for a single line, but that has an unwanted affect - it triggers a search and highlights 'pattern' in other lines. In case of a single # character it is a fail.
Can anybody suggest how to remove a specified character in the beginning of current line in case it present and do nothing, if not, without using pattern replacement?
I have created a simple function to Toggle comment in the line:
function! ToggleComment()
let l:pos = col('.')
if getline('.') =~ '\v(\s+|\t+)?#'
exec 'normal! _"_x'
let l:pos -= 1
else
exec 'normal! I#'
let l:pos += 1
endif
call cursor(line("."), l:pos)
endfunction
nnoremap <Leader>t :call ToggleComment()<CR>
inoremap <Leader>t <C-o>:call ToggleComment()<CR>
I recommend Tim Pope's plugin vim-commentary because is way more complete. But of course our idea gives you guys a glimpse how far we can get with vimscript.
Another approach, which does not need to save windowview and toggles comments in other languages can be seen here
Can anybody suggest how to remove a specified character in the beginning of current line in case it present and do nothing, if not, without using pattern replacement?
A solution would be (assuming your cursor is anywhere to the right of # when using the map):
map <c-c> mmF#x`m
A more general solution would be to use a substitution and histdel() to delete the last search pattern:
function! DelComment()
s/^\( *\)#/\1/
call histdel("search", -1)
let #/ = histget("search", -1)
endfunction
After executing the function (by selecting it and typing :#") you can map it to <c-c>:
map <silent> <c-c> mm:silent! call DelComment()<cr>`m
I like using marks around functions to retain the cursor position after executing the map. Feel free to remove mm and `m in the above map.
Here was a similar post: Vim, how to delete empty lines to "_ automatically?
I didn't understand the accepted solution and found that it didn't work (at least not the way that I wanted).
I want it so that using dd on an empty line (whether in visual or normal mode) will automatically put the deleted whitespace lines into the black hole register without me having to explicitly invoke it by using "_dd
I understand that one can just map "_dd to some other key, but that is not what I'm asking here. Also, taking care of character deletions is rather straightforward: nnormap x "_x
One solution could be to
re-direct the delete to the last register on the register stack (since this register is likely to never be used anyway) ("9 for example)
Then, check the value of "9 to see if it is only whitespace
If it is, then don't do anything
Else, copy the value of "9 into ""
I think I know how to do all of my proposed solution other than the check to see if the register contains only whitespace part
Probably not the most elegant solution, but here's what I came up with (with the help of #DJMcMayhem in a separate question I asked).
A function and binding for normal mode line deletion dd:
function! Smart_Delete_dd()
let temp = getreg('"', 1)
execute 'normal!' 'dd'
if matchstr(#", '\_s*') == #" " if just whitespace
call setreg('"', temp)
endif
endfunction
nnoremap <silent> dd :call Smart_Delete_dd()<CR>
A function and binding for visual mode line deletion Vd:
function! Smart_Delete_Vd() range
let temp = getreg('"', 1)
execute 'normal!' . (a:lastline - a:firstline + 1) . 'dd'
if matchstr(#", '\_s*') == #" " if just whitespace
call setreg('"', temp)
endif
endfunction
vnoremap <silent> d :call Smart_Delete_Vd()<CR>
I have a function that moves the cursor with the built-in cursor() function and it works fine on normal mode.
For concreteness suppose that this is the function:
function! F()
call cursor( line('.')+1, 1)
endfunction
used with a mappings as:
nnoremap <buffer> a :call F()<cr>
Now I want to reuse this function to move the cursor on any visual mode (visual, line visual, and block visual) and without losing the previous selection.
For example, with an initial buffer in visual mode (c means the cursor is at a line, v means the line is part of the current visual selection):
vc 1
2
3
hitting a would give:
v 1
vc 2
3
and hitting a again would give:
v 1
v 2
vc 3
so the old selection was kept.
I would like to reuse F() as much as possible, since in my application F() is quite large.
What is the best way to do that?
Up to now, the best I could do was use a wrapper function:
function! VisMove(f)
normal! gv
call function(a:f)()
endfunction
and map as:
vnoremap <buffer> a :call VisMove('F')<cr>
however I am not satisfied because this:
It requires putting the annoying wrapper on every new fgplugin I write.
Calling a function that moves the cursor (or has other arbitrary side effects) without ever leaving visual (current) mode seems like such a natural thing to be able to do. There is even already <expr> which almost does it, but it resets cursor position.
I solve this by passing a mode argument (or alternatively a boolean isVisual flag) into the function:
fu! F(mode) range
if a:mode ==# 'v'
normal! gv
endif
...
endf
nn <buffer> a :cal F('n')<cr>
vn <buffer> a :cal F('v')<cr>
Vim is great, but like many people I get really annoyed when I want to copy, delete, then paste -- the yank buffer gets overwritten by the delete action.
Now I know there are 101 work-arounds and mappings, some of which are enumerated in posts like this one: Any way to delete in vim without overwriting your last yank?
But all of these solutions have drawbacks -- even I were a buffer-guru (which I'm not). For instance, excess keystrokes -- whereas I normally xxxx to quickly delete 4 characters (just one keystroke cuz I hold it down and wait for autorepeat), it is not practical for me to now switch to ,x,x,x,x or whatever mapping I have to use a different buffer.
What would really be ideal is simply a mode toggle, whereby you can toggle on and off the side-effect behavior of the D, d, X, and x keys so that they alternately do or do not also write their text to a buffer. That way I can simply enter the "no side-effect" mode and delete away to heart's content, then paste when I'm ready. And re-enable side-effects if desired.
Does anyone know a way to do this?
[UPDATE: SOLUTION] OK I got it: I wrote a function that toggles a "no side-effects" mode... works perfectly! See my accepted correct answer below
[UPDATE #2] My solution still works great and I use it all the time when I'm doing a lot of deleting and pasting. But meanwhile I also found a lighter way to meet the specific use-case of copy, paste, delete for simple cases where the text to delete is contiguous.
After yanking text normally, I then visually highlight the text to delete using the v command, and then simply paste over it with the p command. That achieves the desired effect without any special mapping.
Only problem with this workflow is that if I wanted to paste again, the original paste buffer is overwritten by the act of pasting over the highlighted text, but this behavior is easily changed with the following mapping in .vimrc:
vnoremap p "_dp
vnoremap P "_dP
OK, I got it -- this script in .vimrc lets me effectively toggle a "no buffer side-effects" mode whereby the d and x keys no longer overwrite the buffer when "no buffer side-effects" mode is activated.
Add this in .vimrc
function! ToggleSideEffects()
if mapcheck("dd", "n") == ""
noremap dd "_dd
noremap D "_D
noremap d "_d
noremap X "_X
noremap x "_x
echo 'side effects off'
else
unmap dd
unmap D
unmap d
unmap X
unmap x
echo 'side effects on'
endif
endfunction
nnoremap ,, :call ToggleSideEffects()<CR>
Then to toggle in and out of this mode use the key combination ,, (two commas)
I think trying to "turn-off" the side effects for every delete/change command would be overly difficult if not impossible. The basic ways to handle this situation:
Use the black hole ("_) register with your delete or change commands. e.g. "_dd
Use the "0 register which contains the most recent yank with your paste commands. e.g. "0p
Yanking the text to a named register. e.g. "ayy then later doing "ap
I personally lean toward the "0p approach as this is fits with how my mind works.
Now seeing you asked for no such work-arounds I have provided some functions that alter the paste commands to toggle between my so called paste_copy and nopaste_copy mode. nopaste_copy being Vim's default behavior. Put the following in your ~/.vimrc:
function! PasteCopy(cmd, mode)
let reg = ""
if exists('g:paste_copy') && g:paste_copy == 1 && v:register == '"'
let reg = '"0'
elseif v:register != '"'
let reg = '"' . v:register
endif
let mode = ''
if a:mode == 'v'
let mode = 'gv'
endif
exe "norm! " . mode . reg . a:cmd
endfunction
command! -bar -nargs=0 TogglePasteCopy let g:paste_copy = exists('g:paste_copy') && g:paste_copy == 1 ? 0 : 1<bar>echo g:paste_copy ? ' paste_copy' : 'nopaste_copy'
nnoremap <silent> p :call PasteCopy('p', 'n')<cr>
nnoremap <silent> P :call PasteCopy('P', 'n')<cr>
nnoremap <silent> ]p :call PasteCopy(']p', 'n')<cr>
nnoremap <silent> [p :call PasteCopy('[p', 'n')<cr>
nnoremap <silent> ]P :call PasteCopy(']P', 'n')<cr>
nnoremap <silent> [P :call PasteCopy('[P', 'n')<cr>
vnoremap <silent> p :<c-u>call PasteCopy('p', 'v')<cr>
vnoremap <silent> P :<c-u>call PasteCopy('P', 'v')<cr>
You can toggle your paste_copy mode via :TogglePasteCopy. You may prefer a mapping like so
nnoremap <leader>tp :TogglePasteCopy<cr>
As a closing piece of advice I would highly suggest using "0p or using a named register over this approach as they are native to vim and there is one less "mode" to worry about.
I often use vim's / search capabilities and will use n to jump to the next match. However, when the cursor jumps to the next match and the screen redraws, it is often not at all obvious where the cursor is on the screen (and thus where the next match is). In the past, I have had to do a jk dance to make the cursor move so I can find it. My cursor does not blink by default (I find that annoying), but what I would like is this: when the cursor jumps to the next match, it should change color or blink briefly to draw attention to its placement on the screen, then switch back to the default cursor behavior. How can I create this behavior in my .vimrc file? My google-fu has failed me thus far.
Note: I am aware there is a setting for highlighting all search matches (hlsearch), but I prefer to keep my view clean. Temporarily highlighting the current match would be fine, but I want to only draw attention to the current match, not all matches.
I use this in my .vimrc, which will center the search term in the middle of your display. This not only makes it easy to find the search term, but also automatically provides me with enough context before and after that I usually don't need to scroll around after searching.
" Center the display line after searches. (This makes it *much* easier to see
" the matched line.)
"
" More info: http://www.vim.org/tips/tip.php?tip_id=528
"
nnoremap n nzz
nnoremap N Nzz
nnoremap * *zz
nnoremap # #zz
nnoremap g* g*zz
nnoremap g# g#zz
Steve Losh made something similar - when you jump to a next location (n key) the cursor blinks! Here's how it works screencast, and here is the code (see older commits for some variations on the theme).
I whipped up a couple of functions that seem to handle this alright. They may not be the best implementation but they seem to work.
function! s:NextMatch()
let param = getreg('/')
let pos = getpos('.')
let next_match = matchadd('Search', '\%'.pos[1].'l\%'.pos[2].'v'.param)
redraw
sleep 250ms
silent! call matchdelete(next_match)
endfunction
function! s:DoNextMatch()
let cmd_type = getcmdtype()
if cmd_type == '/' || cmd_type == '?'
return "\<cr>:call " . s:SID() . "NextMatch()\<cr>"
endif
return "\<cr>"
endfunction
function s:SID()
return matchstr(expand('<sfile>'), '<SNR>\d\+_\zeSID$')
endfun
nnoremap <silent> n n:call <sid>NextMatch()<cr>
nnoremap <silent> N N:call <sid>NextMatch()<cr>
cnoremap <silent> <expr> <cr> <sid>DoNextMatch()
Tested with: vim -u test.vim -N file.txt