1

I want to highlight foo in foo:: without highlighting foo::<bar>, using font-lock-keywords. This is the result I want:

correct higlighting

Initially I tried this:

(defvar example-font-lock-keywords
  `((,(rx (group (1+ word)) "::" (not (any "<"))) 1 font-lock-type-face)))

(define-derived-mode example-mode prog-mode "Example"
  (setq-local font-lock-defaults '(example-font-lock-keywords)))

But that gave the following:

bad trailing character

Instead I tried two separate keywords:

(defvar example-font-lock-keywords
  `((,(rx (group (1+ word)) "::") 1 font-lock-type-face)
    ;; This is ignored if I use `default', but other faces work!
    (,(rx (group (1+ word)) "::<") 1 font-lock-variable-name-face t)))

(define-derived-mode example-mode prog-mode "Example"
  (setq-local font-lock-defaults '(example-font-lock-keywords)))

The second pattern is used if I specify font-lock-variable-name-face, but if I use default, the whole pattern is ignored!

  • Question: In the example given the colons after module1 are not highlighted, whilst description says foo:: - including colons. Understand it's about foo (colon) not followed by foo (colon) <bar> - where colons never get highlight. – Andreas Röhler Dec 31 '15 at 9:02
  • I don't want to highlight the colons. I've clarified the question. – Wilfred Hughes Dec 31 '15 at 10:03
3

The problem is that your regular expression eats the character behind the second colon and the next search starts behind that character. That is why the first letter of module2 is not highlighted.

You may only look at the character behind the second colon but you may not include it into the regular expression.

Basis for a working version:

(defvar example-font-lock-keywords
  `((example-font-lock-matcher 1 font-lock-type-face)))

(defun example-font-lock-matcher (limit)
  "Matcher matching \"keyword::\" but only if we are not looking at < afterwards."
  (let (match)
    (while (and (setq match (re-search-forward "\\_<\\(\\(?:\\sw\\|\\s_\\)+\\)::" limit t))
        (eq (char-after) ?<)))
    match))

(define-derived-mode example-mode prog-mode "Example"
  (setq-local font-lock-defaults '(example-font-lock-keywords)))

I think that solves your question, but you have still work to do. For an instance you should consider whether there may be some whitespace in between the colon and the <.

If you actually always want to highlight the first keyword in the case that the two colons are followed by a further keyword the following version would be even more appropriate:

(defvar example-font-lock-keywords
  `(("\\_<\\(\\(?:\\sw\\|\\s_\\)+\\)::[[:space:]]*\\_<" 1 font-lock-type-face)))

(define-derived-mode example-mode prog-mode "Example"
  (setq-local font-lock-defaults '(example-font-lock-keywords)))

Allow me one further remark. It would be nice if you would not only post a picture of the text to be highlighted but also the text itself. This would ease the reconstruction of the problem for the people who want to help you. I do so here for other potential helpers:

use module1::function;
use module1::module2::function;

foo::<bar>
  • Thanks, that almost works. There's never any whitespace before the <. However, your matcher solution also highlights the ::, which isn't what I want. (P.s. sorry for not pasting the sample text!) – Wilfred Hughes Dec 31 '15 at 20:48
  • Edited to fix the issue mentioned. – Wilfred Hughes Dec 31 '15 at 20:49

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.