There is a many-to-many relationship between:
- Features that insert and delete text, which can also change the selection bounds.
Features that listen to the GtkTextBuffer::insert-text, ::delete-range or ::mark-set signals.
The first set of features triggers the second set of features, which can be bad for performances.
Features that insert and delete text
- File loading
- Replace, replace all
- Change case
- Join lines
- Comment/Uncomment (gedit plugin)
- Sort (gedit plugin)
- Any others?
Features that listen to insertions or deletions
- Syntax highlighting
- Interactive completion
- Word completion provider (to update the library of words)
- Any others?
Features that listen to selection bounds changes
- Matching bracket highlighting
- In gedit, update the cursor position in the statusbar
In GtkTextView, update the clipboard
- Any others?
In many cases the features that listen to the signals can be disabled or at least optimized, depending on the feature that inserted or deleted text. Examples:
The interactive completion should be activated only for normal key presses handled by GtkTextView. So for all GtkSourceView or application features, the interactive completion must be disabled (and not only for performances).
- The indent/unindent or comment/uncomment don't change the list of words, so the word completion provider can be optimized.
- Features that listen to selection bounds changes can be disabled during a user action (between ::begin-user-action and ::end-user-action), to have only one update at the end.
When doing a bunch of inserts and deletes, we can explicitly disable other features. But since it's a many-to-many relationship, we don't want to have each feature depend on each other, it would become a mess.
Solution 1: user action types
Attach a type and description to a user action. Examples of types:
The description would be useful for the Undo/Redo, to display e.g. a tooltip.
The insert-text and delete-range callbacks could retrieve the current action type, to optimize the work to do. Apps could create their own action types. But the GtkSourceView features would only be aware of the other GtkSourceView features, without a hard dependency on them, just a dependency on the action types (which would be centralized in one header).
Or another design is to let the GtkSourceView object do the orchestration, but it can only disable a feature, not optimize it. So the GtkSourceView object would listen to ::begin-user-action and ::end-user-action. In ::begin-user-action, it retrieves the action type and disable the useless features. In ::end-user-action, it re-enables the features. The GtkSourceView object is anyway aware of all the library features, since it's the main object. This would avoid a specific feature to be aware of another one, even if it's just the action type.
Also, how to attach the user action type and description? A new API is needed, but at least at the beginning this API can be private.
Solution 2: user action flags
Attach flags to a user action. Examples of flags:
- Disable interactive completion.
- Doesn't change words.
The advantage is that apps can set the flags, so that GtkSourceView features can be optimized for insertions/deletions done by an app.
Flags can of course be combined with user action types and descriptions.
Solution 3: new methods/properties/signals in GtkSourceBuffer
Through a centralized location, in particular the buffer, all those operations call methods on the buffer. And then the buffer emits a signal or a property change and all the parts that need to get updated (highlighting, completion, etc) listen to that.