Files
wehub-resource-sync bd44b5aa08
Test / build-libghostty-vt (x86_64-windows-gnu) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-ios) (push) Has been cancelled
Test / build-libghostty-vt-macos (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt-macos (x86_64-macos) (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-dist (push) Has been cancelled
Test / GTK x11=true wayland=true (push) Has been cancelled
Test / Build -Dsimd=false (push) Has been cancelled
Test / Build -Dsimd=true (push) Has been cancelled
Test / Build -Dsentry=false (push) Has been cancelled
Test / Build -Dsentry=true (push) Has been cancelled
Test / zig-fmt (push) Has been cancelled
Test / GitHub Actions Pins (push) Has been cancelled
Test / prettier (push) Has been cancelled
Test / swiftlint (push) Has been cancelled
Test / alejandra (push) Has been cancelled
Test / typos (push) Has been cancelled
Nix / Required Checks: Nix (push) Has been cancelled
Nix / check-zig-cache-hash (push) Has been cancelled
Test / skip (push) Has been cancelled
Test / Required Checks: Test (push) Has been cancelled
Test / build-bench (push) Has been cancelled
Test / list-examples (push) Has been cancelled
Test / Example ${{ matrix.dir }} (Windows) (push) Has been cancelled
Test / build-cmake (push) Has been cancelled
Test / test-lib-vt-pkgconfig (push) Has been cancelled
Test / build-flatpak (push) Has been cancelled
Test / build-snap (push) Has been cancelled
Test / build-libghostty-vt (aarch64-linux) (push) Has been cancelled
Test / build-libghostty-vt (aarch64-macos) (push) Has been cancelled
Test / build-libghostty-vt (wasm32-freestanding) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-linux-musl) (push) Has been cancelled
Test / build-libghostty-vt (x86_64-macos) (push) Has been cancelled
Test / build-libghostty-vt-android (aarch64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-android (arm-linux-androideabi) (push) Has been cancelled
Test / build-libghostty-vt-android (x86_64-linux-android) (push) Has been cancelled
Test / build-libghostty-vt-windows (push) Has been cancelled
Test / build-libghostty-windows-gnu (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-linux-libghostty (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-dist-lib-vt (push) Has been cancelled
Test / trigger-snap (push) Has been cancelled
Test / trigger-flatpak (push) Has been cancelled
Test / build-macos (push) Has been cancelled
Test / build-macos-freetype (push) Has been cancelled
Test / test (push) Has been cancelled
Test / test-lib-vt (push) Has been cancelled
Test / GTK x11=false wayland=false (push) Has been cancelled
Test / GTK x11=true wayland=false (push) Has been cancelled
Test / GTK x11=false wayland=true (push) Has been cancelled
Test / test-macos (push) Has been cancelled
Test / test-windows (push) Has been cancelled
Test / Build -Di18n=false (push) Has been cancelled
Test / Build -Di18n=true (push) Has been cancelled
Test / Build test/fuzz-libghostty (push) Has been cancelled
Test / shellcheck (push) Has been cancelled
Test / translations (push) Has been cancelled
Test / blueprint-compiler (push) Has been cancelled
Test / Test pkg/wuffs (push) Has been cancelled
Test / Test build on Debian 13 (push) Has been cancelled
Test / valgrind (push) Has been cancelled
Test / Example ${{ matrix.dir }} (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:02:48 +08:00

155 lines
6.2 KiB
C

/**
* @file unicode.h
*
* Unicode utilities - codepoint properties matching the terminal's
* text layout semantics.
*/
#ifndef GHOSTTY_VT_UNICODE_H
#define GHOSTTY_VT_UNICODE_H
/** @defgroup unicode Unicode Utilities
*
* Unicode codepoint properties matching the terminal's text layout
* semantics.
*
* ## Basic Usage
*
* Use ghostty_unicode_codepoint_width() to determine how many terminal
* grid cells a codepoint occupies, using the exact same width table the
* terminal itself uses when laying out printed text. Use
* ghostty_unicode_grapheme_width() to segment and measure full grapheme
* clusters with the same rules the terminal uses when mode 2027 is
* enabled. These functions are useful for predicting column layout of
* text that has not yet been written to the terminal, such as IME
* preedit (composition) overlays.
*
* @{
*/
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Returns the terminal display width of a Unicode codepoint in
* terminal grid cells: 0, 1, or 2.
*
* This is the same width table the terminal itself uses when laying
* out printed text, so callers can predict column layout (e.g. IME
* preedit overlays) that exactly matches what the terminal will do
* when the text is actually written to it.
*
* Semantics:
* - Returns 0 for zero-width codepoints: C0/C1 control characters,
* nonspacing and enclosing combining marks, default-ignorable
* codepoints (ZWJ, ZWNJ, variation selectors, etc.), and
* surrogate codepoints.
* - Returns 2 for wide codepoints: East Asian Wide/Fullwidth
* (including emoji with default emoji presentation) and regional
* indicators. Width is clamped to 2 (e.g. the three-em dash).
* - Returns 1 for everything else, including invalid codepoints
* beyond U+10FFFF (this function is total; it never fails).
*
* This operates on a single codepoint only and therefore cannot account
* for grapheme-cluster-level width rules (VS16 emoji presentation,
* combining sequences, etc.). For cluster-accurate widths, use
* ghostty_unicode_grapheme_width(). Summing per-codepoint widths is only
* correct when mode 2027 (grapheme clustering) is disabled.
*
* This function is pure, allocates nothing, and is thread-safe.
*
* @param cp The Unicode codepoint to measure
* @return Display width in cells: 0, 1, or 2
*/
GHOSTTY_API uint8_t ghostty_unicode_codepoint_width(uint32_t cp);
/**
* Measures the terminal display width of the first grapheme cluster in a
* sequence of Unicode codepoints.
*
* This uses the exact same grapheme segmentation and cluster width rules
* the terminal itself uses when printing text with grapheme clustering
* enabled (mode 2027), so callers can predict column layout (e.g. IME
* preedit overlays) that exactly matches what the terminal will do when
* the text is actually written to it. Unlike
* ghostty_unicode_codepoint_width(), this accounts for cluster-level
* rules: emoji variation selectors, ZWJ sequences, combining marks, and
* skin tone modifiers.
*
* Reads codepoints from cps until the terminal would consider the
* grapheme cluster complete, stores the cluster's total width in cells
* (0, 1, or 2) into width (which may be NULL if only segmentation is
* desired), and returns the number of codepoints consumed. Returns 0 if
* and only if len is 0; otherwise consumes at least one codepoint. Measure
* a whole string by calling in a loop:
*
* @code
* size_t total = 0;
* for (size_t i = 0; i < len;) {
* uint8_t width;
* i += ghostty_unicode_grapheme_width(cps + i, len - i, &width);
* total += width;
* }
* @endcode
*
* This is not a streaming API. The provided sequence must contain a
* complete first grapheme cluster, or the logical end of the string. If
* input arrives in chunks, keep buffering while this function consumes all
* available codepoints (return value == len) and the stream may still
* continue; a later codepoint could still extend the cluster and change
* its width.
*
* Width semantics, matching the terminal with mode 2027 enabled:
* - The cluster starts at the width of its first codepoint, as returned by
* ghostty_unicode_codepoint_width().
* - VS16 (U+FE0F) forces the cluster wide (2) and VS15 (U+FE0E) forces it
* narrow (1), but only when the immediately preceding codepoint in the
* cluster is a valid emoji variation sequence base (per Unicode
* emoji-variation-sequences.txt). Invalid variation selectors are
* ignored entirely.
* - Any other continuation codepoint that contributes to grapheme width
* forces the cluster wide (2). Note this means cluster width is NOT the
* maximum of per-codepoint widths: some continuation marks have narrow
* codepoint width yet still widen the cluster.
*
* Mode dependence: this models mode 2027 (grapheme clustering) enabled,
* which is Ghostty's recommended configuration. When mode 2027 is
* disabled, clusters never combine and variation selectors never change
* width; predict layout in that case by summing
* ghostty_unicode_codepoint_width() over each codepoint instead.
*
* Edge cases:
* - Codepoints beyond U+10FFFF consume one codepoint, have width 1, and
* are always cluster boundaries. This function is total; it never fails.
* - Control characters (C0/C1, CR, LF) are never printed through the
* terminal's text path; passing them here returns an unspecified (but
* stable and bounded) result.
* - A cluster whose first codepoint is zero-width (e.g. a lone combining
* mark) is malformed at a cell start; the terminal may attach it to
* earlier screen content. This function reports the fold result for the
* sequence in isolation (typically 0).
*
* This function is pure, allocates nothing, and is thread-safe.
*
* @param cps Pointer to codepoints (may be NULL only when len is 0)
* @param len Number of codepoints available
* @param width Out: cluster display width in cells (0-2); may be NULL
* @return Number of codepoints in the first grapheme cluster
*/
GHOSTTY_API size_t ghostty_unicode_grapheme_width(const uint32_t *cps,
size_t len,
uint8_t *width);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_UNICODE_H */