2

First, I'm not sure just mapping j to gj always is a good idea, because, for instance, I don't want j to behave as gj when wrap is off and the line is longer than the screen.

How can I make 0, j, k, ^, $ behave like g0, gj, gk, g^, g$ when wrap is set? What is the proper way to do so?

I thought a good starting point could be

function! s:setDisplayLinesMovementWhenWrapOn()
  if &wrap
    nnoremap <buffer> j gj
    nnoremap <buffer> k gk
    nnoremap <buffer> 0 g0
    nnoremap <buffer> ^ g^
    nnoremap <buffer> $ g$
  else
    nunmap <buffer> j
    nunmap <buffer> k
    nunmap <buffer> 0
    nunmap <buffer> ^
    nunmap <buffer> $
  endif
endfunction

augroup DisplayLinesMovementWhenWrapOn
  autocmd!
  autocmd OptionSet wrap call s:setDisplayLinesMovementWhenWrapOn()
augroup END

But probably I also need another autocmd to call s:setDisplayLinesMovementWhenWrapOn when a buffer is read? Or a file? Or what?

1 Answer 1

2

You can use expression mappings for cases like this; normally a Vim mapping just sends the keys on the right-hand-side of a :map command straight to Vim, but with expression mappings it's interpreted as a VimScript expression, and the resulting value is used. You can use this to check if wrap is set.

nnoremap <expr> j &wrap ? 'gj' : 'j'

As far as I know and as I read the docs, gj (and related) already behave identical to j when wrapping is off, so I'm not sure if this is a very useful mapping as such, but this is the general strategy to make mappings behave different depending on which settings you have enabled/disabled.


Bonus tip: you can also use :execute to create mappings, since all of these are so similar. For example:

for k in 'jk0^$'
    exe printf("nnoremap <expr> %s &wrap ? 'g%s' : '%s'", k, k, k)
endfor
3
  • Yes, I think gj behaves like j when wrap is off; however, g0 and g$ have different effects depending on whether wrap is on or off, but in neither case they behave as 0 and $.
    – Enlico
    Jun 5, 2022 at 16:51
  • Ah right @Enlico; I just checked the docs for gj and assumed that would apply to all the g* movement commands. Jun 5, 2022 at 19:28
  • As a tip for the readers, I ended up using &wrap && v:count == 0 as the discriminating condition for j and k, the reason being that since I use relativenumber, when I put a count for j and k I most likely don't want to move across a single wrapped line (even if I wanted, I wouldn't have a way to know what the count should be other than counting, so it's just more practical to hit j/k repeatedly).
    – Enlico
    Nov 30, 2022 at 12:50

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.