'Make { and } ignore lines containing only whitespace
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?
Solution 1:[1]
Here's a modified version that handles counts correctly:
function! ParagraphMove(delta, visual, count)
normal m'
normal |
if a:visual
normal gv
endif
if a:count == 0
let limit = 1
else
let limit = a:count
endif
let i = 0
while i < limit
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
let i += 1
endwhile
normal |
endfunction
nnoremap <silent> } :<C-U>call ParagraphMove( 1, 0, v:count)<CR>
onoremap <silent> } :<C-U>call ParagraphMove( 1, 0, v:count)<CR>
" vnoremap <silent> } :<C-U>call ParagraphMove( 1, 1)<CR>
nnoremap <silent> { :<C-U>call ParagraphMove(-1, 0, v:count)<CR>
onoremap <silent> { :<C-U>call ParagraphMove(-1, 0, v:count)<CR>
" vnoremap <silent> { :<C-U>call ParagraphMove(-1, 1)<CR>
Solution 2:[2]
As said before, if you run :help paragraph you will see that lines with whitespace are not treated as a boundary.
In the mean time there are two plugin projects which could help:
- Improved paragraph motion (mirrored as https://github.com/vim-scripts/Improved-paragraph-motion)
- Vim Paragraph Motion based on the code in the other answers.
If you use Pathogen, simply download from one of the sites mentioned above.
If you use Vundle, put one of the following in your .vimrc:
Improved paragraph motion:
Bundle 'vim-scripts/Improved-paragraph-motion'Vim Paragraph Motion:
Bundle 'dbakker/vim-paragraph-motion'
Run :BundleInstall after a reboot and the { } motions should stop on lines containing whitespace characters.
Solution 3:[3]
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.
Solution 4:[4]
The { and } commands move by "paragraph", and vim's documentation (see :help paragraph) says:
Note that a blank line (only containing white space) is NOT a paragraph boundary.
So the only way you can do this would be to remap { and }. Something like:
nmap { ?^\\s*$<CR>
nmap } /^\\s*$<CR>
could work, but you may want to adjust this so it doesn't alter your search history.
Solution 5:[5]
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.
Solution 6:[6]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | keithr |
| Solution 2 | JBert |
| Solution 3 | Mike P |
| Solution 4 | Laurence Gonsalves |
| Solution 5 | eremite |
| Solution 6 | user2153235 |
