1

Recently, using fic-mode as reference, I implemented a way for words like TODO, etc. to be highlighted. Here 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(\\)\\([^)]+?\\)\\():\\)\\)\\|\\(\\(NOTE(\\)\\([^)]+?\\)\\():\\)\\)\\|\\(\\(FIXME(\\)\\([^)]+?\\)\\():\\)\\)\\|\\(\\(IMPORTANT(\\)\\([^)]+?\\)\\():\\)\\)\\)" 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  (3 font-lock-warning-face t t)
                              (4 font-lock-constant-face t t)
                              (5 font-lock-warning-face t t)
                              (7 font-lock-string-face t t)
                              (8 font-lock-constant-face t t)
                              (9 font-lock-string-face t t)
                              (11 font-lock-warning-face t t)
                              (12 font-lock-constant-face t t)
                              (13 font-lock-warning-face t t)
                              (15 font-lock-variable-name-face t t)
                              (16 font-lock-constant-face t t)
                              (17 font-lock-variable-name-face t t)
                              )))

(add-hook 'prog-mode-hook
          (lambda () (font-lock-add-keywords nil todo/keywords 'append)))

This was supposed to enable me to write things like TODO(name): something and have it properly highlighted like this:

What I wanted.

However, if I enable hl-line-mode using (global-hl-line-mode 1), the highlighting only happens if the point (cursor) is on a line different from the one on which the TODO... was typed. If I am on the same line, even doing font-lock-fontify-buffer does not refreshes syntax highlighting.

Also, once the highlighting has been "activated" (by pressing Enter, for example), if I come back to that line and edit something, the highlighting goes away once again.

Clash of the Highlitan

Can someone help as to how can I stop this clashing with hl-line-mode?


PS. I have set the line highlighting color using

(set-face-background hl-line-face theme/color/woodsmoke) ; hl-line

------------------------------------------------------------

Solution

Using the selected answer, putting

(set-face-attribute 'hl-line nil :inherit nil :background theme/color/woodsmoke)

before

(global-hl-line-mode 1)

fixes it.

Drew
  • 75,699
  • 9
  • 109
  • 225
strNOcat
  • 211
  • 2
  • 7

2 Answers2

2

I believe what you need to do is check the inheritance of the various faces. This can be done with describe-face. The available options are given in the manual under Face Attributes, but I believe the one you want is unspecified.

Here is what I use in my init.el for highlighting and how I solved the problem of the highlight clobbering other faces:

(load-theme 'tango-dark)
(global-hl-line-mode 1)
(set-face-attribute 'highlight nil :background "#3e4446" :foreground 'unspecified)

The first line changes the theme. The theme has a highlight color of bright yellow which will become apparent when we enable highlighting.

enter image description here

When highlighting is enabled, the highlight is glorious yellow,

enter image description here

This yellow overrides other faces,

enter image description here

However, using set-face-attribute, I can define what the :background is and leave the :foreground unspecified, leaving space for other faces,

enter image description here

Lorem Ipsum
  • 4,327
  • 2
  • 14
  • 35
  • I replaced `(set-face-background hl-line-face theme/color/woodsmoke)` by `(set-face-attribute 'highlight nil :background theme/color/woodsmoke :foreground 'unspecified)` but it didn't work. Thanks for pointing out the inheritance though, I'll try to hack something later. – strNOcat Feb 15 '19 at 13:43
  • Also, hl-line doesn't really override any other syntax highlighting that comes bundled with Emacs, just this one that I've defined myself. – strNOcat Feb 15 '19 at 13:51
  • EUREKA!!! Putting `(set-face-attribute 'hl-line nil :inherit nil :background theme/color/woodsmoke)` **BEFORE** `(global-hl-line-mode 1)` fixes it. I really need a better text editor! – strNOcat Feb 15 '19 at 13:57
0

I have no idea why your solution works: AFAICT the problem is unrelated to what your faces are defined to look like. Instead it's your todo/pos-in-doc-or-comment-region-p which will get confused because when (get-char-property pos 'face) is called it will be "blinded" by the hl-line face and won't see the underlying faces applied by font-lock.

A quick hack is to use get-text-property instead of get-char-property (since hl-line-mode uses an overlay rather than text-properties). Personally I'd probably go for

(defun todo/pos-in-doc-or-comment-region-p (pos)
  (save-excursion (nth 8 (syntax-ppss pos)))

instead, tho. Also, I hate save-match-data so I'd rewrite your loop as follows:

(defun todo/search-for-keyword (limit)
  (let (ret)
    (while
      (and (setq ret (re-search-forward "\\<\\(\\(\\(TODO(\\)\\([^)]+?\\)\\():\\)\\)\\|\\(\\(NOTE(\\)\\([^)]+?\\)\\():\\)\\)\\|\\(\\(FIXME(\\)\\([^)]+?\\)\\():\\)\\)\\|\\(\\(IMPORTANT(\\)\\([^)]+?\\)\\():\\)\\)\\)" limit t))
           (not (and (todo/pos-in-doc-or-comment-region-p (match-beginning 0))
                     (todo/pos-in-doc-or-comment-region-p (match-end 0))))))
    ret))
Stefan
  • 26,154
  • 3
  • 46
  • 84