I'm completely new to Vim scripting, so forgive me if this may seem trivial, but I would like to modify the Behavior of the Home and End keys such that, if the cursor is somewhere between the first and last non-blank character of the line, they would take me to the first or last non-blank character, respectively. However, if the cursor is already sitting on the first or last character of the line, they go to the first or last non-blank character on the next line, respectively. I think I know some bits and pieces of how to do this, but I have trouble figuring out how to query for the two conditions (cursor on first or last character of the line). Seeing a complete solution would help me learn good coding style also. Thanks!
2 Answers
That's odd, I was quite sure this question was a duplicate, but I cannot find the other Q/A.
Anyway. This is how I proceed:
inoremap <silent> <Home> <c-o>@=<SID>HomeLikeVCpp()<cr>
nnoremap <silent> <Home> @=<SID>HomeLikeVCpp()<cr>
vnoremap <silent> <Home> @=<SID>HomeLikeVCpp()<cr>
inoremap <silent> <End> <c-\><c-n>@=<SID>EndLikeVCpp()<cr>a
nnoremap <silent> <End> @=<SID>EndLikeVCpp()<cr>
vnoremap <silent> <End> @=<SID>EndLikeVCpp()<cr>
function! s:HomeLikeVCpp()
let ll = strpart(getline('.'), -1, col('.'))
if ll =~ '^\s\+$' | return '0'
else | return '^'
endif
endfunction
function! s:EndLikeVCpp()
let l = strpart(getline('.'), col('.')-1)
let ll = match(l, '^\S\s*$')
if getline('.') =~ '^\s*$'
if col('.') + (mode()!='v') == col('$') | return 'g_'
else | return '$'
endif
else
if ll >= 0 | return '$'
else | return 'g_'
endif
endif
endfunction
Nowadays, I'd rewrite it with :map-<expr>
.
-
Hmm, that gets me started, I guess, but it's not what I was looking for. I tried to modify it to do what I want, but I guess I don't understand the logic in those functions. Also, I think what I want is easier to accomplish: All I need to know is if I'm currently on the first or last character (or simply first column or last character for an even simpler case). If I'm on the first character or column already, <Home> will move me down one line to the first character or column there, and if I'm on the last character, <End> will move me down to the last character of the next line.– PirxMar 12, 2018 at 15:26
-
Your code, on the other hand, stays on the line I'm at, just toggling back and forth between first/last column and first/last non-blank character.– PirxMar 12, 2018 at 15:27
-
Indeed. My mistake, you're right. My code mimics VC++6 behaviour. If you want to jump to next line, then return
<down>
. You can check the current column withcol('.')
(the result is 1-indexed). Mar 12, 2018 at 15:42 -
1@Pirx I think the return values you'll want to use are
'+'
for the move-down-and-to-first-non-blank and'jg_'
for move-down-and-to-last-non-blank.– RichMar 12, 2018 at 16:49
Thanks everybody for their pointers. Here is my solution, in case it's helpful to someone:
" Enhanced Home and End keys
inoremap <silent> <Home> <c-o>@=<SID>ExtHome()<cr>i
nnoremap <silent> <Home> @=<SID>ExtHome()<cr>
vnoremap <silent> <Home> @=<SID>ExtHome()<cr>
inoremap <silent> <End> <c-\><c-n>@=<SID>ExtEnd()<cr>a
nnoremap <silent> <End> @=<SID>ExtEnd()<cr>
vnoremap <silent> <End> @=<SID>ExtEnd()<cr>
function! s:ExtHome()
if col('.')=='1' | return 'j'
else | return '0'
endif
endfunction
function! s:ExtEnd()
if strlen(getline('.')) == 0 | return 'j'
elseif strlen(getline('.')) == col('.') | return 'j'
else | return '$'
endif
endfunction