13

I saw a skilled vim ninja do this a while back but I have no idea were to start.

A) Is there a way to set up vims background colour so that consecutive lines with identical content get highlighted.

B) If somebody knows how to do that a nice tweak to this would be if the highlighting happened on consecutive lines but only consider the first word (not the whole line).

A second tweak if the highlighting could be configured to different colours are used based on the number of matching lines (or words depending on A B is active). So of we only have two consecutive lines that match then green, 3-5 consecutive lines then orange, 6+ then red.

10

The following match sets seem to work for (A):

:syn match Low /\v(.+)\n(\1\n)/
:syn match Medium /\v(.+)\n(\1\n){2,4}/
:syn match Critical /\v(.+)\n(\1\n){5,}/
:hi Critical  ctermfg=red
:hi Medium  ctermfg=yellow
:hi Low  ctermfg=green

It seems the order is crucial here. If the Low or Medium matches come after Critical, it gets subsumed by the looser requirements of these, and similarly for Low w.r.t. Medium.

The highlighting doesn't appear immediately after you add, say, a 3rd or 6th dupe line, but once you move around a bit after adding them. I'm not sure what triggers it, exactly.

For B, I imagine you could replace the regex with:

/\v(\S+).*\n(\1.*\n)/

In general, replace all the (.*) with (\S+).* and \1 with \1.*, or whatever constitutes a word for you.

  • I gave this answer the tick because to me its how to do the highlighting that I needed (as expressed by the question). @Matts regular expression nice but does not answer the actual question I asked (changing the highlighting). – Martin York Feb 26 '15 at 21:44
8

As a starting point, here's a search pattern that matches duplicate lines (ignoring changes in leading whitespace):

              \zs                marks start of the pattern. Everything before here will not be highlighted
 ^                               start of the line
  \s*                            leading whitespace
       .\+                       match 1 or more non-newline characters
     \(   \)                     and use parens to capture this in match group 1

            \n                   match the newline character
                 \(        \)\+  1 or more
                      \1         copies of what was in the match group 1
                   \s*  \n       with leading whitespace followed by a newline
/^\s*\(.\+\)\n\zs\(\s*\1\n\)\+   the full regex

:help pattern will provide more info on how to make regexes like this

:help syntax will show you how to take this regular expression and turn it into something that is highlighted for you

Learning to write syntax scripts can be tough, so a good short-term solution is to do this 'on the fly' by making sure 'incsearch' is set so that searches are highlighted and mapping a key to do the above search, i.e. nnoremap <F5> /^\s*\(.\+\)\n\zs\(\s*\1\n\)\+<CR>

  • Is there some automated way of distributing the regex like that? It provides such a clear depiction. – muru Feb 25 '15 at 22:14
  • 1
    I've been doing it by hand. The easiest quick way in vim would be to do something like yy10p on the line with the full regex then select parts you wish to remove and hit r<space>. Maybe I'll add a command for 'replace everything except the selection on this line with spaces' to speed things up a bit. – Matt Boehm Feb 25 '15 at 22:21
  • Wow! That is quite some effort! – muru Feb 25 '15 at 22:21
  • 1
    I made a (really ugly) vim function to make this a bit faster: gist.github.com/mattboehm/da63a48eedf6f14375aa . Select a line, hit ,r then join lines together with <space> in normal/visual mode. – Matt Boehm Feb 26 '15 at 18:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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