How to use Vim's textwidth like a pro
March 5, 2010There 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=72to 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
tflag 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.
I find fo=want to be useful when working on RST documents or emails. Easy mnemonic, too.
:set fo=want
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.
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.
@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
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
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
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
Since vim 7.3, you can also use:
set colorcolumn=+1
To set a vertical line on {textwidth}+1
Edward: This is a really great suggestion, and what I use now!
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).
:set tw”." my setting set fo+=1rnojmBl set fo-=t set tw=72 set colorcolumn=80 “Mark ideal textwidth, I perfer fixed colorcolumn not “+1”
‘mB’ is for multi-bytes language ’l’ is also needed in my case, used to diable auto-formatting when editing, only done with ‘gq’ ‘ro’ is for more intelligent formatting on comments ‘1n’ if for more intelligent formatting on lines start with number sequence
check :h formatoptions and :h fo-table for more detailed explanation
I have set tw=75 set fo+=tcjro
and I’m still not getting c- or C++- style comment (/…/ or //…) wrapped.
How do I make these comments wrap?
Let me clarify: I’m seeing for example // boinon 4890jht b0di8n jhbxui hgkjd nj oingb uiounbjkdsfniogh oignoi oign oin
The second line (starting with “oin”) should have a // in front of it.
gw, which is the same asgqbut you cursor left in the same place where it was.I prefer the overlength line highlights shown here, instead of cursorcolumn, because this method only highlights lines that are actually too long, so is visually silent if nothing is wrong.
Someone above asked about a function to toggle the highlights. I’ve been wrestling with it for a while this morning, and I don’t really know what I’m doing, but this seems to work. I’d love to hear if it can be sensibly abbreviated.