PR #4147 fixes a medium-scale performance bug. While doing so, I discovered two ways of collapsing the complexity of the colorizer.
Naive expectations
We have the right to expect that the qsh will work as follows:
- When changing nodes, the qsh should call _redraw for every line of p.b.
- Otherwise, we expect the qsh to issue highly optimized calls to _redraw when users edit text.
In fact, the qsh called _redraw for all lines of p.b whenever the user changed p.b. Ouch!
The PR identifies two culprits as the cause of the performance bug.
jedit.colorizer
Previously, this method always forced a full redraw. That makes no sense! Now it contains the following new code:
# #4146: Fully recolor p.b *only* if necessary.
old_language = self.language
self.updateSyntaxColorer(p)
if p.v == self.old_v and self.language == old_language:
return
jedit._redraw
Imagine my surprise when I found the following code at the start of jedit._redraw:
block_n = self.currentBlockNumber()
n = self.prevState()
if p.v == self.old_v:
new_language = self.n2languageDict.get(n)
if new_language != self.language:
self.language = new_language
self.init()
else:
self.updateSyntaxColorer(p) # Force a full recolor
assert self.language
self.init_all_state(p.v)
self.init()
Huh??? My intense study of the code showed me that jedit._redraw was a callback for qsh.highlightBlock. Nothing else should ever be calling jedit._redraw. That's why I added the leading underscore.
Forcing the qsh to do a full redraw inside _redraw is utterly misguided. It is a gross interference with the qsh!
I immediately removed this bizarre code. All of a sudden, for the first time in Leo's history, the qsh worked as one would naively expect!
Summary
How did Leo's legacy syntax colorer have any chance of working? It's a mystery.
I fixed the two culprits as follows:
- jedit.colorize forces a full redraw only when Leo changes nodes.
- jedit._redraw never forces a full redraw.
After these changes, the qsh operates exactly as one would naively expect.
Edward