I went down a bit of a rabbit hole wondering why I was getting incomplete font-locking (highlighting) when evaluating in the REPL something like (zipmap (range 100) (repeat :foo)). My LLM managed to fix it by overriding cider-repl-handler but surely that is not the correct way to do this. Details and reproduction in 🧵 .
Here's the LLM generated fix that causes everything to be highlighted correctly. Maybe it breaks other stuff, not sure. Definitely feels like there must be a better way given how long CIDER has been around and how many people have put such great work into it.
(defun kl/cider-repl-handler-fontify-complete-values (buffer)
"Make a CIDER REPL handler that fontifies complete streamed values."
(let ((show-prompt t)
value-chunks)
(cider-make-eval-handler
:buffer buffer
:on-value (lambda (value)
(push value value-chunks))
:on-stdout (lambda (out)
(dolist (f cider--repl-stdout-functions)
(funcall f buffer out))
(cider-repl-emit-stdout buffer out))
:on-stderr (lambda (err)
(dolist (f cider--repl-stderr-functions)
(funcall f buffer err))
(cider-repl-emit-stderr buffer err))
:on-done (lambda ()
(when value-chunks
(cider-repl-emit-result
buffer
(apply #'concat (nreverse value-chunks))
t))
(when show-prompt
(cider-repl-emit-prompt buffer))
(when cider-repl-buffer-size-limit
(cider-repl-maybe-trim-buffer buffer))
(cider-repl--auto-inspect-last-result buffer)
(dolist (f cider--repl-done-functions)
(funcall f buffer)))
:on-content-type (lambda (value content-type)
(if-let* ((content-type* (car content-type))
(handler (cdr (assoc content-type*
cider-repl-content-type-handler-alist))))
(setq show-prompt (funcall handler content-type buffer value nil t))
(cider-repl-emit-result buffer value t t)))
:on-truncated (lambda ()
(cider-repl-emit-stderr buffer nil)))))
(advice-add 'cider-repl-handler
:override
#'kl/cider-repl-handler-fontify-complete-values)Some other LLM suggestions I tried (but which didn't fix the issue) were:
(setq font-lock-maximum-size nil)
(setq jit-lock-chunk-size 4500)Dug a bit deeper after lunch. Seems like the issue is related to how nrepl streams the output in chunks. If everything is on one line then it streams out as one chunk and gets highlighted correctly. However when using the default cider-print-fn set to 'pprint, the output is streamed out as three chunks. only the middle chunk is syntactically valid Clojure, which is why it gets highlighted properly. The first and last chunks have the (unmatched within the chunk) brace of the map, so they don't get highlighted properly.
An alternative "fix" is to add some advice to disable the nrepl streaming entirely:
(define-advice cider--repl-request-plist
(:filter-return (request) disable-repl-print-streaming)
(cl-loop for (key value) on request by #'cddr
append (list key
(if (equal key "nrepl.middleware.print/stream?")
nil
value))))
Still want a cleaner solution though...Investigation from when I encountered this in 2019: https://github.com/clojure-emacs/cider/issues/2628 Report of similar from as early as 2014: https://github.com/clojure-emacs/cider/issues/670 Smart to revisit this with coding assistant help. If I were you I'd add a new issue to the cider repo. 🙂
thanks for the background. Yeah, I can dig around and add to an existing or create new issue so it's more discoverable. I'm just sorta shocked that this is the "out of the box" default behavior. Then again, I've been using cider/emacs for 10+ years now myself, so I'm partly responsible for not noticing and trying to fix until now =P
Perhaps here has been a regression since the final comment in that first issue:
> I've also introduced cider-print-buffer-size which is set to 4k by default. I'm wary of using bigger buffer sizes by default, but everyone can bump them if they want to. I'm wondering whether to allow pretty-printing without streaming, but I probably won't do it as I don't see many benefits of this.
since increasing this value doesn't resolve the issue today.
Well, the problem is still the same - it's just hard to font-lock properly incomplete forms. That's why workaround was essentially to just font-lock one chuck forms and ignore the rest. I'm thinking that potentially we can just re-fontify everything once the streaming is over and perhaps that would be fine for most people.
I tracked the root cause down to nREPL and opened an issue there: https://github.com/nrepl/nrepl/issues/445
I’ll take a closer look, but I haven’t seem any reports of this in quite a while, so I’m not sure it’s really a recent regression.
Behavior is unchanged for me since our original investigation in 2019/ 2020 (https://github.com/clojure-emacs/cider/issues/2628).
Here's a zip file with two emacs configs you can use to reproduce the original behavior and fix. Run with
emacs -Q -l large-print-buffer/init.el
emacs -Q -l handler-rewrite/init.el
I don't think the cider versions matter, but I wanted a repro just to make debugging easier in case.