3

I often view logs in vim, and the log contains large numbers eg 3244522321. It's very difficult to tell if this is 324M, 32M, or 3.2M.

Is there a way to set up something (syntax highlight?) that will color groups of 3 digits differently?

For example:

3244522321
       ^^^ red
    ^^^    blue
 ^^^       green
^          orange

It should act on anything that matches the pattern e.g. /[1-9][0-9]+/

4
  • Probably? Naïvely, I would expect to have to explicitly spell out the maximum number of groups and what colors are to be used (IIRC even rainbow-parentheses have either a max-depth or a max-colors)
    – D. Ben Knoble
    Commented Mar 11, 2021 at 19:30
  • Sure... up to, say, 15 digits would be sufficient (5 groups of 3 digits).
    – obk
    Commented Mar 11, 2021 at 20:31
  • What a good idea! Bonus points for colouring groups of four hexadecimal digits.
    – Rich
    Commented Mar 11, 2021 at 21:56
  • An alternative scheme is shown here (second option, "3rd digit highlight"): github.com/bioSyntax/bioSyntax/issues/12 and the syntax file is here if it appeals to you: github.com/bioSyntax/bioSyntax-vim/blob/…
    – B Layer
    Commented Mar 12, 2021 at 13:35

1 Answer 1

4

Here's one way to do it:

syntax match NumberX /\v<[1-9]\d{,2}\ze(\d{3})*>/ nextgroup=Number1
syntax match Number1 /\v\d{3}/ nextgroup=Number2 contained
syntax match Number2 /\v\d{3}/ nextgroup=Number3 contained
syntax match Number3 /\v\d{3}/ nextgroup=Number1 contained

hi NumberX guifg=red ctermfg=red
hi Number1 guifg=green ctermfg=green
hi Number2 guifg=blue ctermfg=blue
hi Number3 guifg=red ctermfg=red

NumberX matches any number (that starts with a 1-9), but only highlights the first 1-3 digits, leaving a multiple of three digits remaining unhighlighted. The numbered groups then each highlight 3 digits, before looking for the next group in the series. I've set it up with three cycling colours, but you can easily use just two alternating, or add more in the cycle.

The regular expression broken down:

\v<[1-9]\d{,2}\ze(\d{3})*>
\v                         # Using very magic (so we don't need as many \ escapes)
  <                        # Match the start of a word, followed by
   [1-9]                   # any digit from one to nine, followed by
          {,2}             # up to two
        \d                 # digits
              \ze          # End the match (so don't highlight what follows)
                        *  # Then match as many as possible
                 (     )   # groups
                    {3}    # of three
                  \d       # digits
                         > # leading up to the end of the word

In the :syntax commands, nextgroup tells Vim to test for the stated group immediately after the current match, and contained means that the current group cannot be found at the top level: only when hinted via the nextgroup keywords.

A screenshot of the code in action, displaying large numbers with groups of three digits highlighted in different colours.

The possible downside of this solution is that it always highlights the start of the number in the same colour, and you'd probably want to always use the same colour for the end of the number (so, e.g. the thousands column is always the same colour).

Because Vim's syntax highlighting works by searching forwards through the file, a solution that fixes this issue needs to be a bit more complicated than the solution above. Here's one way to do it:

syntax match NumberA /\v<[1-9]\d{,2}\ze(\d{9})*>/ nextgroup=Number3
syntax match NumberB /\v<[1-9]\d{,2}\ze\d{3}(\d{9})*>/ nextgroup=Number2
syntax match NumberC /\v<[1-9]\d{,2}\ze\d{6}(\d{9})*>/ nextgroup=Number1
syntax match Number1 /\v\d{3}/ nextgroup=Number2 contained
syntax match Number2 /\v\d{3}/ nextgroup=Number3 contained
syntax match Number3 /\v\d{3}/ nextgroup=Number1 contained
hi NumberA guifg=blue ctermfg=blue
hi NumberB guifg=green ctermfg=green
hi NumberC guifg=red ctermfg=red
hi Number1 guifg=green ctermfg=green
hi Number2 guifg=blue ctermfg=blue
hi Number3 guifg=red ctermfg=red

A screenshot of the second solution, displaying numbers with consistent colouring in each significant digit.

6
  • Sweet! Thanks for figuring this out; had something like that in my head, but no time to play with it
    – D. Ben Knoble
    Commented Mar 13, 2021 at 3:56
  • All righty, then. :D
    – B Layer
    Commented Mar 18, 2021 at 0:48
  • @BLayer I'm sorry, I didn't mean to ignore you! Your awk script was very cool. I was holding off on replying until I could respond properly. I was going to say that I currently do it all by hand, but I might try your script in the future :(. It also took me a while to track down these answers by anonymous users. This one automates ASCII art. And this one has nice unicode diagrams. I still prefer the style I used above, though, because you don't have to read the explanation upwards.
    – Rich
    Commented Mar 18, 2021 at 9:28
  • No worries @Rich ... I wasn't insulted or anything, just antsy about having two big off-topic comments that (I thought) weren't useful to anyone. Thanks for the links, I will def. check 'em out...I want to get in the habit of using something like those or your format. If you didn't grab the awk script before I deleted it and want a copy let me know and I'll put it in a proper place like pastebin or something. And if you do end up playing with it let me know if you have any issues. Cheers!
    – B Layer
    Commented Mar 18, 2021 at 9:40
  • 1
    Here it is in Github Gist form: gist.github.com/b-layer/7490fac70dce19355d80056922945d3d . What would the meta topic be? Tricks and scripts used by regular Vi&Vim SE contributors? That'd be kind of cool. :)
    – B Layer
    Commented Mar 19, 2021 at 10:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.