Inside 206-105

Existential Pontification and Generalized Abstract Digressions

How to use Vim’s textwidth like a pro

There are lots of little blog posts containing advice about various one-line options you can do in Vim. This post falls into that category, but I'm hoping to do a more comprehensive view into one small subsystem of Vim's configuration: automatic line wrapping.

When programming, automatic line wrapping can be a little obnoxious because even if a piece of code is hanging past the recommended 72/80 column width line, you probably don't want to immediately break it; but if you're writing a text document or an email message, that is specifically the behavior you want. By default, vim does no automatic line wrapping for you; turning it on is a question of being able to toggle it on and off when you want it.

Here are the configuration options you care about:

  • textwidth (or tw): controls the wrap width you would like to use. Use :set tw=72 to set the wrap width; by default it's unset and thus disables line-wrapping. If this value is set, you're entirely at the whimsy of the below formatoptions, which is often filetype sensitive.
  • formatoptions (or fo): controls whether or not automatic text wrapping is enabled, depending on whether or not the t flag is set. Toggle the flag on with :set fo+=t, and toggle it off with :set fo-=t. There are also a number of auxiliary format options, but they're not as important.
  • wrapmargin (or wm): controls when to wrap based on terminal size; I generally find using this to be a bad idea.

Understanding the interaction between these two options is important. Here is a short table of interactions:

  • tw=0 fo=cq wm=0: No automatic wrapping, rewrapping will wrap to 80
  • tw=72 fo=cq wm=0: No automatic wrapping, rewrapping will wrap to 72
  • tw=0 fo=cqt wm=0: No automatic wrapping, rewrapping will wrap to 72
  • tw=0 fo=cqt wm=5: Automatic wrapping at a 5 col right margin
  • tw=72 fo=cqt wm=0: Automatic wrapping at col 72

Notice that to get automatic wrapping you need both fo+=t as well as tw or wm to be nonzero. Note also that some filetype will automatically give you fo+=t, while others won't.

Here are the keystrokes you care about:

  • gq: performs a "formatting operation", which in our universe means "rewrap the text." This will respect leading indent and symbolic characters, which is usually nice but a little obnoxious if you're reflowing a bullet point (since the text will suddenly acquire asterisks in front of everything).
  • The paragraph motions. The big one is vip (preceding v puts us in visual mode, for selection), which selects an "inner paragraph"; this means that if you're anywhere inside of a paragraph, you can type vip and have the entire thing instantly selected for you, possibly for you to run gq subsequently. vap is also equivalent, although it selects a whole paragraph and is more appropriate if you want to, say, delete it. The curly braces move you between paragraphs.

The value of format-options will drastically change the way Vim behaves, so I highly recommend keeping it displayed some where you can reference it quickly. I use:

set statusline=...[%{&fo}]...

You probably have a statusline of your own; just add that small snippet minus the ellipses in somewhere convenient. For further good measure, I explicitly say set fo-=t in my vimrc, to prevent myself from being surprised (since I do primarily coding in vim).

One more neat trick:

augroup vimrc_autocmds
  autocmd BufEnter * highlight OverLength ctermbg=darkgrey guibg=#592929
  autocmd BufEnter * match OverLength /\%74v.*/
augroup END

This will highlight all characters past 74 columns (tweak that number as desired) in dark grey (tweak that color as desired), and is a nice visual cue when auto linewrapping isn't turned on when you should think about breaking things.

