Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Context-sensitive font-locking in emacs

Basically, I'm trying to syntax highlight the following piece of coffeescript code the way I want it. Explanation of the syntax of coffeescript functions can be found here.

nameHere = (tstamp, moo, boo) ->
    ...

The names tstamp, moo and boo should be colored pink (and nothing else, not the commas and not the brackets) because they are parameters to a lambda function.

highOrderFun ((x) -> x * x) someList

Here it is the first x that is the parameter. Parameters can have default arguments:

class Foo
    meth: (msg = "Hello", bar = "foo") ->
        ....

Default arguments can be variables themselves:

defColor = "red"
print = (msg, color = defColor) ->
    ...

So msg and color above should be highlighted, but not defColor. An even trickier case is functions with default arguments that themselves are functions. I think that is to hard for emacs' font-lock to highlight correctly, but I'm including it anyway:

funTakingFuns = (f1 = ((a, b) -> a*b), f2 = ((c, d) -> c/d)) ->
    ...

This appears to be pretty complicated to achieve in emacs because you want the highlighting to be context sensitive. I've read up on the documentation on font-lock but haven't been able to figure it out.

I'd be grateful if someone could show me what to set font-lock-defaults to make it syntax highlight the way I want it.

Update Showing more coffeescript syntax examples.

like image 523
Björn Lindqvist Avatar asked Dec 26 '22 10:12

Björn Lindqvist


1 Answers

font-lock-keywords allows function values in the MATCHER field:

where MATCHER can be either the regexp to search for, or the function name to call to make the search (called with one argument, the limit of the search; it should return non-nil, move point, and set match-data appropriately if it succeeds; like re-search-forward would).

So we need to write a function that would search for the next function argument in the buffer.

Something like this:

    (defun coffee-match-next-argument (limit)
      (let ((start (point)))
        ;; Look for the arrow.
        (when (re-search-forward ") *->" limit t)
          ;; Save the position of the closing paren.
          (let ((stop (point)))
            (goto-char (match-beginning 0))
            ;; Go to the opening paren.
            (goto-char (nth 1 (syntax-ppss)))
            ;; If we're before our initial position, go forward.
            ;; We don't want to find the same symbols again.
            (when (> start (point))
              (goto-char start))
            ;; Look for the next symbol until the arrow.
            (or (re-search-forward "\\((\\|,\\) *\\(\\(\\sw\\|_\\)+\\)" stop 'mv)
                (coffee-match-next-argument limit))))))

And the setup, to use with existing coffee-mode:

(font-lock-add-keywords
 'coffee-mode
 '((coffee-match-next-argument 2 font-lock-variable-name-face)))

You can also use this in font-lock-defaults, of course.

This will likely use some other color than pink, but that's easy to change.

like image 141
Dmitry Avatar answered Jan 04 '23 05:01

Dmitry