Context sensitive font locking in emacs

Basically, I am trying to syntax to highlight the following coffeescript code snippet the way I want it. An explanation of the syntax of coffeescript functions can be found here .

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

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

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

Here is the first x, which is the parameter. Parameters can have default arguments:

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

The default arguments can be the variables themselves:

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

The msg and color values ​​above should be highlighted, but not defColor . An even more complicated case are functions with default arguments, which themselves are functions. I think emacs fonts are hard to select for correcting fonts, but I turn it on anyway:

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

This seems rather difficult to achieve in emacs because you want the highlight to be context sensitive. I read the font locking documentation but couldn't figure it out.

I would appreciate it if someone could show me what to set font-lock-defaults so that the syntax displays what I want.

Update . Display more syntactic coffeescript examples.

+4
source share
2 answers

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

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

So, we need to write a function that will look for the next function argument in the buffer.

Something like that:

 (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 setting used 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.

It will probably use some other color than pink, but it is easy to change.

+8
source

It is rather a kind of hack, it is far from optimal (since I am not familiar with coffeescript at all), but perhaps with a little tweaking, you can do it.

All ingredients are there.

Running commands / functions is based on the assumption that you are using coffee-mode . If you do not, this is not a big problem, you just have to intercept these things in a different way.

Put the following line in .emacs :

(eval-after-load 'coffee '(load "/PATH/custom-coffee-font-lock.el"))

You can simply save the text below as a file and it will:

(1) Font lock when coffee-mode starts

(2) Font lock string when entering " > " as part of "->"

(3) Allows you to block the font of the buffer by running Mx coffee-init-font-lock

 ;;;; custom-coffee-font-lock ;; Firstly, create a new font for this. (make-face 'font-lock-coffeescript-face) (set-face-foreground 'font-lock-coffeescript-face "pink") ;; Next, one function that should be ran after a file is identified as ;; a coffeescript file. It will do the font-locking you want on ;; the whole buffer. It is also possible to run it manually. (defun coffee-init-font-lock () (interactive) (save-excursion (goto-char 1) (while (search-forward-regexp "=.+->" nil t) (search-backward-regexp "(") (forward-char 1) (add-text-properties (point) (- (search-forward-regexp "," nil nil) 1) '(font-lock-face font-lock-coffeescript-face)) (add-text-properties (point) (- (search-forward-regexp "," nil nil) 1) '(font-lock-face font-lock-coffeescript-face)) (add-text-properties (point) (- (search-forward-regexp ")" nil nil) 1) '(font-lock-face font-lock-coffeescript-face)) (move-end-of-line 1))) ) ;; This actually runs that function. (coffee-init-font-lock) ;; This advice will be ran everytime you write something. It will check ;; whether "->" is before it, so when you type the final ">", it will ;; do the font locking for the current line (it also checks for your mode). (defadvice self-insert-command (after coffee-font-lock activate) (when (and (looking-back "->") (eq major-mode 'coffee-mode)) (save-excursion (search-backward-regexp "(") (forward-char 1) (add-text-properties (point) (- (search-forward-regexp "," nil nil) 1) '(font-lock-face font-lock-coffeescript-face)) (add-text-properties (point) (- (search-forward-regexp "," nil nil) 1) '(font-lock-face font-lock-coffeescript-face)) (add-text-properties (point) (- (search-forward-regexp ")" nil nil) 1) '(font-lock-face font-lock-coffeescript-face)))) ) (provide 'custom-coffee-font-lock) ;;; custom-coffee-font-lock.el 

If you have any inquiries, let me know. As I said, I do not use CoffeeScript, so this can lead to huge errors. At the very least, this should help with some basic ideas.

Result:

enter image description here

+2
source

All Articles