5

I am writing a font-lock rule that calls a function to decide what face to apply to a symbol. Here's a simplified version:

("\\(?1:\\s_+\\)"
 (1 (the-function 1)))

The problem is that this function needs to generate some data that is just a little bit slow to compute. So, when jit-font-lock starts calling this function for every symbol in the visible buffer, the lag is noticeable.

I could setq this “slightly-expensive” data to a variable,

(setq data-cache (generate-data))

and then the-function could just use data-cache instead of calling generate-data every time. But then I would have to jump through some non-trivial hoops to make sure that this cache is always properly invalidated.

Q: Does the font-lock engine offer help in this regard? How can I make sure it only runs (generate-data) once per redisplay?

Ideally, I would like to specify something like “let-bind data-cache to the return value of (generate-data). This way I would know that this cache was never outdated.

  • When should the cache be invalidated? (Or IOW, what does the return value of (generate-data) depend on?) – ffevotte Sep 5 '15 at 18:47
  • @Francesco The cache does not need to be invalidated while font-lock is doing its thing (which is why I was hoping font-lock could let-bind it for me). Technically, it needs to be invalidated before each user command, though I can think of other ways it could be done. The return value of generate-data depends on output from an asynchronous background process, and it affects the way that we handle user commands. – Malabarba Sep 5 '15 at 18:55
  • You could perhaps use font-lock's indirection mechanism, setting font-lock-fontify-region-function to a function which let-binds data-cache around the call to the prior value of font-lock-fontify-region-function. Sort of like an around-advice, except the indirection mechanism allows you to do it in a cleaner way. – ffevotte Sep 5 '15 at 19:12
  • @Francesco That's interesting. I'll give it a try! – Malabarba Sep 5 '15 at 19:24
  • @Francesco Yep, it works. Would you like to make that an answer? – Malabarba Sep 6 '15 at 13:21
4

You could perhaps use font-lock's indirection mechanism, setting font-lock-fontify-region-function to a function which let-binds data-cache around the call to the prior value of font-lock-fontify-region-function. Sort of like an around-advice, except the indirection mechanism allows you to do it in a cleaner way.

0

Elisp has closures now. Something like this should work:

;; -*- lexical-binding: t -*-    
(let ((list (let (cache)
              (list (lambda ()
                      (unless cache
                        (message "setting cache")
                        (setq cache 42))
                      cache)
                    (lambda ()
                      (message "invalidating cache")
                      (setq cache nil))))))
  (fset 'do-stuff (car list))
  (fset 'invalidate-cache (cadr list)))

(add-hook 'post-command-hook #'invalidate-cache)

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.