tl;dr: Calling doc.markContentsDirty(0, len(p.b)) suffices to recolor a node! This should be done instead of calling highlighter.rehighlight explicitly.
I could never have found this bug if I hadn't seen how fast pyzo colorizing code was within pyzo itself compared to the same code within Leo.
Having refresh-from-disk do the coloring correctly and quickly was the crucial lucky break. Tracing showed that a big @edit node was being colorized correctly despite highlighter.rehighlight not being called.
After a bit of noodling (without beer) I saw that the body pane's QTextDocument must be repeatedly calling highlighter.highlightBlock. I verified this was so (without huge traces) by examining the before and after counts of highlighter.n_calls. As hoped, these jumped, indicating that something (QTextDocument is the only candidate) was in control.
This is a lucky, lucky break on Friday the thirteenth ;-) It is likely that Leo's existing colorizers can be speeded up by 10x. If so, there will be no need for the big text hack. Crucially, Qt does not show the text until it has been fully colorized.
Furthermore, close study of the pyzo code shows that actual syntax coloring could now be deferred until idle time, thereby further improving performance.
Pyzo is full of superb code, and pyzo's colorer is no exception. I'm not sure whether to adapt pyzo's code for all syntax coloring, but I'm tempted. It would be a big project.
In the meantime, I can adapt two good ideas from the pyzo colorer:
1. Precomputing QTextFormat objects saves a lot of time. Leo's present colorizers do far too much work withing the main colorizing loop.
2. Using a special tag for unterminated strings is genius. The three little dots are a great visual cue, and terminating the token at the end of the line means that adding a quote does not cascade to all following lines. A great hack.
I'm glad this is behind us. I was starting to doubt my sanity, and starting to imagine bugs that would never be found...
The way is now open for more pyzo integration. I am seriously considering replacing Leo's custom text widget with pyzo's. It a big project, but it will pay huge dividends.
Edward