TermBuf::Unicode
Character property lookup for the terminal buffer: display width, grapheme cluster break class, and the two auxiliary properties UAX #29 needs.
Every code point falls into exactly one range of Tables::RANGE_START, so a
lookup is a binary search with no miss case. Code points below FAST_LIMIT
skip the search entirely via a direct-indexed table built at startup, which
covers Latin, Greek, Cyrillic, Hebrew, Arabic, the combining diacriticals,
and most of the Indic scripts.
Constants
Variation selector 16, forcing emoji presentation and so a width of two.
Enclosing marks, general category Me. There are thirteen of them, so a
list costs less than a bit in the generated tables.
They matter only to .code_point_columns: a terminal counting per code
point gives an enclosing mark a column of its own, where it gives a
nonspacing mark none. That is the difference between 1️⃣ owning one
column and owning two.
Code points below this are resolved by direct index rather than search.
Variation selector 15, forcing text presentation and so a width of one.
Joins emoji into one cluster, and on most terminals into one glyph.
Class methods
Whether char is East Asian Ambiguous, and so rendered at a width the terminal's configuration decides.
Cells an East Asian Ambiguous character takes. Reads through to .policy,
which is where the answer lives now that it can be measured rather than
assumed.
Cells char occupies on its own, ignoring any cluster it belongs to. Control characters and default-ignorable code points report zero.
Columns a terminal takes for text when it counts them by summing the code points rather than by measuring the grapheme cluster.
Not what any standard says a cluster is worth: what
Quirk::PerCodePointColumns terminals do. Measured against Terminal.app
470.2 and GNU screen 5.0.2 over 5,274 clusters, in measurements/survey/.
The rule is East Asian Width per code point, with three departures.
- An ignorable character is charged what East Asian Width says rather than nothing. A zero width joiner is Neutral, so four joined faces own eleven; a tag character is Neutral, so a subdivision flag owns eight; the hangul fillers are Wide, so they own two apiece. The joiner and the tag were found one at a time and written down as two rules. They were one.
- An enclosing mark takes one, which is what makes a keycap own two.
- A regional indicator takes one rather than two, so a flag owns two and five indicators own five.
- Conjoining jamo are composed before counting, so the vowel and the tail take nothing and a syllable spelled out owns two, like the one it makes. This is the one place the terminal counts a cluster rather than its pieces. A vowel or tail with no lead is not something the samples cover, and is given nothing here.
Columns a terminal takes for text when it counts them by summing the code points rather than by measuring the grapheme cluster.
Not what any standard says a cluster is worth: what
Quirk::PerCodePointColumns terminals do. Measured against Terminal.app
470.2 and GNU screen 5.0.2 over 5,274 clusters, in measurements/survey/.
The rule is East Asian Width per code point, with three departures.
- An ignorable character is charged what East Asian Width says rather than nothing. A zero width joiner is Neutral, so four joined faces own eleven; a tag character is Neutral, so a subdivision flag owns eight; the hangul fillers are Wide, so they own two apiece. The joiner and the tag were found one at a time and written down as two rules. They were one.
- An enclosing mark takes one, which is what makes a keycap own two.
- A regional indicator takes one rather than two, so a flag owns two and five indicators own five.
- Conjoining jamo are composed before counting, so the vowel and the tail take nothing and a syllable spelled out owns two, like the one it makes. This is the one place the terminal counts a cluster rather than its pieces. A vowel or tail with no lead is not something the samples cover, and is given nothing here.
Indic conjunct break class of char, used by rule GB9c.
Yields each extended grapheme cluster of string in order, without
allocating: a Grapheme locates its cluster by byte offset.
What East Asian Width says char is worth, before anything zeroes it.
Cuts text down to at most width cells, marking the cut with marker. The marker is measured under policy too, so the result is never wider than width; when the marker alone will not fit, the text is cut without one.
Whether char has the Emoji property.
Narrower than .pictographic? and a different question. ⚑ U+2691 is
pictographic and is not an emoji, so a variation selector after it asks for
a presentation it does not have and it stays one column — both terminals
measured agree. The digits are the other way about: emoji, not pictographic,
which is what makes 1️⃣ two columns.
Fits text to exactly width cells: cut when it is too long, padded with fill when it is too short. A cluster dropped rather than split leaves a cell over, which is padded like any other.
All extended grapheme clusters of string, as separate strings. Convenient
for specs and one-off work; the buffer uses each_grapheme instead.
Number of terminal cells char occupies on its own, ignoring any grapheme cluster it may belong to. Control characters report zero; they are never stored in the buffer. Whether char is a format character or default ignorable: one the tables carry an East Asian Width for and nothing draws.
.char_width answers zero for these. .code_point_columns does not, since
a terminal counting per code point charges them anyway.
Whether char has the Extended_Pictographic property, used by rule GB11.
How clusters are measured when no policy is given. Buffer carries its
own, set from what the terminal said when asked; this is for casual callers
and for char_width, which has no cluster to consult.
How clusters are measured when no policy is given. Buffer carries its
own, set from what the terminal said when asked; this is for casual callers
and for char_width, which has no cluster to consult.
Total number of terminal cells string occupies, under policy.
Cuts text down to at most width cells, returning it unchanged when it
already fits. Nothing is added to mark the cut; see .ellipsize for that.
Whether byte continues a character rather than beginning one.
How many bytes the character starting with lead takes, or zero if lead is not a lead byte at all.
The over-long and surrogate ranges are excluded, so a byte this accepts begins a character that can exist.
How much of bytes forms whole characters.
A write can end anywhere, including the middle of a character, so the tail this leaves out has to be held until the rest of it arrives.
The width cells of text starting offset cells in — a horizontal window over a value too wide to show at once. A cluster crossing either edge is left out whole, and a window running past the end simply comes back short. A negative offset is allowed and starts the window before the text, which is what a marquee scrolling in from the left wants.