Mike Lischke:
> I haven't found any discussion related to that with a quick search, so let me ask here: what would you think of letting Scintilla allow to change certain states from a background thread? ...
GUI toolkits often restrict threading. Events must, almost always, be (initially) handled on a designated GUI thread which is generally the main thread of the process. Some platforms allow drawing on another thread but its uncommon to implement, there are often limitations and threaded calls receive less testing and may have consequent bugs. Documentation of threading limitations is poor. Platforms change threading capabilities over time - GTK+ deprecated threaded GUI operations in version 3.6.
Some of the major time sinks in Scintilla are when drawing or preparing for drawing. There are some candidates for threaded code in these areas. For example, it might be possible to divide measuring text up between threads, but the font objects and measurement contexts provided by the platform and needed for this may not be thread safe. Thus there would have to be a platform opt-in to threaded measurement and a non-threaded code path. Text measurement relies strongly on two caches (PositionCache and LineLayoutCache) and access to these would have to be synchronized with mutexes or similar, which would reduce performance.
Because of the complexity, uncertain performance gains, and having reasonable performance for most uses, I've not implemented any threading inside Scintilla. The only work I've done was to make loading and saving on background threads work reasonably well since I/O latencies can be large.
> Additionally, have you ever thought about letting the lexers do their job in a background thread?
Yes, a lot. Also moving lexing into a separate tightly sandboxed process for security. There are 111 lexers delivered with Scintilla and these differ in complexity, quality and degree of testing. The only security advisory ever received for Scintilla was for a lexer.
For a threaded lexer/folder access to the text, style information, and fold state must be made safe for both the lexer and other potentially concurrent activities like drawing. It may be possible to synchronize these uses by locking some or all of the state of Scintilla but there are costs to locking and the granularity of locking may cause performance problems in either the lexer or the other code. Lexers would have to handle situations where text was changed before their current position causing them to abort and restart.
Folding is more difficult than lexing since each change in fold level can be and normally is reported to the container. This allows the container to ensure its folding rules are followed such as showing sections which have had their fold headers removed. The report is done as a normal platform-mediated event so is delivered on the GUI thread. It may be possible to buffer fold level changes and deliver them as a block after fold level discovery has occurred.
Instead of locking Scintilla data structures while lexing, it may be possible (particularly when using a separate process) to make a copy of the text being lexed plus some related information and send this to the lexer; have the lexer/folder use this to produce block of styles and a block of fold levels; then send the results back to the main thread which checks that no changes occurred while the lexing was performed and integrate the results. For copying, you would want to limit the amount copied since only a limited range should be lexed each time and the document may be many megabytes. However, copying is made more difficult since lexers may backtrack before the range being lexed to discover additional state information.
Threaded lexing is a big messy job and its unlikely I'll implement it unless a customer needs it enough to pay for the work.
> For large files there can go by like 10+ secs until the lexer has done lexing the entire file. By letting it do that in the background we can let the user more quickly interact with a just opened file. What makes this worse is that lexing is only done when I bring a line into view that has not been lexed yet. So even if I wait 1 minute after loading it will not speed up lexing.
The application can ask for ranges beyond current visibility to be lexed with SCI_COLOURISE. Implement an idler/timer and ask for an incremental lex in each call.
The 'Responsive Scrolling' feature of OS X 10.9 works (partly) by asking the view to draw not-yet-visible rectangles in idle time, which also causes additional lexing in Scintilla. Scintilla can not yet turn on responsive scrolling, mostly because it doesn't invalidate these speculative rectangles when required by lexing but there are also issues with the animated find indicator and line versus pixel scrolling.
> Say, I have a big script file and want to add markers for each statement + error markers for syntax errors. Currently this is only possible from the main thread which adds a visual hick-up when opening/pasting large text.
A technique that may work but is dependent on the particulars of your operation is to divide the operation into work that can be performed in the background and the minimal work that changes Scintilla. The implementation of spell-checking in SciTE for OS X works with a loop that copies the text from a particular number of lines; performs the spell checking on another thread producing a vector of mistake ranges; then, on the main thread, sets an indicator for each mistake range. This works well since the spell checking calls are much slower than setting indicators in Scintilla.
Neil