I think I might have found a bug in GNU Emacs but I want to check my understanding first.

In Search Based Fontification it is possible to specify a function as a matcher. It must obey the contract

it receives one argument, the limit of the search; it should begin searching at point, and not search beyond the limit. It should return non-nil if it succeeds, and set the match data to describe the match that was found. Returning nil indicates failure of the search.

In addition, for multi-line matches it is possible to extent the region to be fontified by adding a routine to font-lock-extend-region-functions that in-place updates the font-lock-beg or font-lock-end variables (these variables are not visible in a function matcher).

Indeed, I have confirmed that if I extend the region in a font-lock-extend-region-functions then the limit does increase in my function matcher!

However, if we use an an anchored matcher, having the form (matcher . anchored-highlighter), where the anchored-highlighter is a function, my custom font-lock-{beg,end} regions are ignored!

Is there something I need to do so that anchored matchers receive the calculated regions or are they only designed to extend to the end of the current line by default?

  • I don't know much about font lock, but: How are you triggering font lock? Fontifying a whole buffer/region, or in response to making an edit to a buffer, or in response to scrolling (JIT lock)? Are you using a test framework? Commented Nov 11, 2018 at 14:53
  • @CroadLangshan I don't understand your question. font-lock is a "we call you API" that's documented in quite some detail in the docs I linked from the question. I think this one needs a font lock expert :-)
    – fommil
    Commented Nov 11, 2018 at 15:04
  • Sure, and maybe you looked at the code too, but the reason I asked is that looking at the code, I have a suspicion that may be relevant, and I thought I might give it a try and see if I can understand why that happens -- which may lead to an answer (even though you're asking about intent). As for what I meant: as I understand it, for example: if one visits a file, the whole buffer may not be immediately fontified, but only (roughly) the visible region. On the other hand if you're say running font-lock-fontify-buffer, JIT lock presumably won't be used. Commented Nov 11, 2018 at 15:18
  • 1
    Yes I think I understood that fommil. My guess, nevertheless, is that you may see the issue only in particular circumstances, because it looks like font-lock-extend-region-functions is not always called, at least not in a straightforward way (for example by font-lock-extend-jit-lock-region-after-change). Over and out Commented Nov 11, 2018 at 15:37
  • 1
    thanks @CroadLangshan I think I figured it out by following the source code... I added an answer. It seems the documentation just wasn't clear on this point. I can understand the actual (and intended) behaviour now.
    – fommil
    Commented Nov 11, 2018 at 15:44

2 Answers 2


I noticed that you have found the answer to your question already, by looking at the source code.

The behaviour is in fact documented. The doc string of the variable font-lock-keywords contains the following, in the section describing MATCH-ANCHORED:

The limit of the MATCHER search defaults to the end of the line after PRE-MATCH-FORM is evaluated. However, if PRE-MATCH-FORM returns a position greater than the position after PRE-MATCH-FORM is evaluated, that position is used as the limit of the search.

Technically, "returns a position" means that the expression evaluates to an integer value.

For example, the following makes the inner search use the match found in the outer search (which may span multiple lines if font-lock-multiline is non-nil):

  ;; pre-match-form
    (goto-char (match-beginning 0))
    (match-end 0))
  ;; post-match-form
  (1 'font-lock-variable-name-face prepend)))
  • argh, I guess I should remember to read the C-h v help as well as the Lisp manual in future...
    – fommil
    Commented Nov 11, 2018 at 21:32

I think I've tracked the issue to font-lock-fontify-anchored-keywords which is called with a limit parameter, but then limit is mutated very intentionally to the limit generated by the outer matcher... so I think this is NOT a bug, but just very different behaviour to what I expected.

(defsubst font-lock-fontify-anchored-keywords (keywords limit)
  (let ((matcher (nth 0 keywords)) (lowdarks (nthcdr 3 keywords)) highlights
    (lead-start (match-beginning 0))
    (pre-match-value (eval (nth 1 keywords))))
    (if (not (and (numberp pre-match-value) (> pre-match-value (point))))
        (setq limit (line-end-position))
      (setq limit pre-match-value)

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.