18

Very often, I write markdown in VIM, and there will be paragraphs in those markdown. To help my editing, I setup my Vim to wrap a line on 80 chars. It works nice if I just keep typing, but the problem is if I need to do some correction, it becomes very annoying.

demo(taken from wikipedia first order logic):

The adjective "first-order" distinguishes first-order logic from higher-order logic 
in which there are predicates having predicates or functions as arguments. In first-order 
theories, predicates are often associated with sets. In interpreted higher-order 
theories, predicates may be interpreted as sets of sets.

So far so good. But when I revise the article, I might decide to add something in the middle, say:

The adjective "first-order" distinguishes first-order logic from higher-order logic 
in which there are predicates having predicates or functions as arguments,
or in which one or both of predicate quantifiers or function quantifiers are permitted.
In first-order theories, predicates are often associated with sets. In interpreted higher-order
theories, predicates may be interpreted as sets of sets.

notice line 3 is the one I want to wrap. If I do it in VIM, I will need to manually join the lines and rewrap the whole paragraph.

Anyone got idea how to make VIM do it automatically?

3 Answers 3

17

Even simpler: the a flag for 'formatoptions' enables automatic formatting of paragraphs whenever text is inserted or deleted. See :help fo-table for details on 'formatoptions' flags and :help autoformat.

:set formatoptions+=a

gq and gw will format the lines that the following motion moves over.

Formatting is done with one of three methods:
                1. If 'formatexpr' is not empty the expression is
                   evaluated.  This can differ for each buffer.
                2. If 'formatprg' is not empty an external program
                   is used.
                3. Otherwise formatting is done internally.

                In the third case the 'textwidth' option controls the
                length of each formatted line

The difference between the two, is that gq will leave the cursor on the first non-blank of the last formatted line. gw will put the cursor back where it started.

You can easily manually rewrap the paragraph your cursor is currently in with gwap, or the entire document with gggwG, though that will move your cursor thanks to the leading gg.

With an autocommand, you can have formatting happen automatically. Here's an example that formats the current paragraph when leaving insert mode:

augroup myformatting
    autocmd!
    autocmd InsertLeave * normal gwap<CR>
augroup END

There are other autocommand triggers that you may find work better for you. You can explore the options under :help autocmd-events. The most relevant ones are probably under the "various" subheading.

1
  • one word: brilliant!
    – Jason Hu
    Commented Mar 9, 2017 at 20:55
3

For the sake of completeness, I'd like to mention the plugin-based option.

If you use something like ALE which supports running your buffers through a beautifier on save, you could let Prettier handle rewrapping your code.

I accomplished that by putting this in ~/.vim/ftplugin/markdown.vim:

let b:ale_fixers = ['prettier', 'remove_trailing_lines', 'trim_whitespace']
let b:ale_javascript_prettier_options = '--prose-wrap always'

...and putting this in ~/.vimrc:

let g:ale_fix_on_save = 1
1

I would have a look at :help 'textwidth'. It will automatically break lines as you type. However this doesn't work if you're editing the middle of a line.

I personally prefer to leave textwidth off so I created a function that will auto join and split a paragraph. (Basically auto format it to 80 characters) It looks like this:

function! ParagraphToEightyChars()
   while (len(getline(".")) > 80)
      normal! 0
      " Find the first white-space character before the 81st character.
      call search('\(\%81v.*\)\@<!\s\(.*\s.\{-}\%81v\)\@!', 'c', line('.'))
      " Replace it with a new line.
      exe "normal! r\<CR>"
      " If the next line has words, join it to avoid weird paragraph breaks.
      if (getline(line('.')+1) =~ '\w')
         normal! J
      endif
   endwhile
   " Trim any accidental trailing whitespace
   :s/\s\+$//e
endfunction

I then have a mapping to call it whenever I need it:

nnoremap <silent><A-J> :call ParagraphToEightyChars()<CR>

This function works great with formatoptions+=jr for formatting comments in code too! Just put your cursor on the first line that's longer than 80 chars and call the function.

(Note: I've not made this function general to do lengths other than 80, but I think you only need to change the 80 and 81s if you want to make it something else)

See :help 'textwidth' and :help 'formatoptions' for more info.

2
  • Thanks for your sharing. As I check your setup, it's not automatically formatting as I type, correct? If so, then it's still a suboptimal solution, no?
    – Jason Hu
    Commented Mar 2, 2017 at 15:16
  • textwidth will automatically format as you type. My function will not. I prefer to control when vim wraps things, so it works for me. But if you're specifically looking for an as-you-type formatter, yes; it doesn't quite fit your workflow.
    – Tumbler41
    Commented Mar 2, 2017 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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