Make { and } ignore lines containing only whitespace

前端 未结 5 1699
一生所求
一生所求 2021-02-05 09:07

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 tre

相关标签:
5条回答
  • 2021-02-05 09:43

    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.

    0 讨论(0)
  • 2021-02-05 09:46

    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.

    0 讨论(0)
  • 2021-02-05 09:55

    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.

    0 讨论(0)
  • 2021-02-05 09:56

    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>
    
    0 讨论(0)
  • 2021-02-05 09:57

    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.

    0 讨论(0)
提交回复
热议问题