user4720912
user4720912

Reputation:

VIM line count in status bar with thousands separator?

Is it possible to display the line count in the VIM status bar with thousands separators, preferably custom thousands separators?

Example:

set statusline=%L

should lead to "1,234,567" instead of "1234567".

Upvotes: 4

Views: 317

Answers (1)

melpomene
melpomene

Reputation: 85827

I've found a way but it looks a bit crazy:

set statusline=%{substitute(line('$')\,'\\d\\zs\\ze\\%(\\d\\d\\d\\)\\+$'\,'\,'\,'g')}

The first round of backslashes is just for set (I have to escape , and \ itself).

What I'm actually setting the option to is this string:

%{substitute(line('$'),'\d\zs\ze\%(\d\d\d\)\+$',',','g')}

As a format string, this line contains one formatting code, which is %{...}. Everything in ... is evaluated as an expression and the result substituted back in.

The expression I'm evaluating is (spaces added (if I had added them to the real code, I would've had to escape them for set again, forcing yet more backslashes)):

substitute(line('$'), '\d\zs\ze\%(\d\d\d\)\+$', ',', 'g')

This is a call to the substitute function. The arguments are the source string, the regex, the replacement string, and a list of flags.

The string we're starting with is line('$'). This call returns the number of lines in the current buffer (or rather the number of the last line in the buffer). This is what %L normally shows.

The search pattern we're looking for is \d(\d\d\d)+$ (special vim craziness removed), i.e. a digit followed by 1 or more groups of 3 digits, followed by the end of the string. Grouping is spelled \%( \) in vim, and "1 or more" is \+, which gives us \d\%(\d\d\d\)\+$. The last bit of magic is \zs\ze. \zs sets the start of the matched string; \ze sets the end. This works as if everything before \zs were a look-behind pattern and everything after \ze were a look-ahead pattern.

What this amounts to is: We're looking for every position in the source string that is preceded by a digit and followed by exactly N digits (where N is a multiple of 3). This works like starting at the right and going left, skipping 3 digits each time. These are the positions where we need to insert a comma.

That's what the replacement string is: ',' (a comma). Because we're matching a string of length 0, we're effectively inserting into the source string (by replacing '' with ',').

Finally, the g flag says to do this with all matches, not just the first one.

TL;DR:

  • line('$') gives us the number of lines
  • substitute(..., '\d\zs\ze\%(\d\d\d\)\+$', ',', 'g') adds commas where we want them
  • %{ } lets us embed arbitrary expressions into statusline

Upvotes: 4

Related Questions