0

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 2

3

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>.

4
  • 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.
    – Pirx
    Mar 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.
    – Pirx
    Mar 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 with col('.') (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.
    – Rich
    Mar 12, 2018 at 16:49
0

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.