Search code examples
vimguitar

VIM custom syntax school of rock


I try to compact some chord files and then need to highlight some stuff so it is more visual. This syntax is where chord is followed by a comma then a number showing how many beats, and all surrounded in curly brackets. Here is the example from a classic rock song you might have heard:

{Dm,4}Don't cry, don't {C/D,4}raise your eye
It's {Bb/D,2}on-ly {Am,2} teen-age {Dm,4hold}waste-land

I simply want to make the chord names one color, and the time notation another color... In a nutshell that's everything between { and next , as one color then up to the next } as a second color. Maybe the brackets should be another color too. I suck at regular expressions but this forum can point me in right direction to eventually master them I hope.


Solution

  • Here is a very simple version that will just highlight the whole {...} blocks. Put the following in ${HOME}/.vim/syntax/rock.vim:

    if exists("b:current_syntax")
        finish
    endif
    
    syntax match rockNotation      "{[^}]*}"
    
    highlight link rockNotation    String
    

    And the following in ${HOME}/.vim/ftdetect/rock.vim:

    autocmd BufRead,BufNewFile *.rock set filetype=rock
    

    Now whenever you open a .rock file, the chords should be highlighted. (If detection doesn't work, try to set :set filetype=rock manually, see if it changes something.) Note that if you edited these files from Vim, you may need to restart it for the effects to apply.

    Here is a longer version, where chords and time indications are highlighted in different colors:

    if exists("b:current_syntax")
        finish
    endif
    
    syntax clear
    syntax case match
    
    setlocal iskeyword+=#                                                                         
    setlocal iskeyword+=-
    setlocal iskeyword+=+
    
    syntax match rockChord /\<[A-G]\(b\|#\)\=\(m\|-\|dim\|+\|aug\|7\|m7\|Maj7\|m7b5\)\=\(\/[A-G]\(b\|#\)\=\)\=\>/ contained
    syntax match rockDuration /[1-9][0-9]*\(hold\|mute\)\=/ contained
    
    syntax region rockAnnotRegion start=/{/ end=/}/ contains=rockChord,rockDuration
    
    highlight link rockChord          Type
    highlight link rockDuration       Constant
    highlight link rockAnnotRegion    Delimiter
    

    As you can see, my regexp for chords got a little wild. It supports things like A#m7b5/Db, which of course makes little sense (and sounds horrible), but you get the idea.