Search code examples
emacscommentselispfont-lockmajor-mode

different font-lock scheme for "special" comments in emacs derived-mode


I am defining an Emacs major mode by deriving from prog-mode. Font-locking works except for one thing:

I'd like to highlight a special comment type that contains special linker directives, using a font different from the one used for regular comments. Regular comments start with ";" whereas the linker directives have the form ";<...directive...>". And of course, text in strings should not be misidentified as comments.

What I have so far is:

;; define syntax highlighting
(setq p18-font-lock-defaults
      `(
        ;; strings
        ("\"\\.\\*\\?" . font-lock-string-face)
        ;; linker directives
        ("^ *;<.+>.*$" . font-lock-preprocessor-face)
        ;; mnemonics
        ( , p18-mnemonics-regexp . font-lock-keyword-face)
        )
  )

;; define derived mode
(define-derived-mode p18-mode prog-mode "P18"
  "...mode description..."

  ;; define syntax highlighting
  (set (make-local-variable 'font-lock-defaults)
      '(p18-font-lock-defaults nil t))

  ;; comments
  (setq comment-start ";")
  (setq comment-end "")

  ;; === works when comments start with "; "
  ;; (modify-syntax-entry ?; ". 1" p18-mode-syntax-table) 
  ;; (modify-syntax-entry 32 ". 2" p18-mode-syntax-table) 
  ;; (modify-syntax-entry ?\n ">" p18-mode-syntax-table)

  ;; ugly incomplete hack works for comments with ASCII code of
  ;; second char ?\;
  ;; (modify-syntax-entry ?; ". 1" p18-mode-syntax-table) 
  ;; (modify-syntax-entry '(?= . 127) ". 2" p18-mode-syntax-table) 
  ;; (modify-syntax-entry ?\n ">" p18-mode-syntax-table)

  )

The problem is that with the syntax-table entry this mechanisms classifies everything that starts with ; as comment. The linker directive regexp therefore is not effective anymore.

How can I achieve the desired behaviour? It seems I'd need a pattern that allows checks the chars that follow. But then using the syntax table for comment detection seems nice because it handles strings correctly.

More generally, I am interested in a document that explains the "architecture" of emacs/elisp (e.g. modes and what sequence of operations work for font-locking. Same for buffer interaction). I have the elisp reference manual which is great but I miss a conceptual intro to these topics. I have read the emacs elisp intro but did not like it because I found it too "tutorial-style", very lengthy and repetitive, and missing systematic coverage. For example, there was not a sentence about backquoting. It also seemed to address people with zero programming experience - but would one start with elisp then?


Solution

  • You want to use font-lock-syntactic-face-function to distinguish which kind of comment gets which face. E.g. something like

    (defun my-font-lock-syntactic-face-function (ppss)
      (if (and (nth 8 ppss)
               (save-excursion
                 (goto-char (nth 8 ppss))
                 (looking-at ";<.+>")))
          'font-lock-preprocessor-face
        (funcall (default-value 'font-lock-syntactic-face-function) ppss)))
    ...
    (define-derived-mode ...
      ...
      (set (make-local-variable 'font-lock-syntactic-face-function)
           #'my-font-lock-syntactic-face-function)
      ...