GTK 4 Spellcheck Support
GTK 4 Spellcheck Planning
This issue is to serve as a planning and tracking document for adding Spellchecking natively to GTK 4. There have been a number of attempts at various levels of spellcheck support in the past 20 years, and we are at a position in GTK 4 now to do them a bit better than they could be solved previously.
Some work-in-progress is available on wip/chergert/spellcheck
branch.
Spellcheck Providers
We'll need a number of spellcheck providers for platform integration so that the dictionaries match what the user expects from other applications native to the platform. Additionally, it helps to ensure that adding words to a dictionary are added session-wide as appropriate.
-
Enchant-2 (Linux/BSD/etc) which wraps various dictionaries like aspell. -
Hunspell (Linux/BSD/etc) provides better support for some languages. -
NSSpellChecker is the native spellchecker API for macOS. -
Windows Spell Checker API for native integration on Windows.
It has been suggested that we need support for both enchant-2 and hunspell because some language support is better with one over the other. That might also indicate a need to define which to use for a particular language, though environment variable or similar setting.
Multi-lingual support
Many users of GTK/GNOME are multi-lingual. It is important to support multiple dictionaries at once and avoid the situation of simply "joining" dictionaries. Multi-lingual users have been vocal about that not being the best solution for them.
See sections below on propagating input language through PangoLayout so that we have access to language post-itemization.
Container/Isolation Support
With the isolation created by containers such as Flatpak, we could lose the ability to edit the per-user dictionary. That means adding a word to the dictionary in app1
would not be visible to app2
. This is probably not ideal but I don't really know what the attack vector is for two applications to coordinate over dictionaries.
An existing portal may extended for this here.
-
Determine how to modify per-user dictionary in presence of application isolation
Tracking unchecked regions
Tracking regions of text that have not been spellchecked can become quite laborious when you have a buffer that can be changed programatically. For example, GSpell uses a copy of GtkSourceRegion to handle this. The worst sort of case is a buffer full of a
that is each replaced with b
.
We have a new data-structure for this: GtkTextRegion. It combines a B+tree with a piecetable to allow for unchecked region tracking in very little time or effort. Additionally, it allows for tracking changes the same across both GtkTextView and GtkText.
-
Track changes to buffers in scalable manner
Making changes visible to the user
Currently, existing spellcheck tooling adds GtkTextTag
to a GtkTextBuffer to denote misspelled spans using the PANGO_UNDERLINE_ERROR
attribute. This causes changes to the underlying buffer which can be non-ideal as it invalidates cached line displays.
With some work to PangoLayout
we can possibly change these directly without affecting the display so that spellchecking can both be 1) done in a background idle and 2) reduce visual damages.
-
Allow PangoLayout
to change underline semantics of segments without requiring relayout. -
Support dashed and dotted lines in Pango markup and renderers.
Language propagation
Languages that are displayed are perhaps different from languages that were input. PangoAttributes can contain language information which we can use when spellchecking.
If we defer the spellcheck until we have a PangoLayout, then we can benefit from Pango doing language calculation for us based on a number of itemization steps.
-
Propagate language from input into PangoAttrLanguage
Selecting corrections
We need the ability to select corrections. Generally speaking, we can probably get away with a GListModel
from the spelling backends with replacement words.
We do now, however, that simply joining dictionaries together is not a good solution to this problem so we should avoid that if possible. We want corrections related to the language of the misspelled word as discovered by Pango (and/or propagated to Pango from the application).
-
Prioritize corrections by language of input segment
Navigating misspelled words
Users often want to spellcheck a document at once rather than incrementally so that they may replace all instances of a misspelled word. Gspell has the concept of a "Navigator" for this. On macOS, it seems to be builtin as well using a "panel" (dialog in GTK parlance).
We probably want something like this too which can be reached from a GtkTextView popover.
-
GtkDialog to navigate through misspelled words and mass change/edit/ignore/add corrections
Advancing checks in the spellchecker
We may want to make the spellchecker as lazy as possible, only updating things right before they are to be displayed on screen. The implementation of this could look very different between GtkTextView (GtkTextLayout) and GtkText (which uses gtk_snapshot_render_layout() directly).
Auto-capitalization
In some situations, auto-capitalization might be wanted. However, we might need something to denote those regions because it could clearly be very annoying in others.
This is possibly something that could be pushed off into Input Methods.
Undoing changes
Some mobile platforms allow you to undo text you've typed after having typed it. To do this we'd need to keep track of the correction placement w/ original word, or at least a backpointer into the GtkTextHistory.
For something like GtkTextView, that could mean a GtkTextTag around the correction with extra data about what was replaced. Ideally though, we'd be able to share implementation with GtkText.
Avoiding highlighting the current word
So we are not annoying, we really want to avoid spellchecking the word attached to the cursor. Once whitespace is inserted or a movement occurs, we can check the word.
Using in Applications
We'd like it to be as simple as toggling :enable-spellcheck
on a GtkTextView
or GtkText
/GtkEditable
to have spellcheck enabled. This ensures ease of use from tooling such as UI designers. It should not, of course, be enabled on password entries.