Conditional scroll binding in Vim

Let’s start off this post with two apologies:

  1. I’m sorry that I haven’t blogged in quite a while. I do have quite a backlog of ideas, and I hope I’ll have the time and energy to write them soon.
  2. I’m sorry that the images in the last post are all in full size and not scaled down, making the page extremely slow to load. The server was missing the GD library used by WordPress for image scaling. This has now been fixed, but unfortunately the images already uploaded remain full size. I guess I have to start writing more to push the offending post off the front page (see apology number 1).

So lets go over to what this post is actually about.

I was recently tasked with translating parts of a user manual (Docbook XML) from English to Swedish. Not the most exciting task, but I don’t mind doing it and the pay was OK. Anyone who knows me know that my editor of choice is the fantastic Vim text editor.

Now, while working on the translation I realized that in addition to having my working copy open in a window, I’d also like to have the unchanged original at hand. This is because, during translation, you delete a chunk of text to be translated, keep it in your short term memory, and then translate it from your head. This is where things can go wrong; human memory is known to be volatile and can not be trusted, and when it fails, having the original there right next to your working copy is very handy.

So what I first did was to split Vim vertically and open the original in a window to the right of my working copy using :vnew orig/foo.xml. This worked somewhat fine, but I found myself having to constantly switch over to the buffer with the original to scroll it down as the translation progressed, and it costed me quite some time. With a set amount of money for this job, losing time was the last thing I wanted. If only there was a way to make my right window, the one showing the unchanged original, scroll in synchronicity with the left window showing my working copy. And of course there is, this is Vim after all! Just type :scrollbind and scrolling of the two windows will be bound to each other.

This left me happy for a while as I continued the translation. But as I got further on and more and more of my working copy was translated, the lines in the two windows got skewed, so I found myself having to switch off scroll binding, switch over to the right window and manually scroll it in order to compensate for this skew, then switch scroll binding back on. I needed to find a way to save time on this compensation monkey work, and the solution was simple; have Vim automatically turn off the scrollbinding as the right window is entered, and automatically turn it back on as it is left again.

The magic incantation (to be typed in the left window) goes like this:

:set scb | :au WinEnter right_win set noscb | au WinLeave right_win set scb

This is a pretty self explanatory set of commands, but here’s how it works:

  1. Turn on scroll binding (scb is shorthand for scrollbind).
  2. When the window called right_win is entered, turn it back off.
  3. When the window called right_win is left again, turn it back on.

This allows me to go on translating in the left window, and when the skew between the two windows gets too bad, all I need to do is switch over to the right window and do some compensation with Up/Down and then switch back, no messing around with turning scroll binding off and on.

Now some people would say; why don’t you just duplicate the row to be translated in your working copy and then delete the original once you’ve translated the copy? It is true that some people might prefer to work like that, I don’t. The reason is that, which is kind of the whole point with this post, I’m very forgetful and I believe this to be a common problem. With that approach I’m sure to be leaving a trail of forgotten original lines in the working copy. In fact, the translation I was doing was a continuation of someone else’s work, and at several places I have found such “leftovers” from the previous translator.

Let’s end this with a hint for people who use overlapping buffers in the same window, but still want to use this trick; you should be looking at BufEnter / BufLeave instead.

A pretty long post for such a little thing, but it felt kind of good writing something here again.

Bye ’til next time!