21 Responses to “How to use Vim’s textwidth like a pro”

  1. Andrey Popp says:

    Yeah, the last one trick I was looking for very long, thanks.

  2. Mr. Icon says:

    I find fo=want to be useful when working on RST documents or emails. Easy mnemonic, too.

    :set fo=want

  3. steve says:

    vap is also equivalent, although it selects a whole paragraph and is more appropriate if you want to, say, delete it.

    What is the difference between vip and vap? I couldn’t find one when testing, and the help entries for ‘ap’ and ‘ip’ are the same.

  4. Good question! The difference is only visible if you have a blank line(s) after your paragraph. vip (inner) will not select the trailing blank newline; vap (all) will select all trailing newlines. This is most obvious if you have a paragraph afterwards; vipd will leave extra whitespace; vapd will not.

  5. steve says:

    vip (inner) will not select the trailing blank newline; vap (all) will select all trailing newlines.

    Hm. I didn’t see that because I tested with the following:
    ____
    FIRST\n
    \n
    SECOND
    ——–

    On the F in FIRST, ‘yipp’ and ‘yapp’ both result in

    FIRST\n
    FIRST\n
    \n
    SECOND

    rather than

    FIRST\n
    \n
    FIRST\n
    \n
    SECOND

    Although, I suspect that’s not got anything to do with ‘ap’ and ‘ip’ sometimm, but instead is that the rules of ‘p’ are more complicated than I think they are.

  6. Vikas says:

    @steve:
    My expected result of “yapp” in the case mentioned by you is:
    FIRST\n
    FIRST\n
    \n
    SECOND
    \n

    To get the result you expect, you should do “yapjp” instead

  7. mikisvaz says:

    I use gqap to format a paragraph

  8. Marc says:

    Hi and thanks for this article, the last trick is really good (the highlight OverLength one), but how could I have a function highlight the overlength chars, and when I call this function again stop highlighting them ? because it’s annoying to highlight these chars always, as for some config files there a lots of long lines and I don’t need them highlighted. Thx anyway, keep posting good & deep tips (esp. deep ones, going thoroughly on one special feature of our favorite editor).

  9. I don’t know, and I’d love to know the answer if there is one. I suspect this has to do with autocommand naming and selective disabling.

  10. Jithin says:

    Hi,
    For some reason The highlighting part is not happening for me.

    I have these in my vimrc

    set textwidth=80
    set fo-=t “prevent auto word wrapping
    augroup vimrc_autocmds
    autocmd BufRead * highlight OverLength ctermbg=darkgrey guibg=#592929
    autocmd BufRead * match OverLength /\%80v.*/
    augroup END

    Can you help me out in what is going wrong ?

    augroup END

  11. It looks like the BufRead command only triggers when you edit an old file. Try BufEnter; I’ve updated my post accordingly.

  12. William Robertson says:

    Thanks for the tip! I’d come across textwidth before but never really got to the bottom of it. In particular I found that even when I set tw=0 in my _vimrc, reloading _vimrc itself or any .vim file would set it back to 78 – a bit short for me since I no longer use punch cards or a vt100 monitor. It turned out that the copy of vim.vim in ftplugin (there seem to be several) was the culprit. Copied that to my local vimfiles\ftplugin, edited it, problem solved :)

  13. Todd Eddy says:

    Just wanted to say thanks for pointing me in right direction (formatoptions) so here’s a tip that’s different than your “one more neat trick”.

    In vim 7.3 this is built in. Place this in your vimrc (not sure if this will format as code so just indent everything between the start and end if to make it look pretty)

    " Vim v7.3 settingsĀ·
    if v:version >= 703
    " Mark ideal text width (set by textwidth)
    set colorcolumn=+1
    endif

    now you’ll see a bar where the ideal width should be. Problem I was running into is in programming the autowrap doesn’t work too well. So I have that individual filetype set “formatoptions-=t” so it doesn’t auto wrap code but it will still autowrap comments which is what I want.

    Rest of my vim stuff if people are curious: https://github.com/vrillusions/dotfiles

  14. Faheem says:

    Thanks! Toggling fo was what I needed. However, regarding using ‘vip’ for paragraph selection, how can I follow it up with a ‘comment (#) the selected paragraph?’ Thanks

  15. Faheem says:

    Figured that a simple vmap in my vimrc takes care of the ‘comment’ bit:

    ” comment/uncomment blocks of code (in vmode)
    vmap ## :s/^/#/gi:nohl

  16. Phil says:

    Since vim 7.3, you can also use:

    set colorcolumn=+1

    To set a vertical line on {textwidth}+1

  17. Jason says:

    gqip is my new favorite compound command! I’ve been looking for this for a while!

  18. […] for automatically wrapping, there was a good article introducing textwidth and formatoption. However, strangely that they seems no effect on my […]

  19. ipirlo says:

    @Faheem, try the pluggin tcomment or nerd commenter, quite a few useful commenting commands

  20. arturo says:

    Long time i was searching something like this, thanks very much!!

  21. Chris Corbyn says:

    set fo+=a

    This will give you much more expected behaviour when you are editing in the middle of a line (the entire paragraph will be reformatted as you type).

Leave a Comment