1

Since Vim considers paragraphs as lines/sentences separated by blank lines the paragraph movement with { and } feels little weird to me as it takes you to the next blank line and you always have to press either w or j to go to the actual text.

So i thought of remapping this behaviour, the forward movement is pretty simple as you can create a mapping like below

nmap } }w
nmap } }j

However I am not able to create a mapping to create a mapping to move backward because it kind of creates a loop

nmap { {j
nmap { {w

The above mappings do not seem to work because once you move down with j or w the next { will again takes you back to empty line.

So is there any work around to this ?

  • Looks like you're trying to use a non-conditional move operation to do a conditional move. IOW what you basically want is if (cursor past first char of paragraph) then {j else {{j , yes? – B Layer Feb 2 at 14:56
  • And how can I achieve that? – Rohit Bhanot Feb 2 at 16:13
  • I guess, something like this should do it: nnoremap <expr><silent> { (col('.')==1 && len(getline(line('.')-1))==0? '2{j' : '{j') – Christian Brabandt Feb 3 at 15:07
  • @ChristianBrabandt, it works like a charm, could you also explain the mapping for me, I am new to VimL so just wanted to understand how it works. – Rohit Bhanot Feb 6 at 6:50
1

If I understand correctly what you want, the following mapping achieves it:

nnoremap <expr><silent> { (col('.')==1 && len(getline(line('.')-1))==0? '2{j' : '{j')

This is a map expression, that means one can use expression have evaluated at the time the mapping is performed and react to certain conditions.

In the specific case, it checks, whether the cursor is at the beginning of a line (col('.')==1) and the line before that is empty (len(getline(line('.')-1))==0). If that is the case, it will perform the motion 2{j (to not end at the same place with the {j, else it will perform only {j.

  • Exactly what I wanted. – Rohit Bhanot Feb 8 at 7:15
  • Just a small query so what does this (getline(line('.')-1)) return, I can guess that line('.')-1 returns the one line above from my cursor position, but what does getline returns. – Rohit Bhanot Feb 8 at 7:23
  • 1
    correct. and getline returns the content of the specified line number – Christian Brabandt Feb 8 at 7:35
0

This feels kludgy to me, but it's my first vim function, and I still haven't done a custom command yet... It's not used by the d, c, and y commands as a motion.

fun! PriorParagraph() range
  let s:Redraw = &lazyredraw
  let &lazyredraw = 1
  " If our current line is not blank, and the prior line is blank
  if len(getline(line('.'))) > 0 && len(getline(line('.') - 1)) == 0
    " then figure out if we are to the right of the start of the line.
    let s:Curpos = col('.')
    normal ^
    " If we're not to the right of the start of the line, go back another
    " paragraph.
    if s:Curpos <= col('.')
      normal! {
    endif
  endif
  " Was there a count? If so, handle it.
  let s:Count = a:lastline - a:firstline
  if s:Count
    for x in range(1, s:Count)
      normal! {
    endfor
  endif
  normal! {w
  let &lazyredraw = s:Redraw
  return
endfun!
nnoremap { :call PriorParagraph()<CR>

fun! NextParagraph() range
  let s:View      = winsaveview()
  let s:Redraw = &lazyredraw
  let &lazyredraw = 1
  " If we're not on a blank line, we need to go down at least two
  " paragraphs before coming back up one.
  if len(getline(s:StartLine))
    normal! }
  endif
  " Was there a count? If so, handle it.
  let s:Count = a:lastline - a:firstline
  if s:Count > 0
    for x in range(1, s:Count)
      normal! }
    endfor
  endif
  " We're on a blank line or at EOF. If we're at EOF, }{ can take us back
  " up. So check where we are before we }{w.
  let s:StartLine = line('.')
  normal! }{w
  " If we were at EOF, go back there.
  if s:StartLine >= line('.')
    normal! }
  endif
  let s:View.col  = col('.') - 1
  let s:View.lnum = line('.')
  let s:View.curswant = s:View.col
  call winrestview(s:View)
  let &lazyredraw = s:Redraw
  return
endfun!
nnoremap } :call NextParagraph()<CR>
0

I have defined following mappings using the search function to avoid messing up search history:

nnoremap <silent> } :call search('\(^$\n\s*\zs\S\)\<bar>\(\S\ze\n*\%$\)', 'sW')<CR>
nnoremap <silent> { :call search('\(^$\n\s*\zs\S\)\<bar>\(^\%1l\s*\zs\S\)','sWb')<CR>

You can jump to a possibly indented beginning of a paragraph with } and {. Additionally, at the last paragraph you jump to the end of the last line:



    CURSOR Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet.

    CURSOR Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet. CURSOR



Variant

If you prefer to jump to the start or end of the file as well, use following mapping:

nnoremap <silent> } :call search('\(^$\n\s*\zs\S\)\<bar>\%$', 'sW')<CR>
nnoremap <silent> { :call search('\(^$\n\s*\zs\S\)\<bar>\%1l','sWb')<CR>
CURSOR


    CURSOR Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet.

    CURSOR Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren,
no sea takimata sanctus est Lorem ipsum dolor sit amet.


CURSOR

(remove CURSOR to test also the behavior with whitespace)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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