0

In trying to learn Emacs Lisp on Emacs 25.3.1, I decided to implement a minimal version of fic-mode. Following is the code:

(defun todo/pos-in-doc-or-comment-region-p (pos)
  (memq (get-char-property pos 'face)
    '(font-lock-doc-face font-lock-comment-face)))

(defun todo/search-for-keyword (limit)
  (let ((original-match-data nil))
    (save-match-data
      (while (and (null original-match-data)
          (re-search-forward "TODO([^)]+?):" limit t))
    (if (and (todo/pos-in-doc-or-comment-region-p (match-beginning 0))
         (todo/pos-in-doc-or-comment-region-p (match-end 0)))
        (setq original-match-data (match-data)))))
    (when original-match-data
      (set-match-data original-match-data)
      (goto-char (match-end 0))
      t)))

(defvar todo/keywords
  '((todo/search-for-keyword . font-lock-warning-face)))

(font-lock-add-keywords nil todo/keywords 'append)

When I run the function todo/search-for-keyword in a Elisp buffer containing the comment

;; TODO(me): Hey

the function does the right thing (finds the comment and puts cursor after the colon). However, when I put the whole code in my .emacs, the TODO(me): does not get colored.

The following even simpler version does work but not in comments (which is the whole point of this exercise):

(defvar todo/keywords
  '(("\\(TODO(\\)\\([^)]+?\\)\\():\\)" .
                 ((1 font-lock-warning-face)
                  (2 font-lock-variable-name-face)
                  (3 font-lock-warning-face)))))
(font-lock-add-keywords nil todo/keywords 'append)

It seems like Emacs already decides to render the text as a comment before my keyword even comes into picture. How can I override Emacs so that parts of comments get highlighted in different way according to my rules?

PS: Here is the documentation for Search-based fontification.

1
  • 2
    Using font-lock-add-keywords without a mode as argument is a bad idea because it will only work for whatever is the currently active mode. It's better to put your code into a function, then add it to the respective mode hooks you're interested in.
    – wasamasa
    Mar 25, 2018 at 9:42

1 Answer 1

1

You're right, comments are highlighted in a first pass which is done by interpreting syntax tables. Font-lock does not override already fontified text by default, to do that you have to add another list item in your font-lock expression:

MATCH-HIGHLIGHT should be of the form:

(SUBEXP FACENAME [OVERRIDE [LAXMATCH]])

The optional OVERRIDE argument is what you're after.

That aside, here's a minimal variation of what fic-mode does: https://github.com/tarsius/hl-todo

4
  • Thank you, I am not sure how I missed that. However, there is another minor problem. When I write TODO(name):, it doesn't get colored until I press return. I guess Emacs caches the results of highlighting. Is there any way I can force Emacs to recalculate highlighting?
    – strNOcat
    Mar 25, 2018 at 9:16
  • 1
    M-x font-lock-fontify-buffer
    – wasamasa
    Mar 25, 2018 at 9:36
  • Do I call it upon inserting every character? That seems wasteful.
    – strNOcat
    Mar 25, 2018 at 9:43
  • 1
    No, you call it interactively to check whether it's indeed an intermittent failure or not. It's not an actual solution to such problems.
    – wasamasa
    Mar 25, 2018 at 11:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.