Search code examples
regexemacselispsyntax-highlightingfont-lock

Context-sensitive discontinuous font-locking in Emacs


Im trying to setup font-locking for a major mode. Here is some example code:

USING: foo bar bar ;

IN: fuelcolors

TUPLE: font < super-class
    name
    size
    bold?
    italic?
    { foreground initial: COLOR: black }
    { background initial: COLOR: white } ;

TUPLE: rgb red green blue ;

: foobar ( seq -- seq )
  hello there { 1 2 3 } ;

The following symbols should be highlighted with some face (doesn't matter which, my problem is the matching part): name, size, bold?, italic?, foreground, background, red, green, blue. They represent names of slots in tuples.

I know a regexp wont do it because the matched region isn't continuous. italic? and foreground should be matched, but not the { character in between those symbols. So instead I thought I could author a font-lock matcher function, similar to the one Dmitri offered here: Context-sensitive font-locking in emacs for a very similar problem.

But afaict, his solution takes advantage of the fact that the "sequence" of items to highlight is inside paranthesises which is not the case here.

Font-lock has trouble with situations like these (Unknown number of matches in regex and font-lock), but I'm still hoping for some "good enough" solution even it if requires hacking font-lock internals.


Solution

  • Here is the solution I ended up with:

    (,"\\(TUPLE\\):[ \n]+\\(\\(?:\\sw\\|\\s_\\)+\\)\\(?:[ \n]+<[ \n]+\\(\\(?:\\sw\\|\\s_\\)+\\)\\)?"
         (1 'factor-font-lock-parsing-word)
         (2 'factor-font-lock-type-name)
         (3 'factor-font-lock-type-name nil t)
         ("\\(\\(?:\\sw\\|\\s_\\)+\\)\\|\\(?:{[ \n]+\\(\\(?:\\sw\\|\\s_\\)+\\)[^}]+\\)"
          ((lambda (&rest foo)
             (save-excursion
               (re-search-forward " ;" nil t)
               (1- (point)))))
          nil
          (1 'factor-font-lock-symbol nil t)
          (2 'factor-font-lock-symbol nil t)))