Search code examples
vimsyntaxhighlight

vim syntax highlighting comments that can be one line or block


this is my first post, so be gentle please!

So, I have input files (.in) for an in-house program. The syntax is as follows (for example):

$set (code) $end

$run
(code)
$end

$cmt this is a comment

$cmt this is

a block comment

$end

My situation is I want all the $set and $run to be red with their corresponding $end to be red also. Everything in between has to be nominal color (grey).

I simply use the

syntax match inCMD "\$SET"

for that and it works fine.

Where I have a problem is that I want the "$CMT" to be yellow so i use

syntax match inCMT "/^\$CMT.*$"

The particularity is that $CMT does not have to have a corresponding $END. So, if there is no $END (or that it figures at the end of the same line as $CMT, i want the line to be yellow, and the line after to be outside the syntax region. However, if i want to do a block comment and that there is a corresponding $END to this $CMT, everything inside has to be yellow.

I came up with

syntax commands

but i have a problem on line 14-17 of the 2nd picture: syntax example.

If a $set is directly under the $cmt, the text inside the $set will be yellow instead of simply white. The other problem is that the $end corresponding to $set are white and not red.

How can i solve this?

Thanks a lot!

edit: Syntax file:

syntax case ignore 
syntax match inCMT /^\$CMT.*$/
syntax match inCMD "\$SET"
syntax match inCMD "\$RUN"

sy region inCMT matchgroup=inCMT start= /^\$CMT.*$/ end=/\(^\$end\)\|\(^\s*$\)/ contains=inCMD
:sy region inCMD matchgroup=inCMD start= /\v($(SET))/ end=/\(^\$end\)\|\(^\s*$\)/ contained

:hi inCMT ctermfg=yellow 
:hi inCMD ctermfg=red 

Input file:

 $cmt eoipwejf
iowejwed
$end

$set
weoifjwef

$end
$set 
$end

$cmt
$set ewdiw
efef
$end
$set 
effef 
$end

$cmt 
efoiwef
$end

$cmt 
wd
$END

wd

$set
deiuwf = ewoiw
ewofoi we
$end

$cmt fefef
$cmt
efwef
$end

$set 
$set
$set

$cmt ewfoief
wdwwd
$end

$set efopwef


fwfewf
eiojf
$end 

$set 
ere

wd

$cmt
$end

effe

$cmt
wdeoiqwd
$end
edfeef

$run 
goto  
$cmt
wdqwd
$end

2nd edit: What i want as final result (colors in brackets) (y) yellow (r) red (n) nominal

Block comment:  
$cmt foo (y)
bar (y)
$end (y)

$cmt (y)
   foo (y)
   bar (y)
$end (y)

$cmt (y)
foo (y)

bar(y)
$end (y)

Line comment: 
$cmt (y)
$set (r) foo = bar (n) $end (r)

$cmt foo bar (y)
$set (r) 
foo = bar (n) 
$end (r)


I think these are all the cases.


Solution

  • This worked for me:

    syntax clear
    syntax case ignore
    syntax match inCMD "\$set"
    syntax match inCMD "\$cmd"
    syntax match inCMD "\$end"
    syntax region inCMT start=/^\$cmt/ end=/\$end\|\$\@=/
    
    hi inCMT ctermfg=yellow
    hi inCMD ctermfg=red
    

    It seems to match your update indicating which color each line or word should take. Normally only the keywords ($cmd, $run and $end) are red, but for a comment the whole block is yellow, including the final $end.

    The trick to match a comment with or without an $end was to do a zero-width match on a single $ (that's the \$\@= part of the regex.) Since regular expressions return the longest match first, whenever $end is found it will be matched (and highlighted yellow), but if a $ is otherwise matched, it ends the region but it doesn't become part of it, so it won't be highlighted yellow (and it turns out it's still available to be highlighted red if it's one of the other matching commands, which was important in this case.)

    I noticed you had an $end further down one line, so I didn't anchor the commands anywhere. My first instinct was to use ^ to have them at the start of the line and also use a $ to only allow $end to be by itself on a line. But I removed all that and it turns out it still works as expected. Feel free to add those back if you think they make sense.