When you navigate by paragraph in vim using { and } it skips lines that contain nothing but whitespace though they are otherwise 'blank'.
How can I convince vim to treat "whitespace only" lines as paragraph breaks so { and } will jump to them?
When you navigate by paragraph in vim using { and } it skips lines that contain nothing but whitespace though they are otherwise 'blank'.
How can I convince vim to treat "whitespace only" lines as paragraph breaks so { and } will jump to them?
This is something that's bothered me for a long time. Probably the "right" solution would be to submit a patch to vim itself that would allow you to customize paragraph boundaries with a regex (like :set paragraphs, but actually useful).
In the meantime, I've made a function and a couple of mappings that almost do the right thing:
function! ParagraphMove(delta, visual)
normal m'
normal |
if a:visual
normal gv
endif
if a:delta > 0
" first whitespace-only line following a non-whitespace character
let pos1 = search("\\S", "W")
let pos2 = search("^\\s*$", "W")
if pos1 == 0 || pos2 == 0
let pos = search("\\%$", "W")
endif
elseif a:delta < 0
" first whitespace-only line preceding a non-whitespace character
let pos1 = search("\\S", "bW")
let pos2 = search("^\\s*$", "bW")
if pos1 == 0 || pos2 == 0
let pos = search("\\%^", "bW")
endif
endif
normal |
endfunction
nnoremap <silent> } :call ParagraphMove( 1, 0)<CR>
onoremap <silent> } :call ParagraphMove( 1, 0)<CR>
" vnoremap <silent> } :call ParagraphMove( 1, 1)<CR>
nnoremap <silent> { :call ParagraphMove(-1, 0)<CR>
onoremap <silent> { :call ParagraphMove(-1, 0)<CR>
" vnoremap <silent> { :call ParagraphMove(-1, 1)<CR>
This doesn't correctly handle counts like '4}' or visual mode correctly (uncomment the vnoremap lines at your peril), but seems ok for things like not clobbering the current search pattern and not flickering. Also, 'd}', 'y}', etc. seem to work ok. If anyone has ideas for making counts work or fixing visual mode, please let me know.
I never have a legitimate need for whitespace only lines so I solved this "problem" by adding the following to my .vimrc:
" Highlight spaces at the end of lines.
highlight link localWhitespaceError Error
au Syntax * syn match localWhitespaceError /\(\zs\%#\|\s\)\+$/ display
" Remove end of line white space.
noremap <Leader>r ma:%s/\s\+$//e<CR>`a
So then if { and } skips whitespace only lines I use my mapping to remove it and try again.
I finally caved and did something similar to
eremite. I previously had
Z mapped to {gq}, which reformats text from last
blank line to the next blank line. If lines
containing only spaces are not recognized as
boundaries, it can destroy a lot of intricate code
structures, and days of work. Undo is not an
option if I've switched buffers a few times using
<C-^>.
I leveraged a custom command command! Trim execute "normal \<S-m>" | % s=\s*$== | execute "normal \<C-o>z.\<C-o>" | set nohlsearch to
"Trim" all trailing spaces in my file. I have
expandtab enabled so I only ever have spaces, not
tabs. But it's easy enough to delete all trailing
space using \_s instead of \s. My new Z
command is nmap Z mq:Trim<CR>`q{gq}`q. I use
marker q to store my current cursor position,
then use `q to return to it after the
reformatting.