mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
widget: [API] implement UAX#29 grapheme clustering in text widgets
This commit teaches the text widgets how to position their cursor according to grapheme cluster boundaries rather than rune boundaries. While this is more work, the results better match the expectations of users. A "grapheme cluster" is a user-perceived character that may be composed of arbitrarily many runes. I chose to implement this within widgets for two reasons: - grapheme cluster boundaries would be extremely difficult to encode within the glyph stream returned by the text shaper - not all text needs to be segmented, only text that can be interacted with All mutation operations exposed by widget.Editor now work in terms of grapheme clusters instead of runes. Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
+10
-5
@@ -742,18 +742,21 @@ func (e *Editor) CaretCoords() f32.Point {
|
||||
// direction to delete: positive is forward, negative is backward.
|
||||
//
|
||||
// If there is a selection, it is deleted and counts as a single rune.
|
||||
func (e *Editor) Delete(runes int) {
|
||||
func (e *Editor) Delete(graphemeClusters int) {
|
||||
e.initBuffer()
|
||||
if runes == 0 {
|
||||
if graphemeClusters == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
start, end := e.text.Selection()
|
||||
if start != end {
|
||||
runes -= sign(runes)
|
||||
graphemeClusters -= sign(graphemeClusters)
|
||||
}
|
||||
|
||||
end += runes
|
||||
// Move caret by the target quantity of clusters.
|
||||
e.text.MoveCaret(0, graphemeClusters)
|
||||
// Get the new rune offsets of the selection.
|
||||
start, end = e.text.Selection()
|
||||
e.replace(start, end, "", true)
|
||||
// Reset xoff.
|
||||
e.text.MoveCaret(0, 0)
|
||||
@@ -889,7 +892,9 @@ func (e *Editor) replace(start, end int, s string, addHistory bool) int {
|
||||
|
||||
// MoveCaret moves the caret (aka selection start) and the selection end
|
||||
// relative to their current positions. Positive distances moves forward,
|
||||
// negative distances moves backward. Distances are in runes.
|
||||
// negative distances moves backward. Distances are in grapheme clusters,
|
||||
// which closely match what users perceive as "characters" even when the
|
||||
// characters are multiple code points long.
|
||||
func (e *Editor) MoveCaret(startDelta, endDelta int) {
|
||||
e.initBuffer()
|
||||
e.text.MoveCaret(startDelta, endDelta)
|
||||
|
||||
Reference in New Issue
Block a user