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.

  • 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 '18 at 9:42
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

  • 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 '18 at 9:16
  • 1
    M-x font-lock-fontify-buffer – wasamasa Mar 25 '18 at 9:36
  • Do I call it upon inserting every character? That seems wasteful. – strNOcat Mar 25 '18 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 '18 at 11:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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