2

Background

I'm attempting to remap the arrow keys to move by word while staying within the current line. I.e. I'm looking for a behavior similar to w and b, but that acts like h and l in the sense that it doesn't move to a line above or below. For moving right, I have the current solution:

nnoremap <expr> <Right> getline('.')[col('.')-1:] =~# '\s\S' ? 'w' : '$'

It gets most of the way there, but since \s\S is only looking to see if there are more whitespaces, the behavior breaks down at the end of a line. For instance, it misses instrs in the following example line:`

'>'::xs -> parse_chars xs ((Next 1)::instrs)

Question

How do I get the behavior I'm looking for? Is there any way to regex match a "vim word" to get the desired behavior?

Edit

I'm aware that this is technically possible by a short script using norm, like below:

function! CustomRight()
    let last = line('.')
    norm w
    if line('.') != last
        norm b$
    endif
endfunction

But this isn't ideal, since norm brings you into normal mode. So it wouldn't work in visual mode.

3
  • 1
    Not exactly sure, but I would try nnoremap <expr> <Right> getline('.')[col('.')-1:] =~# '\<' ? 'w' : '$' so check if there is a word-boundary atom anywhere on the right Jun 9, 2021 at 5:59
  • @ChristianBrabandt I guess \< must be a vim-regex dialect for something other than what vim considers to be words (in w and b)? It doesn't seem to work correctly near the end of some lines. For instance, If I try it on the solution you posted it will skip from the first apostrophe in ... w' : '$' to the end of the line.
    – mortelsson
    Jun 9, 2021 at 16:35
  • 1
    well, yes, those are technically not beginning of words :). BTW: Check the help for any unknown regex atom like this: :h /\<. Jun 9, 2021 at 16:41

1 Answer 1

1

This is what I came up with:

:nnoremap <expr> <Right> col('.') == (col('$') - 1) \|\| getline('.')[col('.')-1:] =~# '^[^[:keyword:]]\+$' ? '$' : 'w'

Unfortunately it still doesn't work quite right, so I came up with this:

:nnoremap <expr> <Right> col('.') == (col('$') - 1) \|\| getline('.')[col('.')-1:] =~# '^[^[:keyword:]]\+\s*$\\|^\k\+\s*$' ? '$' : 'w'
4
  • Huh, I thought there were \w and \W atoms for word and WORD characters
    – D. Ben Knoble
    Jun 9, 2021 at 2:10
  • @D.BenKnoble There are, and I probably misunderstood mortelsson's requirements. It can be adjusted, though. (Although the w and b commands do rely on 'iskeyword'.)
    – Heptite
    Jun 9, 2021 at 2:59
  • 2
    you might simply try the \< beginning of word atom Jun 9, 2021 at 6:00
  • The second solution seems to do the trick. Very nice!
    – mortelsson
    Jun 9, 2021 at 16:20

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.