How to Manage Documents With Long Lines in Vim

When using a text editor as a software developer, we're generally aware of conventions around line length, and develop good habits, or adhere to coding standards established by the team or community that we're contributing to. We rarely have to cope with very long lines, or thinking about the formatting impact of a carriage return.

However, sometimes we write documents - plain or structured text - and here it's a little less clear.

Vim's Default Behaviour

If we take an out-of-the-box Vim, with its default settings, here is how it will handle text:
Screen-Shot-2018-04-01-at-09.54.02

I took some text, and pasted it into Vim, on my mac, with its out-of-the box behaviour.

Now if I resize my terminal, watch what happens to the lines:

Screen-Shot-2018-04-01-at-09.54.35

Let's try to classify this:

  1. The text will fill the entire width of the screen. If you're using a terminal emulator, the text will start on the far left and flow to the far right, without any margin.
  2. As you resize the terminal (or editor, if you use gvim or macvim) the text will wrap to fit in the visible window, but may wrap in the middle of a word.
  3. If you want the line to be shorter, you must insert a manual line break, with 'carriage return'.

This isn't a very useful set of defaults, in my view, for a number of reasons:

  • It's not clear to me whether there are any line breaks, or the line just happened to wrap at the end of a word.
  • It's not easy for me to see or refer to lines - I'd like to see some numbers.
  • I like to work in a full-screen environment, and I have a high-resolution display, so my screen could be hundreds of characters wide. That's hard to read.
  • I try to be sensitive to other people's needs, or the needs of tools which might interact with what I write - so I'd like to know when I'm getting close to or exceeding a certain width, and sometimes I'd like hard wrapping to happen automatically.
  • Sometimes it's not desirable for lines to have hard breaks in them, but I'd still like to read them at a certain width.
  • As I interact with the text, adding or removing text, I want a seamless and enjoyable experience that doesn't distract me from the matter at hand - writing.

With this in mind, lets work through the various ways there are in Vim to control wrapping, and interaction with long lines.

Make Vim's Behaviour Explicit

The first thing we might like to do is be explicit about our lines. Without some explicit indicator, we may inherit a document from someone which contains line breaks, but which appears not to.

We can be certain by setting either number or list. You could set both, but that would probably be overkill.

Show line numbers with number

From normal mode, set or unset line numbering like this:

:set number
:set nonumber

You'll now see clearly that your line is one, very long line:

Screen-Shot-2018-04-01-at-09.55.57

It's obvious that after "character;" there's not a newline character, and that our document is really just four long lines.

Show end of line and tab characters with list

It can be helpful to see the end of a line, and any tab characters. Setting list will, by default, show a line end with a $ sign, and a tab with ^I.

Screen-Shot-2018-04-01-at-09.59.13

This can be toggled:

:set list
:set nolist

In the example, I switched off number mode, and enabled list instead. Personally I find the number mode more useful, but both convey the information we were previously lacking.

Show 'soft' wrapping line continuations with showbreak

Another handy setting is showbreak. This gives an indication when a line has been wrapped, using a character such as > or +++. An attractive option here is to the the unicode elipsis symbol: …

To set showbreak do:

:set showbreak=>

To set a unicode character, when it's time to enter the character you want, enter C-v u and then the unicode number, which in this case is 2026.

Here's the effect in action:

Screen-Shot-2018-04-01-at-10.02.38

How Vim Wraps Text

The default behaviour we saw, where text runs onto the next line at the edge of the visible display is known as 'wrapping'.

In what follows I will discuss the various approaches to tweaking Vim's behaviour, but before doing so, in anticipation that you might want to experiment as you read, let me first talk about reformatting.

Reformat with gw or gq

Vim allows selective reformatting with the gq or gw command. The difference is that gq allows external programs or algorithms to be used, and gw always uses Vim's own. Both commands take a motion, which means we have complete flexibility on which lines we reformat. For example, to reformat the whole document, use gg to get the start, then run gqG, with the motion G passing over every line, until the end of the file. To reformat to the end of the paragraph, use gq}, or to the whole paragraph with gqip.

Alternatively, a series of lines or a block of lines can be selected using V or c-v, followed by gq.

Depending on which setting you alter, and in which context you're writing, changes you make to wrapping behaviour may well not seem to have an impact on text already entered. If you get used to running a reformat command after making a change, you'll always be in a known state.

Use wrap to wrap lines longer than the screen's width

Returning to wrapping, if we disable wrapping, the line will continue beyond the visible width of the screen, if it's long enough.

Wrapping can be toggled like this:

:set wrap
:set nowrap

Here's what happens if wrapping is disabled:

Screen-Shot-2018-04-01-at-10.03.47

Our four long lines are now not wrapping at all, and go off the screen.

Use linebreak to break at word boundaries

I don't like to see lines going off the edge of the screen, so having wrapping enabled seems like a good move. However, I also don't like to see words cut off arbitrarily. This behaviour can be altered with the linebreak setting. If this is on, Vim will break at the end of a word instead. Here's the difference:

