Newsletter, May 2023
Grapheme Cluster Line Wrapping and an Interview

May has come and gone, and Gio has grown some more, both in features and awareness.

I had the honor this past month of being interviewed about Gio on this episode of the Linux Lads podcast. Check it out if you’re so inclined.

Additionally, this month I was able to finish a long-awaited text feature: grapheme cluster line wrapping. In most languages, this is synonymous with “wrapping lines by breaking words if necessary.” However, there are languages in which the writing system has a less-clearly-defined notion of what a “word” is or how to break a line within one. As such, we break between “grapheme clusters,” which roughly map to what native language speakers perceive as “characters.” See below for more details. I’d like to thank Plato Team for supporting this work.

In the coming months, I hope to continue working on commonly-requested font/text features.


This month, Gio thanks the following organizations and community members for their ongoing support!

Supporting the whole team:

Supporting a maintainer:

Sponsorship money given to Gio enables Elias and I to cover the costs of running Gio’s infrastructure, to pay for some of our time spent maintaining and improving Gio, and to plan for funding significant feature work. You can support Gio by contributing on OpenCollective or GitHub Sponsors.

Changes by repo

Below you can find summaries and details of all changes across the official project repositories.

core gio

Elias fixed a window close bug reported by Jack Mordaunt and dropped a confusing key routing change.

I added some helpers for resizing layout.Constraints safely, enabled grapheme cluster line wrapping, and fixed a text shaper bug. Of these, only grapheme cluster line wrapping warrants more discussion.

You can now control the policy used to break lines when displaying text. There’s a new text.Parameters.WrapPolicy which can be set to WrapWords (the old behavior), WrapHeuristically (the new intelligent default), or WrapGraphemes (which will always choose to break words if it gets more characters per line). All text widgets surface a WrapPolicy field you can use to control this aspect of text shaping.

Mearaj enabled horizontal scrolling while holding the Shift key on Linux, Windows, and WASM. Thanks Mearaj!

Non-Breaking Changes by Author

Elias Naur:

  • app: replace uses of Window.dead with Window.destroy. There doesn’t seem to be a need for a two-step shutdown sequence, so a single channel is enough to trigger destruction of the Window. 8571b25f
  • Revert “io/router: try all handlers if a key don’t match the focus ancestor tree”. This reverts commit 28c206fc78c76b1481fc3ed4c28ce3562ce424ba. The commit introduced counter-intuitive behaviour as demonstrated by #503. In the meantime, topmost handlers now receive all unhandled key.Events[0], which should cover the use-cases that motivated the original commit. e3ef98dd
  • widget: update Editor.Delete documentation to refer to graphemes. a2523943

Chris Waldon:

  • layout: add resize helpers for constraints. This commit adds two helper methods to layout.Contraints that make it easier to manipulate the constraints while keeping their invariants. In particular, code manually manipulating constraints usually fails to correctly ensure that the max does not become smaller than the min, the min does not exceed the max, and that no value goes below zero. 59695984
  • text: fix over-reading on truncated EOF. When consuming text from an io.Reader, the shaper could hit an EOF when reading the text, then still try to check whether it was done by calling ReadByte() followed by UnreadByte(). The ReadByte() would still return EOF, but the UnreadByte() would then walk the iterator cursor backwards to the final byte of the text. If and only if the text was being truncated, this unexpected cursor position could cause the shaper to conclude that there were additional runes that were truncated, and thus the returned glyph stream would account for too many runes. This commit provides a test and a fix. 4677b72a
  • go.*,text,widget{,/material}: enable configurable line wrapping within words. This commit enables consumers of the text shaper to select a policy for how line breaking candidates will be chosen. The new default policy can break lines within “words” (UAX#14 segments) when words do not fit by themselves on a line. This ensures that text does not horizontally overflow its bounding box unless the available width is insufficient to display a single UAX#29 grapheme cluster. c6e4eecf


  • app: [linux,windows,wasm] scroll horizontally when shift key is pressed. Adds support for horizontal scroll using mousewheel with a shift key. Support is added for windows, linux (wayland and x11), js (wasm). febadd31


In x, I fixed some bugs in styledtext introduced by the text trunctor feature and updated to the latest Gio.

Lothar May improved the component.TextField’s visuals and simplified the implementation. Thanks Lothar!

Non-Breaking Changes by Author

Chris Waldon:

  • styledtext: handle new truncation behaviors. This commit updates styledtext to expect automatic text truncation and to properly process the results. 8432ec5
  • styledtext: fix possible infinite loop. This commit fixes a condition in which the styledtext display could loop infinitely if none of the text in a run could fit on a line. The text iterator would detect zero runes of text prior to the truncator symbol and would fail to make progress, performing the same shaping with the same runes on the next iteration. This change ensures that if the truncator is encountered after zero runes, it is treated as consuming a rune which must be a newline. 630678c
  • go.*: update to latest gio. f4f65e9

Lothar May:

  • component: If text_field hint text is empty, do not display a space in the field border. 5533984
  • component: remove type cast which is no longer needed. 711bcab


The examples have all been updated to use the latest Gio and x commits.

Non-Breaking Changes by Author

Chris Waldon:

  • go.*: update to latest gio and gio-x. bfc09af


Thanks for reading!

Chris Waldon