The other day my boss found me locked in the server room, naked and bathing myself with dish washing liquid and toilet water. When he asked what in the flying fuck I was playing at, I told him my soul was filthy and corrupt from all the long lines I'd been committing. In reply he told me I'd better sack up and write some vimscript hacks to keep my long lines under control. So that's what I did. Later that afternoon I was so happy I proposed to my boss and we lived happily ever after.
Read this raving if long lines bug you like a colony of fire ants assaulting your prostate.
Note: this raving assumes a fair amount of knowledge about statuslines in vim. If you aren't pro at statuslines then you should read
this raving first.
Reporting long lines on the statusline
I've found it quite useful to have flags on my statusline that appear when a buffer is in an undesirable state; e.g. if the file format or encoding is wrong, or there are syntax errors, or mixed indenting etc. Ive recently coded a warning for long lines into my statusline. Check out this screenshot:
Notice the
[#141,m82,$162]
on the statusline. This is telling us that the buffer has 141 long lines, where the median length of these lines is 82 chars and the longest is 162 chars. This notice only appears when there is at least one line that is longer than
&textwidth
(typically 80).
That may seem like an excessive amount of information, but when I first coded a statusline warning, I only included the length of the longest line. This turned out to be insufficient since its common for a file to have one or two crazy long lines that are acceptable or troublesome to avoid. I could have only shown the
number of long lines, but then I'd be left wondering
how long they were; hence the median and longest line stats. Besides, more stats means more code behind my statusline, which makes it more likely the mother fucker will become sentient and
hunt down Jamis Buck.
Here's the code from my vimrc:
1 "....
2 set statusline+=%{StatuslineLongLineWarning()}
3 "....
4
5 "recalculate the long line warning when idle and after saving
6 autocmd cursorhold,bufwritepost * unlet! b:statusline_long_line_warning
7
8 "return a warning for "long lines" where "long" is either &textwidth or 80 (if
9 "no &textwidth is set)
10 "
11 "return '' if no long lines
12 "return '[#x,my,$z] if long lines are found, were x is the number of long
13 "lines, y is the median length of the long lines and z is the length of the
14 "longest line
15 function! StatuslineLongLineWarning()
16 if !exists("b:statusline_long_line_warning")
17 let long_line_lens = s:LongLines()
18
19 if len(long_line_lens) > 0
20 let b:statusline_long_line_warning = "[" .
21 \ '#' . len(long_line_lens) . "," .
22 \ 'm' . s:Median(long_line_lens) . "," .
23 \ '$' . max(long_line_lens) . "]"
24 else
25 let b:statusline_long_line_warning = ""
26 endif
27 endif
28 return b:statusline_long_line_warning
29 endfunction
30
31 "return a list containing the lengths of the long lines in this buffer
32 function! s:LongLines()
33 let threshold = (&tw ? &tw : 80)
34 let spaces = repeat(" ", &ts)
35
36 let long_line_lens = []
37
38 let i = 1
39 while i <= line("$")
40 let len = strlen(substitute(getline(i), '\t', spaces, 'g'))
41 if len > threshold
42 call add(long_line_lens, len)
43 endif
44 let i += 1
45 endwhile
46
47 return long_line_lens
48 endfunction
49
50 "find the median of the given array of numbers
51 function! s:Median(nums)
52 let nums = sort(a:nums)
53 let l = len(nums)
54
55 if l % 2 == 1
56 let i = (l-1) / 2
57 return nums[i]
58 else
59 return (nums[l/2] + nums[(l/2)-1]) / 2
60 endif
61 endfunction
Crikey dick that's a lot of code! Lets run through it.
The
StatuslineLongLineWarning()
function constructs and caches the flag that will appear on the statusline. The flag will be an empty string if there aren't any long lines.
The hard work is actually delegated off to the
LongLines()
and
Median()
functions.
LongLines()
examines every line in the buffer and returns an array containing the lengths of the long lines, where "long" is determined by the users
&textwidth
setting (defaulting to 80 if
&textwidth
is set to 0). Note that
LongLines()
converts tabs into spaces according to the users
&tabstop
setting.
Median()
calculates the median of a given array of numbers.
Line 2 puts the flag onto the statusline and should appear with the rest of your statusline setup code.
Line 6 clears the cached flag every time the user is idle or saves the file, thus causing the flag to be recalculated.
Highlighting the offending parts of long lines
1 "define :HighlightLongLines command to highlight the offending parts of
2 "lines that are longer than the specified length (defaulting to 80)
3 command! -nargs=? HighlightLongLines call s:HighlightLongLines('<args>')
4 function! s:HighlightLongLines(width)
5 let targetWidth = a:width != '' ? a:width : 79
6 if targetWidth > 0
7 exec 'match Todo /\%>' . (targetWidth) . 'v/'
8 else
9 echomsg "Usage: HighlightLongLines [natural number]"
10 endif
11 endfunction
I stole line 7 above from
this vim tip and wrapped it up in a the
HighlightLongLines
command above. When invoked, the command highlights the "long" parts of long lines. Ive found this command pretty handy when embarking on anti long line crusades.
I'd highly recommend reading that vim tip for more code to highlight long lines. Theres some pretty dynamite stuff there.
Conclusion
Long lines suck, here's what Abe had to say about the matter:
Peppering your code with long lines is highly recommended; right up there with "strolling into church with an entourage of scantly clad, chronically obese prostitutes" and "licking the testicles of senile old men who are not fully in control of their bladders".
Abraham Lincoln, 1862
Inspirational.
Use the relatively passive vim script hacks above to make vim bitch at you and steer you away from using long lines. If you want a more aggressive solution, then check out
the aforementioned vim tip.