Defining second font-lock-comment-face in Emacs

1.4k views Asked by At

Is it possible to define a second comment face and comment-start indicator in Emacs such that the second comment highlight appears even if called from within the first comment-face?

I currently have a custom Emacs mode with the following:

.emacs file:: (set-face-attribute 'font-lock-comment-face nil :foreground "gray70")

custom_mode.el:: (set (make-local-variable 'comment-start) "//")

Is it possible to add:

.emacs file:: (set-face-attribute 'font-lock-comment-face nil :foreground "gray70") (set-face-attribute 'font-lock-comment2-face nil :foreground "forestgreen")

custom_mode.el:: (set (make-local-variable 'comment-start) "//") (set (make-local-variable 'comment2-start) "||")

such that the line

//Test comment: ||Second test comment

is rendered in two colors?

Would I need to define 'comment2' elsewhere?

Thanks!

1

There are 1 answers

4
Jordon Biondo On

Coloring comments is generally handled by font-lock referring to the mode's syntax table, this only supports one face for comments.

You can however, specify a regexp for font-lock to force highlight in any color you want, this way we can specify a regexp that matches "//" followed by text, followed by "||" followed by more text, and have font-lock highlight the "||" and the following text only.

Here is a basic implementation of this in a major mode.

;; your custom face to color secondary comments blue
(defface my-second-comment-face '((t (:foreground "blue"))) "its a face")

(define-derived-mode testy-mode fundamental-mode
  "test"
  (modify-syntax-entry ?/ "<1")
  (modify-syntax-entry ?/ "<2")
  (modify-syntax-entry 10 ">")
  (font-lock-add-keywords
   'testy-mode
   ;; this highlights || followed by anything to the end of the line as long as there is
   ;; a // before it on the same line.
   ;; the 2 means only highlight the second regexp group, and the t means highlight it
   ;; even if it has been highlighted already, which is should have been.
   '(("\\(//.*\\)\\(||.*$\\)" 2 'my-second-comment-face t))))

You should note that this is a basic solution that doesn't handle all cases. A normal case like

foobar // comment || more comments

will be handled correctly, but something like

foobar "string//string" || text 

will not work correctly, the || text will be highlighted even though // occurs in a string

enter image description here

If you want fontification of these secondary comments to be "smarter" you will need to look into more advanced techniques for fontification. You use a hook in jit-lock-functions to do this. In your jit lock function, you would need to scan for the ||text pattern and highlight it based on whether or not it is already in a comment which you can find out with syntax-ppss assuming your syntax table is set up correctly.