Screen-Shot-2018-04-01-at-10.05.43

In this example, I've set number, showbreak and linebreak. If you look at the start and end of the line, that Vim is now displaying them within the visible width of the display, but without breaking lines in the middle of words.

As an aside, linebreak is not compatible with list, so if you want explicit wrapping to be visualised, set showbreak and/or number instead, and ensure nolist has been set.

This is progress of a sort. However, as I mentioned, I use a full-screen terminal, or a tiling window manager, so with these settings, my screen looks like this:

Screen-Shot-2018-04-01-at-10.08.15

This is much too wide for comfortable comprehension and scanning.

Use columns to maintain a visual width narrower than the size of your screen

Vim's default behaviour made sense when terminals were no more than 80 characters wide, but modern screens could easily accommodate three times as much text as this!

We can tell Vim to wrap at a certain column width, to compensate. This is particularly effective for those not using a resizable window, because if your terminal or edit is resizable, changing the columns setting will cause the window to resize to the width you specified. Resizing the window will change the column width again. For example, if I set my columns to 120, the editor or terminal will or grow to the same width:

Screen-Shot-2018-04-01-at-10.11.38

If I then make my window a little smaller, to see something else on the screen, the number of columns will decrease accordingly:

Screen-Shot-2018-04-01-at-10.12.55

Similarly, if I set it to 72, but then made my window a bit bigger, the columns will grow!

This feels suboptimal. We can get around it with a bit of ingenuity though. For me, it's not a big deal, as I almost never use resizable windows, but here's how it's done:

:autocmd VimResized * | set columns=72

Event handling with autocommands is a whole subject in itself, but in essence, Vim makes it possible to watch for events, and provides hooks to intercept them and take action. In this case, we tell Vim that if Vim resizes, with any file being edited, set the columns to 72. If we make the visual display narrower than 72, Vim will sill wrap, but if it's larger, Vim will enforce a 72 column width.

Use textwidth to enforce hard line breaks

Some circumstances request or demand an explicit width that is not merely visual. We want the line formatting to persist on disk, and match what we saw in Vim, and be visible irrespective of what we use to view the text. For example, the verbose portion of a Git commit should we no wider than 72 characters - this allows for git log padding, and centralises the message. Emails should generally be written to enforce a line break at a sensible length, and some open source projects set standard for documentation, in markdown, or restructured text. Again, 72 is a commonly used width.

If we want to impose a hard width, we can do that by explicitly stating how wide the text can be before a carriage return will be inserted. This is done with the textwidth setting:

:set textwidth=72

If I set textwidth to 72, on my wide display, and then paste in a long line, I'll see that Vim inserts new lines to break up the text and make it fit:

Screen-Shot-2018-04-01-at-10.16.59

The line numbering, and the showbreak options are still enabled, which makes it very clear that these most-recently inserted lines have been formatted by Vim to honour my 72 character width constraint.

Note, however, that the previous lines have not been reformatted, and will need to be reformatted using gq or gw:

Screen-Shot-2018-04-01-at-10.19.44

Another handy setting, available in Vim 7.3 and above, is 'colorcolumn' - this will highlight a certain column, making it easy to align text. It can be set to a fixed width, such as 72, or relative to the textwidth:

:set colorcolumn=72
:set colorcolumn=-2

Screen-Shot-2018-04-01-at-10.21.18

Use formatoptions to reformat edited lines dynamically

What happens if we go back and make changes to lines which have been resized previously? The last example was set up with a textwidth of 72, and a colorcolumn. Let's add a caveat to the wisdom of the Dalai Lama:

Screen-Shot-2018-04-01-at-10.23.45

Vim has made an effort break the line (although we see we went over the 72 char width), but it didn't reflow the text underneath, and showbreak indicates that some soft-wrapping has taken place.

A quick gqip fixes this, but it would be nice if this just happened on the fly.

This behaviour can be altered with the formatoptions setting. To see the current settings, run:

:set formatoptions

The standard is tcq. If I add the a setting, like this:

:set formatoptions+=a

Now whenever any change is made to a line, the whole paragraph is dynamically resized. Let's teach his holiness about the cloud:

Screen-Shot-2018-04-01-at-10.29.55

Vim resized this for me as I typed, without any need to issue a separate gqip command.

Wrapping Up... ;)

This article should have given you a clear understanding of how line wrapping works in Vim, and you should now know the various settings which you can tweak in order to get yourself set up in which ever way suits your needs.

Vim has excellent in-editor help, so explore it with :help - just note that many of the terms have more than one meaning, depending on context, so try quoting the term, if you find yourself reading about an obscure part of Vimscript!

Of course, all of these settings can be placed in your own vim config, and using autocmd you can detect which files need which sorts of setups. You can also set up new commands, macros, and shortcuts, or keypresses to toggle various settings.

I wish you many happy and productive hours of writing.

Show Comments