Vim and Breakindent

My contention: Programmers should never have to insert line breaks into long lines of code.

Why: The position of line breaks in long lines of code does not contain any semantic information.  Where coding standards limit line length, it is generally so that the code is easy to read by all developers, even when editing the file via a terminal.  I think that code should be easy to read for all developers regardless of their view settings, and that the ideal solution would use tools to make this so, rather than coding standards.

A step towards the solution: I often use Vim to edit Python files. Vim’s breakindent patch lets you edit files with long lines, with sensible wrapping based on the indentation of the original line.

Breakindent explained

Breakindent is a setting for Vim which means that wrapped lines have an indentation level starting at the indentation level of the line itself. Unfortunately, breakindent is not part of the standard Vim distribution.  I explain how to compile Vim with breakindent further on in this post.

The easiest way for me to demonstrate the use of breakindent is as follows.  Suppose I have a Python file whose contents are something like this:

class MyClass(object):
    def __init__(self, some_parameter_or_other):
        self.some_long_attribute = [i for i in some_parameter_or_other if
…i > 32768 and str(i) not in sys.argv]

Yes, that’s supposed to be one really long line. And the listing above is pretty much what the file would look like in Vim with the Vim settings linebreak on (break lines at word endings) and showbreak=…. If you want to have the ellipses for your showbreak, you do need to be using a version of Vim with unicode support.
Now suppose I have a version of Vim that has been compiled with the breakindent patch. If I turn the breakindent option on, all of a sudden the example looks like this:

class MyClass(object):
    def __init__(self, some_parameter_or_other):
        self.some_long_attribute = [i for i in some_parameter_or_other if
        …i > 32768 and str(i) not in sys.argv]

Notice that the long line wraps to the same indentation as the beginning of the line. But I can go one step further and set showbreak=…\ \ \ \ \ \ \ (that’s ellipses followed by seven escaped spaces). This will mean that the file is displayed like this:

class MyClass(object):
    def __init__(self, some_parameter_or_other):
        self.some_long_attribute = [i for i in some_parameter_or_other if
        …       i > 32768 and str(i) not in sys.argv]

I find that this makes the code look really neat no matter what the window width of my editor is. If you’re working in a team of course, you wouldn’t want to move to a standard of not breaking long lines until you’re sure that every member of your team has access to an editor that can do this sort of thing.

The Difficulty

On the face of it, breakindent seems to be a really useful option. The only thing that makes it less useful is that it doesn’t come with Vim. For quite a while Vim’s TODO help has included the following line:

-   Patch for 'breakindent' option: repeat indent for wrapped
    line. (Vaclav Smilauer, 2004 Sep 13, fix Oct 31, update 2007
    May 30)

And for quite a while the idea of finding a patch compatible with a recent version of Vim, and then compiling Vim, seemed too daunting for me to worry about. But not so any more.

Compiling Vim with Breakindent

First you will need to get Eli Carter’s updated version of the breakindent patch from here. I used the version for Vim 7.2.315, but if there’s a newer version, you’re welcome to try it.

Next, you will need the Vim source code. (I assume you have mercurial installed.)

$ hg clone vim

Update the Vim repository to the tag that matches the version of the patch.

$ cd vim
$ hg update v7-2-315

Then apply the patch.

$ patch -p1 < vim-7.2-breakindent.patch

Edit src/Makefile and set whatever options you want. I chose to uncomment the following options:

CONF_ARGS = --enable-gui
CONF_OPT_PYTHON = --enable-pythoninterp
CONF_OPT_FEAT = --with-features=huge

If you want to compile Vim with the GUI, you will need to have one of several GUI packages installed. I compiled Vim with the GTK2 GUI in order to match the Ubuntu Vim I already had. It took me a while to figure out which package I had to install to get this working. In the end, it turned out to be libgtk2.0-dev (if I recall correctly), which should have been obvious except that it doesn’t show up in Syntaptic if you search for “gtk2”.
The rest of the compiling process is pretty much as you’d expect.

$ sudo apt-get install libgtk2.0-dev
$ make
$ sudo make install

(Edit: To compile with the Python interpreter you’ll need to install the python-dev and libssl-dev packages. If you get stuck while trying to include features, src/auto/config.log may have some useful debugging information.)

This will install to /usr/local/bin/vim by default, so you may need to change your vim / gvim aliases to point to this new location. If your distribution has its own default vim settings with things like set backspace=2 and syn on, you may need to set these in your .vimrc file.

Why Isn’t it Part of Vim?

The reason that the breakindent patch hasn’t been submitted to Bram for inclusion in Vim is simple: it still contains bugs. For instance, try selecting text in the second or subsequent row of a wrapped line.  Or try turning on the linebreak option and making a line so long that it wraps several times, then see what happens to your cursor.

Even with these bugs though, I find this patch extremely useful.

This entry was posted in long and tagged , , , , , , , , , . Bookmark the permalink.

Comments are closed.