text

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 29, 2025 License: MIT Imports: 11 Imported by: 0

README

text - Unicode-Aware Text Operations for Go

A practical, high-level text manipulation library that provides Unicode-correct operations for terminal UIs, text editors, and layout engines.

Features

Core Text Operations
  • Unicode-Correct Width Calculation - Properly handles CJK characters, emoji, combining marks
  • Smart Text Wrapping - Uses UAX #14 line breaking algorithm
  • Intelligent Truncation - Respects grapheme cluster boundaries (won't break emoji!)
  • Text Alignment - Left, right, center, justify
  • Bidirectional Text - Supports Arabic, Hebrew mixed with Latin (UAX #9)
  • Grapheme Awareness - Treats emoji sequences, combining marks as single units
  • Word & Sentence Boundaries - Uses UAX #29 for proper text segmentation
  • Renderer-Agnostic - Works with terminals (cells) and canvas (pixels)
CSS Text Module Support
  • White Space Processing - Normal, pre, nowrap, pre-wrap, pre-line, break-spaces
  • Text Transformation - Uppercase, lowercase, capitalize, fullwidth, full-size kana
  • Word Breaking - Normal, break-all, keep-all, break-word
  • Line Breaking - Auto, loose, normal, strict, anywhere
  • Overflow Wrapping - Control word breaking to prevent overflow
  • Hyphenation - None, manual, auto (with UAX #14 integration)
  • Letter & Word Spacing - Type-safe spacing with CSS units
Vertical Text Layout
  • Writing Modes - Horizontal-tb, vertical-rl, vertical-lr, sideways
  • Text Orientation - Mixed, upright, sideways (UAX #50)
  • Character Rotation - Automatic based on Unicode properties
  • Text Combine Upright - Tate-chu-yoko for horizontal in vertical
Type-Safe Units
  • CSS Units Integration - Uses github.com/SCKelemen/units for all measurements
  • Length Types - Px, em, ch, rem, vw, vh, and more
  • Unit Conversion - Clean API boundaries with proper CSS value types

Installation

go get github.com/SCKelemen/text

Quick Start

Basic Operations
package main

import (
    "fmt"
    "github.com/SCKelemen/text"
)

func main() {
    // Create terminal text handler
    txt := text.NewTerminal()

    // Measure width (accounts for wide characters)
    width := txt.Width("Hello 世界")  // 9.0 (not 7!)

    // Truncate with ellipsis
    short := txt.Truncate("Very long text here", text.TruncateOptions{
        MaxWidth: 10,
        Strategy: text.TruncateEnd,
    })
    fmt.Println(short)  // "Very lo..."

    // Wrap text
    lines := txt.Wrap("Hello world! This is a test.", text.WrapOptions{
        MaxWidth: 15,
    })
    for _, line := range lines {
        fmt.Println(line.Content)
    }

    // Align text
    aligned := txt.Align("Hello", 20, text.AlignCenter)
    fmt.Printf("|%s|\n", aligned)  // "|       Hello        |"
}
CSS Text Module
package main

import (
    "fmt"
    "github.com/SCKelemen/text"
    "github.com/SCKelemen/units"
)

func main() {
    txt := text.NewTerminal()

    // White space processing
    processed, _ := txt.ProcessWhiteSpace("Hello    world\n\nFoo", text.WhiteSpaceNormal)
    fmt.Println(processed)  // "Hello world Foo"

    // Text transformation
    upper := txt.Transform("hello world", text.TextTransformUppercase)
    fmt.Println(upper)  // "HELLO WORLD"

    caps := txt.Transform("hello world", text.TextTransformCapitalize)
    fmt.Println(caps)  // "Hello World"

    // Word and sentence boundaries
    words := txt.Words("Hello, world! How are you?")
    fmt.Println(len(words))  // Includes punctuation and spaces

    wordCount := txt.WordCount("Hello world")  // 2
    sentenceCount := txt.SentenceCount("Hello. World.")  // 2

    // CSS-style wrapping with text properties
    lines := txt.WrapCSS("hello    world", text.CSSWrapOptions{
        MaxWidth: units.Ch(15),
        Style: text.CSSTextStyle{
            WhiteSpace:    text.WhiteSpaceNormal,  // Collapse spaces
            TextTransform: text.TextTransformUppercase,  // Convert to uppercase
            LetterSpacing: units.Px(0),
            WordSpacing:   units.Px(0),
        },
    })
    for _, line := range lines {
        fmt.Println(line.Content)  // "HELLO WORLD"
    }
}
Vertical Text Layout
package main

import (
    "fmt"
    "github.com/SCKelemen/text"
)

func main() {
    txt := text.NewTerminal()

    // Vertical text configuration
    style := text.VerticalTextStyle{
        WritingMode:     text.WritingModeVerticalRL,  // Right-to-left vertical
        TextOrientation: text.TextOrientationMixed,   // CJK upright, Latin rotated
    }

    // Measure vertical text
    metrics := txt.MeasureVertical("Hello世界", style)
    fmt.Printf("Advance: %.1f, InlineSize: %.1f\n", metrics.Advance, metrics.InlineSize)

    // Wrap vertical text into columns
    columns := txt.WrapVertical("Hello世界test", text.VerticalWrapOptions{
        MaxBlockSize: 5.0,  // Max column height
        Style:        style,
    })
    for i, col := range columns {
        fmt.Printf("Column %d: %s\n", i, col.Content)
    }
}

Why This Library?

Most Go text libraries get Unicode wrong:

len("世界") = 6 bytes, not 2 characters ❌ utf8.RuneCountInString("世界") = 2 runes, but 4 terminal cells wideutf8.RuneCountInString("👋🏻") = 2 runes, but 1 grapheme cluster

text.Width("世界") = 4.0 cells (correct!) ✅ text.GraphemeCount("👋🏻") = 1 (correct!)

This library gets it right by using proper Unicode algorithms.

Core Operations

Width Measurement

Correctly measures display width accounting for:

  • CJK ideographs (2 cells)
  • Emoji (2 cells)
  • Emoji modifiers (0 width)
  • Combining marks (0 width)
  • Ambiguous width characters (configurable)
txt := text.NewTerminal()

txt.Width("Hello")      // 5.0
txt.Width("世界")        // 4.0 (2 + 2)
txt.Width("😀")         // 2.0
txt.Width("👋🏻")        // 2.0 (emoji + modifier)
txt.Width("é")          // 1.0 (e + combining accent)
Text Wrapping

Smart wrapping using UAX #14 line breaking algorithm:

txt := text.NewTerminal()

lines := txt.Wrap("Hello 世界! This is a test.", text.WrapOptions{
    MaxWidth: 15,
})

for _, line := range lines {
    fmt.Printf("%.1f: %s\n", line.Width, line.Content)
}
// Output:
// 12.0: Hello 世界!
// 15.0: This is a test.
Truncation with Ellipsis

Three truncation strategies, all grapheme-aware:

txt := text.NewTerminal()

// Truncate at end
txt.Truncate("Hello world", text.TruncateOptions{
    MaxWidth: 10,
    Strategy: text.TruncateEnd,
})
// Output: "Hello w..."

// Truncate in middle
txt.Truncate("Hello world", text.TruncateOptions{
    MaxWidth: 10,
    Strategy: text.TruncateMiddle,
})
// Output: "Hel...rld"

// Truncate at start
txt.Truncate("Hello world", text.TruncateOptions{
    MaxWidth: 10,
    Strategy: text.TruncateStart,
})
// Output: "...o world"
Text Alignment
txt := text.NewTerminal()

txt.Align("Hello", 20, text.AlignLeft)      // "Hello               "
txt.Align("Hello", 20, text.AlignRight)     // "               Hello"
txt.Align("Hello", 20, text.AlignCenter)    // "       Hello        "
txt.Align("Hello world", 20, text.AlignJustify)  // Distributes padding
Grapheme Cluster Operations

Properly handles user-perceived characters:

txt := text.NewTerminal()

// Emoji with skin tone modifier = 1 grapheme
graphemes := txt.Graphemes("👋🏻")
fmt.Println(len(graphemes))  // 1

// Family emoji with ZWJ = 1 grapheme
graphemes = txt.Graphemes("👨‍👩‍👧‍👦")
fmt.Println(len(graphemes))  // 1

// Combining mark = 1 grapheme
graphemes = txt.Graphemes("é")  // e + ́
fmt.Println(len(graphemes))  // 1
Bidirectional Text

Supports Arabic, Hebrew mixed with Latin:

txt := text.NewTerminal()

// Properly reorders mixed LTR/RTL text
display := txt.Reorder("Hello שלום world")

// Auto-detect direction
dir := txt.DetectDirection("שלום עולם")  // DirectionRTL

Configuration

The library is renderer-agnostic through the MeasureFunc:

Terminal (Cell-Based)
txt := text.NewTerminal()
// Or explicit configuration:
txt := text.New(text.Config{
    MeasureFunc: text.TerminalMeasure,
    AmbiguousAsWide: false,  // For non-East Asian terminals
})
East Asian Terminals
txt := text.NewTerminalEastAsian()
// Treats ambiguous characters as wide (2 cells)
Custom (e.g., Canvas/Pixels)
txt := text.New(text.Config{
    MeasureFunc: func(r rune) float64 {
        return fontFace.GlyphAdvance(r)
    },
})

Integration with Layout Engines

Implements the layout.TextMetricsProvider interface:

package main

import (
    "github.com/SCKelemen/layout"
    "github.com/SCKelemen/text"
)

func main() {
    // Create metrics provider
    metrics := text.NewTerminalMetrics()

    // Inject into layout engine
    layout.SetTextMetricsProvider(metrics)

    // Now your layout engine uses proper Unicode text measurement!
    root := layout.NewNode().
        WithWidth(layout.Value{Value: 80, Unit: layout.UnitCh}).
        SetText("Hello 世界! Unicode is handled correctly.")

    root.Layout(layout.Constraint{MaxWidth: 80})
}

Unicode & CSS Standards

This library implements multiple Unicode and CSS specifications:

Unicode Standards
  • UAX #11 (East Asian Width) - Character width classification
  • UAX #14 (Line Breaking) - Line break opportunities and hyphenation
  • UAX #29 (Text Segmentation) - Grapheme cluster, word, and sentence boundaries
  • UAX #50 (Vertical Text Layout) - Character orientation in vertical text
  • UAX #9 (Bidirectional) - RTL text reordering
  • UTS #51 (Emoji) - Emoji properties and width

All Unicode implementations provided by github.com/SCKelemen/unicode.

CSS Standards
  • CSS Text Module Level 3 - White space, text transformation, word breaking
  • CSS Text Module Level 4 - Advanced text layout features
  • CSS Writing Modes Level 4 - Vertical text, writing direction, text orientation
  • CSS Values and Units Level 4 - Type-safe length and unit types

CSS unit types provided by github.com/SCKelemen/units.

Use Cases

Terminal UI Libraries
// Table cell truncation
func renderCell(content string, width int) {
    txt := text.NewTerminal()
    display := txt.Truncate(content, text.TruncateOptions{
        MaxWidth: float64(width),
        Strategy: text.TruncateEnd,
    })
    fmt.Print(display)
}
Progress Bars
// Fit status message in terminal width
func updateStatus(message string, termWidth int) {
    txt := text.NewTerminal()
    display := txt.Truncate(message, text.TruncateOptions{
        MaxWidth: float64(termWidth - 10),
        Strategy: text.TruncateEnd,
    })
    fmt.Printf("\r%s", display)
}
Text Editors
// Cursor movement by grapheme clusters
func moveCursorRight(text string, pos int) int {
    txt := text.NewTerminal()
    graphemes := txt.Graphemes(text)
    if pos < len(graphemes)-1 {
        return pos + 1
    }
    return pos
}
Log Formatting
// Truncate long log lines
func formatLog(message string, maxWidth int) string {
    txt := text.NewTerminal()
    return txt.Truncate(message, text.TruncateOptions{
        MaxWidth: float64(maxWidth),
        Strategy: text.TruncateEnd,
    })
}

API Reference

See GoDoc for complete API documentation.

Main Types
  • Text - Main text operations handler
  • Config - Configuration for text measurement
  • MeasureFunc - Function to measure rune width
  • Line - Wrapped line of text
  • Metrics - Layout engine integration
Functions

Measurement:

  • Width(s string) float64
  • WidthRange(s string, start, end int) float64

Wrapping:

  • Wrap(text string, opts WrapOptions) []Line

Truncation:

  • Truncate(text string, opts TruncateOptions) string

Alignment:

  • Align(text string, width float64, align Alignment) string

Bidirectional:

  • Reorder(text string) string
  • DetectDirection(text string) Direction

Graphemes:

  • Graphemes(text string) []string
  • GraphemeCount(text string) int
  • GraphemeAt(text string, index int) string

Performance

The library is designed for practical performance:

  • Width calculation: O(n) where n is number of runes
  • Wrapping: O(n × log m) where m is number of break opportunities
  • Truncation: O(n)
  • All operations use efficient binary search for Unicode lookups

Benchmarks on a modern CPU:

BenchmarkWidth-10        1000000    1043 ns/op
BenchmarkTruncate-10      500000    2891 ns/op
BenchmarkWrap-10          200000    7234 ns/op

License

BearWare 1.0 (MIT Compatible)

Documentation

Overview

Package text provides Unicode-aware text measurement, wrapping, truncation, and alignment operations for terminal UIs and text layout engines.

This package coordinates multiple Unicode standards (UAX #11, #14, #29, #9, UTS #51) to provide practical text operations that are correct for CJK characters, emoji, combining marks, and bidirectional text.

Based on:

Units

All width measurements (MaxWidth, Width, Line.Width) are in "abstract units" determined by the MeasureFunc configuration:

  • For terminals: character cells (1.0 per ASCII, 2.0 per CJK)
  • For canvas: pixels (varies by font)

The package doesn't care about the unit semantics - it just accumulates whatever your MeasureFunc returns.

Quick Start

import "github.com/SCKelemen/text"

// Create terminal text handler
txt := text.NewTerminal()

// Measure width (accounts for wide characters, emoji)
width := txt.Width("Hello 世界")  // 9.0 cells

// Wrap text to fit width
lines := txt.Wrap("Long text here...", text.WrapOptions{
    MaxWidth: 40,  // 40 character cells
})

// Truncate with ellipsis
short := txt.Truncate("Very long text", text.TruncateOptions{
    MaxWidth: 10,  // 10 character cells
    Strategy: text.TruncateEnd,
})

// Align text
aligned := txt.Align("Hello", 20, text.AlignCenter)  // 20 cells total

Configuration

The package is renderer-agnostic through the MeasureFunc configuration:

// Terminal: measure in cells
txt := text.New(text.Config{
    MeasureFunc: text.TerminalMeasure,
})

// Canvas: measure in pixels (future)
txt := text.New(text.Config{
    MeasureFunc: func(r rune) float64 {
        return fontFace.GlyphAdvance(r)
    },
})

Index

Constants

View Source
const (
	// Strong types
	ClassL  = uax9.ClassL  // Left-to-Right
	ClassR  = uax9.ClassR  // Right-to-Left
	ClassAL = uax9.ClassAL // Right-to-Left Arabic

	// Weak types
	ClassEN  = uax9.ClassEN  // European Number
	ClassES  = uax9.ClassES  // European Number Separator
	ClassET  = uax9.ClassET  // European Number Terminator
	ClassAN  = uax9.ClassAN  // Arabic Number
	ClassCS  = uax9.ClassCS  // Common Number Separator
	ClassNSM = uax9.ClassNSM // Nonspacing Mark
	ClassBN  = uax9.ClassBN  // Boundary Neutral

	// Neutral types
	ClassB  = uax9.ClassB  // Paragraph Separator
	ClassS  = uax9.ClassS  // Segment Separator
	ClassWS = uax9.ClassWS // Whitespace
	ClassON = uax9.ClassON // Other Neutrals

	// Explicit formatting types
	ClassLRE = uax9.ClassLRE // Left-to-Right Embedding
	ClassLRO = uax9.ClassLRO // Left-to-Right Override
	ClassRLE = uax9.ClassRLE // Right-to-Left Embedding
	ClassRLO = uax9.ClassRLO // Right-to-Left Override
	ClassPDF = uax9.ClassPDF // Pop Directional Format
	ClassLRI = uax9.ClassLRI // Left-to-Right Isolate
	ClassRLI = uax9.ClassRLI // Right-to-Left Isolate
	ClassFSI = uax9.ClassFSI // First Strong Isolate
	ClassPDI = uax9.ClassPDI // Pop Directional Isolate
)

Bidirectional character classes (re-exported from uax9)

Variables

This section is empty.

Functions

func IsCJKIdeograph

func IsCJKIdeograph(r rune) bool

IsCJKIdeograph returns true if the rune is a CJK ideograph.

func IsClosingFullwidthPunctuation

func IsClosingFullwidthPunctuation(r rune) bool

IsClosingFullwidthPunctuation returns true if the rune is closing fullwidth punctuation.

func IsClosingPunctuation

func IsClosingPunctuation(r rune) bool

IsClosingPunctuation returns true if the rune is closing punctuation.

func IsFullwidthPunctuation

func IsFullwidthPunctuation(r rune) bool

IsFullwidthPunctuation returns true if the rune is fullwidth punctuation.

func IsHorizontalWritingMode

func IsHorizontalWritingMode(mode WritingMode) bool

IsHorizontalWritingMode returns true if the writing mode is horizontal.

func IsIdeographic

func IsIdeographic(r rune) bool

IsIdeographic returns true if the rune is an ideographic character. Includes CJK ideographs, Hiragana, Katakana, and Hangul.

func IsOpeningFullwidthPunctuation

func IsOpeningFullwidthPunctuation(r rune) bool

IsOpeningFullwidthPunctuation returns true if the rune is opening fullwidth punctuation.

func IsOpeningPunctuation

func IsOpeningPunctuation(r rune) bool

IsOpeningPunctuation returns true if the rune is opening punctuation.

func IsStopPunctuation

func IsStopPunctuation(r rune) bool

IsStopPunctuation returns true if the rune is a stop/comma.

func IsVerticalWritingMode

func IsVerticalWritingMode(mode WritingMode) bool

IsVerticalWritingMode returns true if the writing mode is vertical.

func TerminalMeasure

func TerminalMeasure(r rune) float64

TerminalMeasure measures characters in terminal cells.

Returns:

  • 2 for wide characters (CJK ideographs, fullwidth, emoji)
  • 1 for narrow characters (ASCII, halfwidth)
  • 0 for zero-width characters (combining marks, ZWJ, variation selectors, emoji modifiers)

Uses UAX #11 with ContextNarrow (ambiguous characters treated as narrow). UTS #51 takes precedence for emoji characters.

func TerminalMeasureEastAsian

func TerminalMeasureEastAsian(r rune) float64

TerminalMeasureEastAsian measures characters in terminal cells with East Asian context.

Same as TerminalMeasure but treats ambiguous characters as wide (2 cells). Use this for terminals with East Asian locales (Chinese, Japanese, Korean).

Types

type Alignment

type Alignment int

Alignment specifies text alignment.

Specification:

const (
	// AlignLeft aligns text to the left (physical direction).
	AlignLeft Alignment = iota

	// AlignCenter centers text.
	AlignCenter

	// AlignRight aligns text to the right (physical direction).
	AlignRight

	// AlignJustify distributes padding between words.
	AlignJustify

	// AlignStart aligns text to the start edge (flow-relative).
	// Left in LTR, right in RTL.
	AlignStart

	// AlignEnd aligns text to the end edge (flow-relative).
	// Right in LTR, left in RTL.
	AlignEnd

	// AlignMatchParent inherits parent's alignment, computed for direction.
	AlignMatchParent
)

type AutospaceFlags

type AutospaceFlags int

AutospaceFlags specifies which autospace features to apply.

const (
	// AutospaceNone disables all autospace features.
	AutospaceNone AutospaceFlags = 0

	// AutospaceIdeographAlpha adds spacing between ideographic and non-ideographic characters.
	AutospaceIdeographAlpha AutospaceFlags = 1 << 0

	// AutospaceIdeographNumeric adds spacing between ideographic and numeric characters.
	AutospaceIdeographNumeric AutospaceFlags = 1 << 1

	// AutospacePunctuation adjusts spacing around fullwidth punctuation.
	AutospacePunctuation AutospaceFlags = 1 << 2

	// AutospaceAll enables all autospace features.
	AutospaceAll = AutospaceIdeographAlpha | AutospaceIdeographNumeric | AutospacePunctuation
)

type BidiClass

type BidiClass = uax9.BidiClass

BidiClass represents the bidirectional character type.

type CSSTextBounds

type CSSTextBounds struct {
	TextBounds

	// CSS intrinsic sizes
	Intrinsic IntrinsicSize

	// Applied spacing
	LetterSpacing units.Length
	WordSpacing   units.Length
	TextIndent    TextIndent
}

CSSTextBounds extends TextBounds with CSS-specific measurements.

type CSSTextStyle

type CSSTextStyle struct {
	// White space handling
	WhiteSpace WhiteSpace

	// Text transformation
	TextTransform TextTransform

	// Word and line breaking
	WordBreak    WordBreak
	LineBreak    LineBreak
	OverflowWrap OverflowWrap
	Hyphens      Hyphens

	// Text overflow (CSS Overflow Module)
	// https://drafts.csswg.org/css-overflow/#text-overflow
	TextOverflow               TextOverflow // How to handle overflow (applies to both ends if TextOverflowEnd not set)
	TextOverflowEnd            TextOverflow // How to handle overflow at end (if different from start)
	TextOverflowClipString     string       // Custom string for clip mode
	TextOverflowEllipsisString string       // Custom ellipsis string (default: "...")

	// Spacing (using CSS length units)
	LetterSpacing units.Length // Additional spacing between characters
	WordSpacing   units.Length // Additional spacing between words

	// Indentation and alignment
	TextIndent    TextIndent // First line indentation (supports hanging, each-line)
	TextAlign     Alignment  // Horizontal alignment
	TextAlignLast Alignment  // Alignment of last line (justify becomes start)
	VerticalAlign Alignment  // Vertical alignment within line box
	Direction     Direction  // Text direction (LTR, RTL, Auto)

	// Hanging punctuation (CSS Text Level 3 §6)
	HangingPunctuation HangingPunctuation // Controls punctuation hanging outside line box

	// Text spacing trim (CSS Text Level 4)
	TextSpacingTrim TextSpacingTrim // Controls CJK spacing trimming
}

CSSTextStyle represents CSS text properties for text layout.

func DefaultCSSTextStyle

func DefaultCSSTextStyle() CSSTextStyle

DefaultCSSTextStyle returns a CSSTextStyle with default values matching CSS defaults.

type CSSWrapOptions

type CSSWrapOptions struct {
	MaxWidth units.Length
	Style    CSSTextStyle
}

CSSWrapOptions extends WrapOptions with CSS text properties.

type Config

type Config struct {
	// MeasureFunc measures the width of a single rune in abstract units.
	// For terminals: returns 1 or 2 (cells)
	// For canvas: returns pixel width from font metrics
	MeasureFunc MeasureFunc

	// AmbiguousAsWide determines UAX #11 context for ambiguous width characters.
	// Set to true for East Asian contexts (Chinese, Japanese, Korean).
	// Set to false (default) for non-East Asian contexts.
	AmbiguousAsWide bool

	// HyphenationMode specifies UAX #14 line breaking preferences.
	HyphenationMode uax14.Hyphens

	// BaseDirection specifies the default paragraph direction for UAX #9.
	BaseDirection uax9.Direction
}

Config configures text measurement and layout behavior.

type DictionaryProvider

type DictionaryProvider interface {
	// IsAbbreviation returns true if the word is a known abbreviation.
	// This is used to prevent sentence breaks after abbreviated words.
	//
	// Example: "Dr." -> true, "Mr." -> true, "hello" -> false
	IsAbbreviation(word string) bool

	// GetHyphenationPoints returns hyphenation points for a word.
	// Returns slice of byte indices where hyphenation is allowed.
	//
	// Example: "example" -> []int{2, 4} (ex-am-ple)
	GetHyphenationPoints(word string) []int

	// IsCompoundWord returns true if the word is a compound that shouldn't be broken.
	// Used for language-specific compound word handling.
	//
	// Example: "JavaScript" -> true
	IsCompoundWord(word string) bool
}

DictionaryProvider provides domain-specific dictionaries for text segmentation.

This allows extending UAX #29 sentence and word boundary detection with: - Common abbreviations (Dr., Mrs., Ph.D., etc.) - Language-specific rules - Domain-specific terminology - Hyphenation patterns

type Direction

type Direction int

Direction specifies text directionality (LTR or RTL).

Specification:

const (
	// DirectionLTR is left-to-right text direction (Latin, Cyrillic, etc).
	DirectionLTR Direction = iota

	// DirectionRTL is right-to-left text direction (Arabic, Hebrew, etc).
	DirectionRTL

	// DirectionAuto determines direction from content using Unicode bidi algorithm.
	DirectionAuto
)

type ElideContext

type ElideContext int

ElideContext represents different elision contexts.

const (
	// ElideContextGeneral is for general text (middle elision).
	ElideContextGeneral ElideContext = iota

	// ElideContextPath is for file paths (preserve filename).
	ElideContextPath

	// ElideContextURL is for URLs (preserve domain).
	ElideContextURL

	// ElideContextEmail is for email addresses (preserve domain).
	ElideContextEmail

	// ElideContextDescription is for descriptions (end elision).
	ElideContextDescription

	// ElideContextCode is for code identifiers (middle elision).
	ElideContextCode
)

type EmptyDictionary

type EmptyDictionary struct{}

EmptyDictionary provides no dictionary support (pure UAX #29).

func (*EmptyDictionary) GetHyphenationPoints

func (d *EmptyDictionary) GetHyphenationPoints(word string) []int

GetHyphenationPoints always returns nil.

func (*EmptyDictionary) IsAbbreviation

func (d *EmptyDictionary) IsAbbreviation(word string) bool

IsAbbreviation always returns false.

func (*EmptyDictionary) IsCompoundWord

func (d *EmptyDictionary) IsCompoundWord(word string) bool

IsCompoundWord always returns false.

type EnglishDictionary

type EnglishDictionary struct {
	// contains filtered or unexported fields
}

EnglishDictionary provides common English abbreviations and rules.

func NewEnglishDictionary

func NewEnglishDictionary() *EnglishDictionary

NewEnglishDictionary creates a dictionary with common English abbreviations.

func (*EnglishDictionary) AddAbbreviation

func (d *EnglishDictionary) AddAbbreviation(abbrev string)

AddAbbreviation adds a custom abbreviation to the dictionary.

func (*EnglishDictionary) AddAbbreviations

func (d *EnglishDictionary) AddAbbreviations(abbrevs []string)

AddAbbreviations adds multiple custom abbreviations.

func (*EnglishDictionary) GetHyphenationPoints

func (d *EnglishDictionary) GetHyphenationPoints(word string) []int

GetHyphenationPoints implements DictionaryProvider. Returns empty slice for now - hyphenation requires more complex rules.

Future enhancement: Implement Liang's TeX hyphenation algorithm with language-specific pattern dictionaries.

func (*EnglishDictionary) IsAbbreviation

func (d *EnglishDictionary) IsAbbreviation(word string) bool

IsAbbreviation implements DictionaryProvider.

func (*EnglishDictionary) IsCompoundWord

func (d *EnglishDictionary) IsCompoundWord(word string) bool

IsCompoundWord implements DictionaryProvider.

type EnglishDictionaryWithHyphenation

type EnglishDictionaryWithHyphenation struct {
	*EnglishDictionary
	// contains filtered or unexported fields
}

EnglishDictionaryWithHyphenation extends EnglishDictionary with hyphenation.

func NewEnglishDictionaryWithHyphenation

func NewEnglishDictionaryWithHyphenation() *EnglishDictionaryWithHyphenation

NewEnglishDictionaryWithHyphenation creates a full-featured English dictionary.

func (*EnglishDictionaryWithHyphenation) GetHyphenationPoints

func (d *EnglishDictionaryWithHyphenation) GetHyphenationPoints(word string) []int

GetHyphenationPoints implements DictionaryProvider with actual hyphenation.

type FontMetrics

type FontMetrics interface {
	// Ascent returns the distance from baseline to top of tallest glyph.
	Ascent() float64

	// Descent returns the distance from baseline to bottom of lowest glyph.
	Descent() float64

	// LineGap returns the recommended line spacing (leading).
	LineGap() float64

	// CapHeight returns the height of capital letters.
	CapHeight() float64

	// XHeight returns the height of lowercase 'x'.
	XHeight() float64

	// UnitsPerEm returns the font's units per em.
	UnitsPerEm() float64
}

FontMetrics provides actual font measurements.

This interface allows integration with font rendering libraries that can provide real font metrics (not just approximations).

For future integration with: - freetype-go - golang.org/x/image/font - harfbuzz bindings

type HangingPunctuation

type HangingPunctuation int

HangingPunctuation controls whether punctuation can hang outside the line box.

Specification:

const (
	// HangingPunctuationNone disables hanging punctuation.
	HangingPunctuationNone HangingPunctuation = 0

	// HangingPunctuationFirst allows opening brackets/quotes to hang at start.
	HangingPunctuationFirst HangingPunctuation = 1 << 0

	// HangingPunctuationLast allows closing brackets/quotes to hang at end.
	HangingPunctuationLast HangingPunctuation = 1 << 1

	// HangingPunctuationForceEnd allows stops/commas to hang at end if needed.
	HangingPunctuationForceEnd HangingPunctuation = 1 << 2

	// HangingPunctuationAllowEnd allows stops/commas to hang at end if they don't fit.
	HangingPunctuationAllowEnd HangingPunctuation = 1 << 3
)

type HyphenationDictionary

type HyphenationDictionary struct {
	// contains filtered or unexported fields
}

HyphenationDictionary provides hyphenation patterns for a language.

Users can create custom dictionaries by loading patterns from TeX hyphen files: https://github.com/hyphenation/tex-hyphen

Example:

dict := text.NewHyphenationDictionary(myPatterns, 2, 3)
points := dict.Hyphenate("example")

func NewDanishHyphenation

func NewDanishHyphenation() *HyphenationDictionary

NewDanishHyphenation creates a hyphenation dictionary with Danish patterns.

func NewEnglishHyphenation

func NewEnglishHyphenation() *HyphenationDictionary

NewEnglishHyphenation creates a hyphenation dictionary with English (US) patterns.

Provides decent coverage for common English words. For comprehensive hyphenation, load full TeX patterns: https://github.com/hyphenation/tex-hyphen/tree/master/hyph-utf8/tex/generic/hyph-utf8/patterns/txt

func NewFrenchHyphenation

func NewFrenchHyphenation() *HyphenationDictionary

NewFrenchHyphenation creates a hyphenation dictionary with French patterns.

func NewGermanHyphenation

func NewGermanHyphenation() *HyphenationDictionary

NewGermanHyphenation creates a hyphenation dictionary with German patterns.

func NewHyphenationDictionary

func NewHyphenationDictionary(patterns map[string]string, minLeft, minRight int) *HyphenationDictionary

NewHyphenationDictionary creates a custom hyphenation dictionary.

Parameters:

  • patterns: Map of hyphenation patterns (see Liang's algorithm)
  • minLeft: Minimum characters required on left side of hyphen
  • minRight: Minimum characters required on right side of hyphen

Example:

patterns := map[string]string{
    "ex1am": "ex1am",     // Allow break after "ex"
    "ta1ble": "ta1ble",   // Allow break after "ta"
}
dict := text.NewHyphenationDictionary(patterns, 2, 3)

func NewNorwegianHyphenation

func NewNorwegianHyphenation() *HyphenationDictionary

NewNorwegianHyphenation creates a hyphenation dictionary with Norwegian patterns.

func NewSpanishHyphenation

func NewSpanishHyphenation() *HyphenationDictionary

NewSpanishHyphenation creates a hyphenation dictionary with Spanish patterns.

func NewSwedishHyphenation

func NewSwedishHyphenation() *HyphenationDictionary

NewSwedishHyphenation creates a hyphenation dictionary with Swedish patterns.

func (*HyphenationDictionary) Hyphenate

func (h *HyphenationDictionary) Hyphenate(word string) []int

Hyphenate returns hyphenation points for a word using Liang's algorithm.

Returns byte indices where hyphenation is allowed. Uses pattern matching with priority levels to determine break points.

Example:

dict := text.NewEnglishHyphenation()
points := dict.Hyphenate("example")
// Returns []int{2, 4} for ex-am-ple

func (*HyphenationDictionary) HyphenateWithString

func (h *HyphenationDictionary) HyphenateWithString(word, hyphen string) string

HyphenateWithString returns the hyphenated word with hyphens inserted.

Example:

dict := text.NewEnglishHyphenation()
result := dict.HyphenateWithString("example", "-")
// Returns "ex-am-ple"

type Hyphens

type Hyphens int

Hyphens controls hyphenation behavior.

Specification:

const (
	// HyphensNone disables all hyphenation.
	HyphensNone Hyphens = iota

	// HyphensManual only allows hyphenation at manually specified points (soft hyphens).
	HyphensManual

	// HyphensAuto allows automatic hyphenation using language-appropriate rules.
	HyphensAuto
)

type IntrinsicSize

type IntrinsicSize struct {
	// MinContent is the minimum width without overflow.
	// This is the width of the longest word/grapheme cluster.
	MinContent float64

	// MaxContent is the width if the text never wraps.
	// This is the total width of all text on a single line.
	MaxContent float64

	// PreferredWidth is a suggested width for comfortable reading.
	// For text, this is typically around 60-80 characters.
	PreferredWidth float64
}

IntrinsicSize represents the intrinsic dimensions of text.

Based on CSS Box Sizing Module Level 3: https://www.w3.org/TR/css-sizing-3/#intrinsic-sizes

type KnuthPlassOptions

type KnuthPlassOptions struct {
	// MaxWidth is the target line width
	MaxWidth float64

	// Tolerance controls how much stretch/shrink is acceptable
	// Higher values allow more variation in line lengths
	// Default: 1.0 (TeX uses 1.0)
	Tolerance float64

	// FitnessClass controls which fitness classes are compatible
	// Prevents mixing very tight and very loose lines adjacent to each other
	// Default: true
	FitnessClass bool

	// Hyphenate enables hyphenation for better line breaks
	// Default: false
	Hyphenate bool

	// HyphenPenalty is the penalty for breaking at a hyphen
	// Default: 50
	HyphenPenalty float64

	// LinePenalty is the penalty for each line (encourages fewer lines)
	// Default: 10
	LinePenalty float64
}

KnuthPlassOptions configures the Knuth-Plass line breaking algorithm.

func DefaultKnuthPlassOptions

func DefaultKnuthPlassOptions(maxWidth float64) KnuthPlassOptions

DefaultKnuthPlassOptions returns sensible defaults.

type Line

type Line struct {
	// Content is the text content of the line.
	Content string

	// Width is the display width of the line in abstract units.
	// For terminals: character cells
	// For canvas: pixels
	Width float64

	// Start is the rune index in the original text where this line starts.
	Start int

	// End is the rune index in the original text where this line ends.
	End int
}

Line represents a wrapped line of text.

type LineBoxMetrics

type LineBoxMetrics struct {
	// Content dimensions
	Width   float64 // Content width (advance)
	Content string  // Text content

	// Baseline and vertical metrics (in abstract units)
	Ascent  float64 // Distance above baseline
	Descent float64 // Distance below baseline
	Leading float64 // Extra space distributed above/below

	// Line box dimensions
	LineHeight float64 // Total line height (ascent + descent + leading)
	Baseline   float64 // Position of baseline from top

	// Position in source text
	Start int // Rune index in original text
	End   int // Rune index in original text
}

LineBoxMetrics provides complete metrics for a single line of text.

Based on CSS Inline Layout Module: https://www.w3.org/TR/css-inline-3/#line-box

type LineBreak

type LineBreak int

LineBreak controls line breaking strictness for CJK text.

Specification:

const (
	// LineBreakAuto uses the default line breaking rule.
	LineBreakAuto LineBreak = iota

	// LineBreakLoose uses the least restrictive line break rule.
	// Allows breaks at more positions.
	LineBreakLoose

	// LineBreakNormal uses the common line break rule.
	LineBreakNormal

	// LineBreakStrict uses the most restrictive line break rule.
	// Follows traditional typography rules strictly.
	LineBreakStrict

	// LineBreakAnywhere allows breaks at any character, even within words.
	LineBreakAnywhere
)

type MeasureFunc

type MeasureFunc func(r rune) float64

MeasureFunc measures the width of a single rune in abstract units.

For terminal rendering, it should return 1 or 2 (character cells). For pixel-based rendering, it should return the actual pixel width.

type Metrics

type Metrics struct {
	// contains filtered or unexported fields
}

Metrics implements layout.TextMetricsProvider for integration with the layout engine.

Example:

// Create metrics for terminal rendering
metrics := text.NewMetrics(text.Config{
    MeasureFunc: text.TerminalMeasure,
})

// In your layout engine setup:
layout.SetTextMetricsProvider(metrics)

func NewMetrics

func NewMetrics(config Config) *Metrics

NewMetrics creates a layout-compatible metrics provider.

func NewTerminalMetrics

func NewTerminalMetrics() *Metrics

NewTerminalMetrics creates metrics configured for terminal rendering.

func (*Metrics) Measure

func (m *Metrics) Measure(text string, style TextStyle) (advance, ascent, descent float64)

Measure implements layout.TextMetricsProvider interface.

Returns:

  • advance: The display width of the text
  • ascent: The distance above the baseline (for line height calculation)
  • descent: The distance below the baseline (for line height calculation)

For terminal rendering:

  • advance is measured in character cells
  • ascent/descent are proportional to line height for proper spacing

func (*Metrics) Text

func (m *Metrics) Text() *Text

Text returns the underlying Text instance for direct access to text operations.

This allows using all text.Text methods (Wrap, Truncate, Align, etc.) alongside the metrics provider.

Example:

metrics := text.NewTerminalMetrics()
layout.SetTextMetricsProvider(metrics)

// Also use for direct text operations
txt := metrics.Text()
truncated := txt.Truncate("Long text...", text.TruncateOptions{
    MaxWidth: 40,
})

type OverflowWrap

type OverflowWrap int

OverflowWrap controls whether to break within words to prevent overflow.

Specification:

const (
	// OverflowWrapNormal breaks only at allowed break points.
	OverflowWrapNormal OverflowWrap = iota

	// OverflowWrapBreakWord breaks within words if necessary to prevent overflow.
	OverflowWrapBreakWord

	// OverflowWrapAnywhere breaks at any point if necessary.
	OverflowWrapAnywhere
)

type PhraseBreaker

type PhraseBreaker interface {
	// FindPhrases returns phrase boundary positions (rune indices).
	// Positions should be sorted and include 0 as the first position.
	//
	// Example: "你好世界" might return [0, 2, 4] for "你好" and "世界"
	FindPhrases(text string) []int
}

PhraseBreaker is an interface for language-specific phrase segmentation.

This enables word-break: auto-phrase for CJK languages by allowing users to provide their own dictionary/ML-based segmentation.

Specification:

Users should integrate external libraries for phrase breaking:

  • Chinese: jieba, pkuseg, HanLP
  • Japanese: MeCab, kuromoji, Sudachi
  • Korean: KoNLPy, Mecab-ko
  • Thai: ICU, libthai

Example:

type MyJiebaBreaker struct {
    segmenter *jieba.Segmenter
}

func (j *MyJiebaBreaker) FindPhrases(text string) []int {
    segments := j.segmenter.Cut(text, true)
    positions := []int{0}
    offset := 0
    for _, seg := range segments {
        offset += len([]rune(seg))
        positions = append(positions, offset)
    }
    return positions
}

breaker := &MyJiebaBreaker{segmenter: jieba.NewSegmenter()}
lines := txt.WrapWithPhrases("你好世界", 20, breaker)

type TabSize

type TabSize struct {
	// Value is the tab width
	Value float64

	// Unit determines if Value is spaces or a length
	Unit TabSizeUnit
}

TabSize controls the width of tab characters.

Specification:

func DefaultTabSize

func DefaultTabSize() TabSize

DefaultTabSize returns the default tab size (8 spaces).

type TabSizeUnit

type TabSizeUnit int

TabSizeUnit specifies how tab size is measured.

const (
	// TabSizeSpaces measures tabs in number of space characters.
	TabSizeSpaces TabSizeUnit = iota

	// TabSizeLength measures tabs in CSS length units.
	TabSizeLength
)

type Text

type Text struct {
	// contains filtered or unexported fields
}

Text provides high-level Unicode-aware text operations.

func New

func New(config Config) *Text

New creates a new Text instance with the given configuration.

func NewTerminal

func NewTerminal() *Text

NewTerminal creates a Text instance configured for terminal rendering.

Uses:

  • TerminalMeasure for width calculation (1 or 2 cells)
  • ContextNarrow for UAX #11 ambiguous characters
  • Manual hyphenation for UAX #14
  • LTR base direction for UAX #9

func NewTerminalEastAsian

func NewTerminalEastAsian() *Text

NewTerminalEastAsian creates a Text instance configured for East Asian terminals.

Same as NewTerminal but treats ambiguous characters as wide (2 cells).

func (*Text) Align

func (t *Text) Align(text string, width float64, align Alignment) string

Align pads text to a specific width with the specified alignment. For flow-relative alignment (start/end), assumes LTR direction. Use AlignWithDirection for RTL support.

The width parameter is in abstract units (cells for terminals, pixels for canvas).

Example:

txt := text.NewTerminal()
aligned := txt.Align("Hello", 20, text.AlignCenter)
fmt.Printf("|%s|", aligned)  // "|       Hello        |" (20 cells total)

func (*Text) AlignLines

func (t *Text) AlignLines(lines []Line, width float64, style CSSTextStyle) []Line

AlignLines aligns multiple lines according to CSS text-align and text-align-last properties.

Based on CSS Text Module Level 3: - text-align: https://www.w3.org/TR/css-text-3/#text-align-property - text-align-last: https://www.w3.org/TR/css-text-3/#text-align-last-property

Example:

lines := []Line{
    {Content: "First line", Width: 10},
    {Content: "Second line", Width: 11},
    {Content: "Last", Width: 4},
}
aligned := txt.AlignLines(lines, 20.0, text.CSSTextStyle{
    TextAlign:     text.AlignJustify,
    TextAlignLast: text.AlignLeft,
})

func (*Text) AlignWithDirection

func (t *Text) AlignWithDirection(text string, width float64, align Alignment, direction Direction, parentAlign Alignment) string

AlignWithDirection pads text to a specific width with the specified alignment, respecting text direction for flow-relative alignments (start/end/match-parent).

Parameters:

  • text: The text to align
  • width: The target width
  • align: The alignment mode
  • direction: Text direction (LTR, RTL, or Auto)
  • parentAlign: Parent's alignment (used for match-parent)

Example:

txt := text.NewTerminal()
// In RTL context, start means right
aligned := txt.AlignWithDirection("مرحبا", 20, text.AlignStart, text.DirectionRTL, text.AlignLeft)

func (*Text) ApplyAutospace

func (t *Text) ApplyAutospace(text string, flags AutospaceFlags) string

ApplyAutospace applies automatic spacing according to text-autospace rules.

Example:

txt := text.NewTerminal()
result := txt.ApplyAutospace("Hello世界123", text.AutospaceAll)
// Returns "Hello 世界 123" (with spacing between scripts)

func (*Text) ApplyAutospaceMode

func (t *Text) ApplyAutospaceMode(text string, mode TextAutospace) string

ApplyAutospaceMode applies text-autospace with predefined mode.

func (*Text) ApplyTextOverflow

func (t *Text) ApplyTextOverflow(text string, maxWidth float64, style CSSTextStyle) string

ApplyTextOverflow applies CSS text-overflow property to text that exceeds maxWidth.

Based on CSS Overflow Module Level 3 §3: https://drafts.csswg.org/css-overflow/#text-overflow

Example:

txt := text.NewTerminal()
result := txt.ApplyTextOverflow("Very long text here", 15, text.CSSTextStyle{
    TextOverflow: text.TextOverflowEllipsis,
    TextOverflowEllipsisString: "…",
})
// Returns: "Very long t…"

func (*Text) CharOrientation

func (t *Text) CharOrientation(r rune, orientation TextOrientation) uax50.Orientation

CharOrientation returns the orientation for a character in vertical text.

This implements the UAX #50 algorithm combined with CSS text-orientation property. For TextOrientationMixed, it respects UAX #50 defaults. For TextOrientationUpright, all characters are upright. For TextOrientationSideways, all characters are rotated.

func (*Text) DetectDirection

func (t *Text) DetectDirection(text string) uax9.Direction

DetectDirection automatically detects paragraph direction.

func (*Text) Elide

func (t *Text) Elide(text string, maxWidth float64) string

Elide shortens text by removing the middle portion if it exceeds maxWidth.

This is a convenience function that uses TruncateMiddle strategy. Common for displaying file paths, URLs, and identifiers.

Example:

txt := text.NewTerminal()
short := txt.Elide("/very/long/path/to/some/file.txt", 20)
// Returns: "/very/.../file.txt"

func (*Text) ElideAuto

func (t *Text) ElideAuto(text string, maxWidth float64) string

ElideAuto automatically chooses the best elision strategy based on content.

Detects if text looks like a path, URL, email, etc. and applies the most appropriate elision strategy.

Example:

txt := text.NewTerminal()
txt.ElideAuto("/path/to/file.txt", 15)          // Uses path elision
txt.ElideAuto("https://example.com/path", 20)  // Uses URL elision
txt.ElideAuto("user@domain.com", 15)           // Uses email elision

func (*Text) ElideEnd

func (t *Text) ElideEnd(text string, maxWidth float64) string

ElideEnd shortens text by truncating at the end.

Common for displaying snippets, descriptions, and body text.

Example:

txt := text.NewTerminal()
short := txt.ElideEnd("This is a very long description", 20)
// Returns: "This is a very lo..."

func (*Text) ElideEndUnicode

func (t *Text) ElideEndUnicode(text string, maxWidth float64) string

ElideEndUnicode truncates at end with Unicode ellipsis (…).

func (*Text) ElideEndWith

func (t *Text) ElideEndWith(text string, maxWidth float64, ellipsis string) string

ElideEndWith shortens text at the end with custom ellipsis.

func (*Text) ElideForContext

func (t *Text) ElideForContext(text string, maxWidth float64, context ElideContext) string

ElideForContext elides text using strategy appropriate for the context.

func (*Text) ElidePath

func (t *Text) ElidePath(path string, maxWidth float64) string

ElidePath intelligently shortens file paths.

Preserves the filename and important directory information. Uses middle truncation but tries to break at path separators.

Example:

txt := text.NewTerminal()
short := txt.ElidePath("/usr/local/share/applications/myapp.desktop", 30)
// Returns: "/usr/.../applications/myapp.desktop"

func (*Text) ElideStart

func (t *Text) ElideStart(text string, maxWidth float64) string

ElideStart shortens text by truncating at the start.

Common for displaying file paths where the end is most important.

Example:

txt := text.NewTerminal()
short := txt.ElideStart("/path/to/myfile.txt", 15)
// Returns: "...myfile.txt"

func (*Text) ElideStartUnicode

func (t *Text) ElideStartUnicode(text string, maxWidth float64) string

ElideStartUnicode truncates at start with Unicode ellipsis (…).

func (*Text) ElideStartWith

func (t *Text) ElideStartWith(text string, maxWidth float64, ellipsis string) string

ElideStartWith shortens text at the start with custom ellipsis.

func (*Text) ElideURL

func (t *Text) ElideURL(url string, maxWidth float64) string

ElideURL intelligently shortens URLs.

Preserves the domain and important parts of the path.

Example:

txt := text.NewTerminal()
short := txt.ElideURL("https://example.com/very/long/path/to/resource", 35)
// Returns: "https://example.com/.../resource"

func (*Text) ElideUnicode

func (t *Text) ElideUnicode(text string, maxWidth float64) string

ElideUnicode uses the proper Unicode horizontal ellipsis character (…).

This is more typographically correct than three dots (...).

Example:

txt := text.NewTerminal()
short := txt.ElideUnicode("Long text here", 10)
// Returns: "Long t…re" (using U+2026)

func (*Text) ElideWith

func (t *Text) ElideWith(text string, maxWidth float64, ellipsis string) string

ElideWith shortens text using a custom ellipsis string.

Useful for different UI contexts or localization.

Example:

txt := text.NewTerminal()
short := txt.ElideWith("Long text", 10, "…")     // Single character ellipsis
short = txt.ElideWith("Long text", 10, " [...] ") // Bracketed ellipsis

func (*Text) ExpandTabs

func (t *Text) ExpandTabs(text string, tabSize TabSize) string

ExpandTabs expands tab characters according to tab-size.

func (*Text) GetBidiClass

func (t *Text) GetBidiClass(r rune) BidiClass

GetBidiClass returns the bidirectional character type for a rune.

This is useful for understanding how a character behaves in bidirectional text or for implementing custom bidirectional algorithms.

Example:

txt := text.NewTerminal()

class := txt.GetBidiClass('a')      // ClassL (Left-to-Right)
class := txt.GetBidiClass('א')      // ClassR (Right-to-Left Hebrew)
class := txt.GetBidiClass('ا')      // ClassAL (Right-to-Left Arabic)
class := txt.GetBidiClass('5')      // ClassEN (European Number)

func (*Text) GraphemeAt

func (t *Text) GraphemeAt(text string, index int) string

GraphemeAt returns the grapheme cluster at the specified index.

func (*Text) GraphemeCount

func (t *Text) GraphemeCount(text string) int

GraphemeCount returns the number of grapheme clusters.

func (*Text) Graphemes

func (t *Text) Graphemes(text string) []string

Graphemes splits text into grapheme clusters (user-perceived characters).

Uses UAX #29 to properly handle:

  • Emoji sequences with ZWJ: 👨‍👩‍👧‍👦
  • Emoji with skin tones: 👋🏻
  • Combining marks: é (e + ́)
  • Regional indicators: 🇺🇸

Example:

txt := text.NewTerminal()
graphemes := txt.Graphemes("Hello👋🏻")
fmt.Println(len(graphemes))  // 6, not 7 (emoji+modifier is 1 grapheme)

func (*Text) IntrinsicSizing

func (t *Text) IntrinsicSizing(text string) IntrinsicSize

IntrinsicSizing calculates intrinsic sizes for text.

Returns:

  • MinContent: Width of the widest word/grapheme (won't overflow)
  • MaxContent: Width if text never wraps (single line)
  • PreferredWidth: Comfortable reading width (60-80 ch)

Example:

txt := text.NewTerminal()
sizes := txt.IntrinsicSizing("Hello world! This is a test.")
// sizes.MinContent = 6.0 (widest word "Hello!" or "world!")
// sizes.MaxContent = 28.0 (full line width)

func (*Text) IsRotated

func (t *Text) IsRotated(r rune, style VerticalTextStyle) bool

IsRotated returns true if the character should be rotated in vertical text.

func (*Text) IsUpright

func (t *Text) IsUpright(r rune, style VerticalTextStyle) bool

IsUpright returns true if the character should be displayed upright in vertical text.

func (*Text) JustifyText

func (t *Text) JustifyText(text string, targetWidth float64, method TextJustify) string

JustifyText applies justification to text to fit a specific width.

Uses the specified justification method to distribute extra space.

Example:

txt := text.NewTerminal()
justified := txt.JustifyText("Hello world", 20, text.TextJustifyInterWord)

func (*Text) LineContainingPosition

func (t *Text) LineContainingPosition(lines []Line, position int) int

LineContainingPosition finds which line contains the given text position.

Returns:

  • Line index if position is within a line
  • -1 if position is before all lines
  • len(lines) if position is after all lines

Example:

txt := text.NewTerminal()
lines := []text.Line{
    {Start: 0, End: 5},
    {Start: 5, End: 10},
}
lineIdx := txt.LineContainingPosition(lines, 7) // Returns 1

func (*Text) MeasureCSS

func (t *Text) MeasureCSS(text string, cssOpts CSSWrapOptions, textStyle TextStyle) CSSTextBounds

MeasureCSS calculates complete bounds with CSS text properties.

This combines: - Multi-line wrapping with CSS white-space - Intrinsic sizing for layout - Text transformation - Letter/word spacing

Example:

txt := text.NewTerminal()
bounds := txt.MeasureCSS("hello world", text.CSSWrapOptions{
    MaxWidth: units.Ch(40),
    Style: text.CSSTextStyle{
        WhiteSpace: text.WhiteSpaceNormal,
        TextTransform: text.TextTransformUppercase,
        LetterSpacing: units.Px(1),
    },
}, text.TextStyle{
    LineHeight: 1.5,
})

func (*Text) MeasureLineBox

func (t *Text) MeasureLineBox(text string, style TextStyle) LineBoxMetrics

MeasureLineBox calculates complete metrics for a line of text.

Parameters:

  • text: The line content
  • style: Font and line height settings

Returns metrics needed for proper line box positioning and alignment.

func (*Text) MeasureMultiLine

func (t *Text) MeasureMultiLine(text string, wrapOpts WrapOptions, style TextStyle) TextBounds

MeasureMultiLine calculates bounds for wrapped text.

This is essential for layout engines that need to know: - Total height of text block - Baseline positions for alignment - Per-line metrics for rendering

Example:

txt := text.NewTerminal()
bounds := txt.MeasureMultiLine("Long text...", text.WrapOptions{
    MaxWidth: 40,
}, text.TextStyle{
    LineHeight: 1.5,
})
// bounds.Height = total height with line spacing
// bounds.FirstBaseline = for vertical-align: baseline

func (*Text) MeasureVertical

func (t *Text) MeasureVertical(text string, style VerticalTextStyle) VerticalMetrics

MeasureVertical measures text dimensions for vertical layout.

In vertical layout:

  • Advance is the vertical distance (top to bottom or bottom to top)
  • InlineSize is the width (perpendicular to flow)
  • BlockSize is the height (parallel to flow)

func (*Text) MirrorBrackets

func (t *Text) MirrorBrackets(text string) string

MirrorBrackets mirrors brackets for RTL display.

In RTL text, opening brackets like '(' should become ')' and vice versa. This function is typically called automatically by the reordering algorithm, but is exposed for cases where manual bracket handling is needed.

Note: The UAX #9 algorithm handles this automatically in most cases. This function is provided for special situations or debugging.

Example:

txt := text.NewTerminal()

result := txt.MirrorBrackets("(hello)")
// result: ")hello(" (brackets mirrored)

func (*Text) PositionToXOffset

func (t *Text) PositionToXOffset(line Line, position int) float64

PositionToXOffset finds the x-offset of a text position within a line.

This converts a character position to its visual offset from the start of the line. Returns 0 if position is before the line, line.Width if after.

Example:

txt := text.NewTerminal()
line := text.Line{Content: "Hello", Start: 0, End: 5}
offset := txt.PositionToXOffset(line, 2) // Returns 2.0 (position of 'l')

func (*Text) ProcessWhiteSpace

func (t *Text) ProcessWhiteSpace(text string, whiteSpace WhiteSpace) (processed string, allowWrap bool)

ProcessWhiteSpace processes text according to CSS white-space property. Returns the processed text and whether line wrapping is allowed.

func (*Text) Reorder

func (t *Text) Reorder(text string) string

Reorder applies the bidirectional algorithm for display.

Uses UAX #9 to properly reorder mixed LTR/RTL text (e.g., Latin + Arabic).

Example:

txt := text.NewTerminal()
display := txt.Reorder("Hello שלום world")
fmt.Println(display)  // Properly reordered for display

func (*Text) ReorderLine

func (t *Text) ReorderLine(text string, direction Direction) string

ReorderLine reorders a single line after wrapping.

This is used internally by wrapping functions to ensure each wrapped line is properly reordered for display. Layout engines should call this after computing line breaks.

Example:

txt := text.NewTerminal()

line := text.Line{
    Content: "Hello مرحبا world",
    Width:   15.0,
    Start:   0,
    End:     17,
}

// Reorder the line content
line.Content = txt.ReorderLine(line.Content, text.DirectionAuto)

func (*Text) ReorderParagraph

func (t *Text) ReorderParagraph(text string, baseDirection Direction) string

ReorderParagraph reorders a paragraph, handling line breaks properly.

This function: 1. Splits text by line breaks 2. Detects direction for each paragraph 3. Reorders each line independently 4. Rejoins with line breaks

Example:

txt := text.NewTerminal()

input := "Hello world\nمرحبا العالم\nMixed text"
result := txt.ReorderParagraph(input, text.DirectionAuto)
// Each line reordered according to its detected direction

func (*Text) ReorderWithDirection

func (t *Text) ReorderWithDirection(text string, dir uax9.Direction) string

ReorderWithDirection applies bidirectional algorithm with explicit direction.

func (*Text) SentenceCount

func (t *Text) SentenceCount(text string) int

SentenceCount returns the number of sentences in the text.

func (*Text) SentenceCountWithDictionary

func (t *Text) SentenceCountWithDictionary(text string, dict DictionaryProvider) int

SentenceCountWithDictionary returns the number of sentences using dictionary support.

func (*Text) Sentences

func (t *Text) Sentences(text string) []string

Sentences splits text into sentences using UAX #29 sentence boundaries.

func (*Text) SentencesWithDictionary

func (t *Text) SentencesWithDictionary(text string, dict DictionaryProvider) []string

SentencesWithDictionary splits text into sentences using dictionary support.

This provides more accurate sentence boundary detection by: - Not breaking after known abbreviations (Dr., Mrs., etc.) - Handling language-specific rules - Supporting domain-specific terminology

Example:

dict := text.NewEnglishDictionary()
sentences := txt.SentencesWithDictionary("Dr. Smith is here.", dict)
// Returns ["Dr. Smith is here."] instead of ["Dr. ", "Smith is here."]

func (*Text) ShouldHang

func (t *Text) ShouldHang(text string, position int, mode HangingPunctuation) (shouldHang bool, hangWidth float64)

ShouldHang determines if punctuation should hang outside the line box.

func (*Text) Transform

func (t *Text) Transform(text string, transform TextTransform) string

Transform applies text transformation according to CSS text-transform property.

func (*Text) TrimCJKSpacing

func (t *Text) TrimCJKSpacing(text string, mode TextSpacingTrim) string

TrimCJKSpacing trims spacing around CJK characters according to the trim mode.

func (*Text) Truncate

func (t *Text) Truncate(text string, opts TruncateOptions) string

Truncate shortens text to fit within maxWidth, adding an ellipsis.

Uses UAX #29 to respect grapheme cluster boundaries, ensuring emoji and combining marks are not broken.

Example:

txt := text.NewTerminal()
short := txt.Truncate("Hello 世界!", text.TruncateOptions{
    MaxWidth: 10,
    Strategy: text.TruncateEnd,
})
fmt.Println(short)  // "Hello 世..."

func (*Text) Width

func (t *Text) Width(s string) float64

Width measures the display width of text in abstract units.

Units are determined by the MeasureFunc configuration:

  • For terminals: character cells (1.0 per ASCII char, 2.0 per CJK char)
  • For canvas: pixels (12.5 per 'a', 24.3 per 'W', etc.)

This correctly handles:

  • CJK characters (2 cells/units wide)
  • Emoji (2 cells/units wide)
  • Emoji sequences (flags, ZWJ sequences, modifiers - all 2 cells wide)
  • Combining marks (0 width)
  • Zero-width joiners (0 width)

Example:

txt := text.NewTerminal()
width := txt.Width("Hello")     // 5.0 cells
width = txt.Width("Hello 世界")  // 9.0 cells (5 + 1 space + 2 + 2)
width = txt.Width("👋🏻")        // 2.0 cells (emoji + skin tone modifier)
width = txt.Width("🇺🇸")        // 2.0 cells (flag emoji)

func (*Text) WidthBytes

func (t *Text) WidthBytes(b []byte) float64

WidthBytes measures the display width of a UTF-8 byte buffer.

This is more efficient than Width(string(bytes)) as it avoids string allocation and conversion overhead for large buffers.

Example:

txt := text.NewTerminal()
buf := []byte("Hello 世界")
width := txt.WidthBytes(buf)  // 9.0 cells

func (*Text) WidthMany

func (t *Text) WidthMany(strings []string) []float64

WidthMany efficiently measures multiple strings in a batch.

This can be more efficient than calling Width() multiple times if the implementation can reuse internal state or optimize for batch operations.

Example:

txt := text.NewTerminal()
strings := []string{"Hello", "世界", "Test"}
widths := txt.WidthMany(strings)
// widths = [5.0, 4.0, 4.0]

func (*Text) WidthRange

func (t *Text) WidthRange(s string, start, end int) float64

WidthRange measures the display width of a substring by rune indices.

Example:

txt := text.NewTerminal()
text := "Hello 世界"
width := txt.WidthRange(text, 0, 5)  // 5.0 (just "Hello")
width = txt.WidthRange(text, 6, 8)   // 4.0 (just "世界")

func (*Text) WidthUpTo

func (t *Text) WidthUpTo(s string, maxWidth float64) (width float64, exceeded bool)

WidthUpTo measures display width up to a maximum, with early termination.

Returns the measured width and whether it exceeded the maximum. This is more efficient than Width() when you only care about fitting within a maximum width, as it stops measuring once the limit is reached.

Example:

txt := text.NewTerminal()
width, exceeded := txt.WidthUpTo("Very long text here", 10.0)
if exceeded {
    // Text is too wide, needs truncation
}

func (*Text) WithFontMetrics

func (t *Text) WithFontMetrics(fm FontMetrics) *Text

WithFontMetrics creates a Text instance with real font metrics.

When provided, font metrics override the default ascent/descent calculations. This enables proper support for font-relative units (em, ex, cap, ch, ic).

Future enhancement: Store and use font metrics in line box measurement for pixel-perfect canvas/GUI rendering with proper baseline alignment.

func (*Text) WordCount

func (t *Text) WordCount(text string) int

WordCount returns the number of words in the text.

func (*Text) Words

func (t *Text) Words(text string) []string

Words splits text into words using UAX #29 word boundaries. Returns a slice of word segments (includes spaces and punctuation).

func (*Text) Wrap

func (t *Text) Wrap(text string, opts WrapOptions) []Line

Wrap breaks text into lines that fit within maxWidth.

Uses UAX #14 for proper line break opportunities and UAX #29 to avoid breaking within grapheme clusters (emoji, combining marks, etc.).

Example:

txt := text.NewTerminal()
lines := txt.Wrap("Hello 世界! This is a test.", text.WrapOptions{
    MaxWidth: 15,
})
for _, line := range lines {
    fmt.Println(line.Content)
}
// Output:
// Hello 世界!
// This is a test.

func (*Text) WrapBalanced

func (t *Text) WrapBalanced(text string, maxWidth float64) []Line

WrapBalanced wraps text with balanced line lengths.

func (*Text) WrapCSS

func (t *Text) WrapCSS(text string, opts CSSWrapOptions) []Line

WrapCSS wraps text according to CSS text properties. This is a more sophisticated version of Wrap that handles white-space, word-break, line-break, and other CSS properties.

func (*Text) WrapKnuthPlass

func (t *Text) WrapKnuthPlass(text string, opts KnuthPlassOptions) []Line

WrapKnuthPlass wraps text using the Knuth-Plass optimal line breaking algorithm.

This produces better-looking paragraphs than greedy wrapping by considering all possible break points and choosing the set that minimizes total "badness".

Example:

txt := text.NewTerminal()
opts := text.DefaultKnuthPlassOptions(40.0)
lines := txt.WrapKnuthPlass("The quick brown fox jumps over the lazy dog", opts)

func (*Text) WrapPretty

func (t *Text) WrapPretty(text string, maxWidth float64) []Line

WrapPretty wraps text optimizing for readability.

func (*Text) WrapVertical

func (t *Text) WrapVertical(text string, opts VerticalWrapOptions) []VerticalLine

WrapVertical wraps text for vertical layout.

In vertical layout, "lines" are vertical columns that flow from top to bottom. When a column reaches MaxBlockSize, text wraps to the next column.

func (*Text) WrapWithControls

func (t *Text) WrapWithControls(text string, maxWidth float64, controls []WrapPoint) []Line

WrapWithControls wraps text respecting wrap-before/wrap-after controls.

This function modifies line break opportunities based on CSS wrap-before and wrap-after properties: - WrapControlAvoid: Avoids breaking at this position if possible - WrapControlAlways: Forces a break at this position - WrapControlAuto: Uses normal UAX #14 break opportunities

Example:

controls := []WrapPoint{
    {Position: 5, After: WrapControlAlways}, // Force break after position 5
    {Position: 10, Before: WrapControlAvoid}, // Avoid breaking before position 10
}
lines := txt.WrapWithControls("Hello world test", 20, controls)

func (*Text) WrapWithPhrases

func (t *Text) WrapWithPhrases(text string, maxWidth float64, breaker PhraseBreaker) []Line

WrapWithPhrases wraps text using phrase boundaries from a PhraseBreaker.

This implements CSS word-break: auto-phrase, which breaks at natural phrase boundaries in languages that don't use spaces between words.

The PhraseBreaker interface allows users to integrate language-specific dictionaries without requiring this library to ship with large dictionary files or ML models.

Example:

// User provides their own phrase breaker
breaker := &MyChineseBreaker{}
lines := txt.WrapWithPhrases("你好世界,这是一个测试。", 20, breaker)

func (*Text) WrapWithPhrasesAndControls

func (t *Text) WrapWithPhrasesAndControls(text string, maxWidth float64, breaker PhraseBreaker, controls []WrapPoint) []Line

WrapWithPhrasesAndControls combines phrase breaking with wrap controls.

This allows fine-grained control over phrase-based line breaking.

Example:

controls := []WrapPoint{
    {Position: 5, After: WrapControlAvoid}, // Don't break after phrase at position 5
}
lines := txt.WrapWithPhrasesAndControls(text, 20, breaker, controls)

func (*Text) XOffsetToPosition

func (t *Text) XOffsetToPosition(line Line, xOffset float64) XOffsetInfo

XOffsetToPosition finds the character position at the given x-offset within a line.

This is the core text operation for finding where a click or cursor should go within a line's content. The layout engine provides the x-offset within the line.

Example:

txt := text.NewTerminal()
line := text.Line{Content: "Hello", Width: 5.0, Start: 0, End: 5}
info := txt.XOffsetToPosition(line, 2.3)
// info.Position = 2 (character 'l')
// info.IsTrailing = false (left half of 'l')

type TextAutospace

type TextAutospace int

TextAutospace controls automatic spacing around ideographic characters.

Specification:

const (
	// TextAutospaceNormal creates extra spacing as specified.
	TextAutospaceNormal TextAutospace = iota

	// TextAutospaceNoAutospace disables automatic spacing.
	TextAutospaceNoAutospace

	// TextAutospaceAuto uses language-specific spacing rules.
	TextAutospaceAuto
)

type TextBounds

type TextBounds struct {
	// Total dimensions
	Width  float64 // Width of widest line
	Height float64 // Total height of all lines

	// Baseline information
	FirstBaseline float64 // Position of first line's baseline from top
	LastBaseline  float64 // Position of last line's baseline from top

	// Line information
	LineCount int              // Number of lines
	Lines     []LineBoxMetrics // Metrics for each line
}

TextBounds represents the bounding box of multi-line text.

type TextCombineUpright

type TextCombineUpright int

TextCombineUpright controls horizontal text runs in vertical layout. Based on CSS Writing Modes Module Level 4 §9: https://www.w3.org/TR/css-writing-modes-4/#text-combine-upright

const (
	// TextCombineUprightNone disables text combining.
	TextCombineUprightNone TextCombineUpright = iota

	// TextCombineUprightAll enables combining for all characters.
	// Used for numbers, acronyms, etc. in vertical text (tate-chu-yoko in Japanese).
	TextCombineUprightAll

	// TextCombineUprightDigits enables combining for digit sequences only.
	TextCombineUprightDigits
)

type TextConfig

type TextConfig struct {
	*Text
	Dictionary DictionaryProvider
}

TextConfig extends Text with dictionary support.

func NewTerminalWithEnglishDictionary

func NewTerminalWithEnglishDictionary() *TextConfig

NewTerminalWithEnglishDictionary creates a terminal text handler with English dictionary.

func NewTextWithDictionary

func NewTextWithDictionary(config Config, dict DictionaryProvider) *TextConfig

NewTextWithDictionary creates a Text instance with dictionary support.

func (*TextConfig) SentenceCount

func (tc *TextConfig) SentenceCount(text string) int

SentenceCount returns sentence count using the configured dictionary.

func (*TextConfig) Sentences

func (tc *TextConfig) Sentences(text string) []string

Sentences uses the configured dictionary for sentence segmentation.

type TextIndent

type TextIndent struct {
	// Length is the indentation amount (can be negative).
	Length units.Length

	// Hanging applies indent to all lines except the first (reverse indent).
	// CSS: text-indent: 2em hanging;
	Hanging bool

	// EachLine applies indent to each line after a forced line break.
	// CSS: text-indent: 2em each-line;
	EachLine bool
}

TextIndent controls indentation of the first line or all lines.

Specification:

func DefaultTextIndent

func DefaultTextIndent() TextIndent

DefaultTextIndent returns zero indentation.

type TextJustify

type TextJustify int

TextJustify specifies the justification method.

Specification:

const (
	// TextJustifyAuto allows the browser to choose (typically inter-word).
	TextJustifyAuto TextJustify = iota

	// TextJustifyNone disables justification.
	TextJustifyNone

	// TextJustifyInterWord adds space between words.
	// Best for scripts that use word separators (Latin, Greek, Cyrillic).
	TextJustifyInterWord

	// TextJustifyInterCharacter adds space between characters.
	// Best for CJK scripts without word separators.
	TextJustifyInterCharacter

	// TextJustifyDistribute distributes space evenly (similar to inter-character).
	// Legacy value, maps to inter-character.
	TextJustifyDistribute
)

type TextOrientation

type TextOrientation int

TextOrientation controls glyph orientation in vertical text. Based on CSS Writing Modes Module Level 4 §7.1: https://www.w3.org/TR/css-writing-modes-4/#text-orientation

const (
	// TextOrientationMixed uses upright orientation for CJK and rotates other characters.
	// This is the default for vertical writing modes.
	TextOrientationMixed TextOrientation = iota

	// TextOrientationUpright forces all characters to upright orientation.
	TextOrientationUpright

	// TextOrientationSideways rotates all characters 90° clockwise.
	TextOrientationSideways

	// TextOrientationSidewaysRight is deprecated, use Sideways instead.
	TextOrientationSidewaysRight
)

type TextOverflow

type TextOverflow int

TextOverflow controls how overflowing inline content is signaled to users. Based on CSS Basic User Interface Module Level 4 §3.1: https://www.w3.org/TR/css-ui-4/#text-overflow

const (
	// TextOverflowClip clips the text at the content edge (no ellipsis).
	TextOverflowClip TextOverflow = iota

	// TextOverflowEllipsis displays an ellipsis ('...') to represent clipped text.
	TextOverflowEllipsis

	// TextOverflowString displays a custom string to represent clipped text.
	// The string value is specified separately.
	TextOverflowString

	// TextOverflowFade fades out the end of the text (not widely supported).
	TextOverflowFade
)

type TextSpacingTrim

type TextSpacingTrim int

TextSpacingTrim controls trimming of CJK spacing.

Specification:

const (
	// TextSpacingTrimNone disables spacing trim.
	TextSpacingTrimNone TextSpacingTrim = iota

	// TextSpacingTrimSpaceAll trims space before/after ideographic characters.
	TextSpacingTrimSpaceAll

	// TextSpacingTrimSpaceFirst trims space at line start.
	TextSpacingTrimSpaceFirst

	// TextSpacingTrimAuto uses language-specific rules.
	TextSpacingTrimAuto
)

type TextStyle

type TextStyle struct {
	FontSize      float64
	LineHeight    float64
	LetterSpacing float64
	FontFamily    string
	Bold          bool
	Italic        bool
}

TextStyle mirrors the text styling properties from the layout engine. This avoids importing the layout package directly.

type TextTransform

type TextTransform int

TextTransform controls case transformation of text.

Specification:

const (
	// TextTransformNone performs no transformation.
	TextTransformNone TextTransform = iota

	// TextTransformUppercase converts all characters to uppercase.
	TextTransformUppercase

	// TextTransformLowercase converts all characters to lowercase.
	TextTransformLowercase

	// TextTransformCapitalize capitalizes the first character of each word.
	TextTransformCapitalize

	// TextTransformFullWidth converts characters to their fullwidth forms.
	// Used in East Asian typography.
	TextTransformFullWidth

	// TextTransformFullSizeKana converts small kana to full-size equivalents.
	TextTransformFullSizeKana
)

type TextWrap

type TextWrap int

TextWrap controls advanced text wrapping strategies.

Specification:

const (
	// TextWrapWrap allows wrapping at any break point (default).
	TextWrapWrap TextWrap = iota

	// TextWrapNowrap disables wrapping.
	TextWrapNowrap

	// TextWrapBalance tries to balance line lengths.
	// Good for headings and short blocks of text.
	TextWrapBalance

	// TextWrapStable minimizes reflow when editing.
	// Only wraps when next word doesn't fit.
	TextWrapStable

	// TextWrapPretty optimizes for readability.
	// Avoids orphans and short last lines.
	TextWrapPretty
)

type TextWrapMode

type TextWrapMode int

TextWrapMode controls whether lines may wrap at soft wrap opportunities.

Specification:

const (
	// TextWrapModeWrap allows wrapping at soft wrap opportunities.
	TextWrapModeWrap TextWrapMode = iota

	// TextWrapModeNowrap prevents wrapping.
	TextWrapModeNowrap
)

type TextWrapStyle

type TextWrapStyle int

TextWrapStyle controls how wrapping is performed.

Specification:

const (
	// TextWrapStyleAuto uses standard wrapping.
	TextWrapStyleAuto TextWrapStyle = iota

	// TextWrapStyleBalance tries to balance line lengths.
	TextWrapStyleBalance

	// TextWrapStyleStable minimizes reflow when editing.
	TextWrapStyleStable

	// TextWrapStylePretty optimizes for readability.
	TextWrapStylePretty
)

type TruncateOptions

type TruncateOptions struct {
	// MaxWidth is the maximum width for the truncated text in abstract units.
	// For terminals: character cells (e.g., 20 means 20 columns)
	// For canvas: pixels (e.g., 200.0 means 200 pixels)
	// Units are determined by the MeasureFunc configuration.
	MaxWidth float64

	// Ellipsis is the string to append when truncating (default: "...").
	Ellipsis string

	// Strategy specifies where to truncate.
	Strategy TruncateStrategy
}

TruncateOptions configures truncation behavior.

type TruncateStrategy

type TruncateStrategy int

TruncateStrategy specifies where to truncate text.

const (
	// TruncateEnd truncates at the end: "Hello wo..."
	TruncateEnd TruncateStrategy = iota

	// TruncateMiddle truncates in the middle: "Hel...rld"
	TruncateMiddle

	// TruncateStart truncates at the start: "...o world"
	TruncateStart
)

type VerticalLine

type VerticalLine struct {
	Content    string
	Advance    float64 // Vertical advance (column height)
	InlineSize float64 // Horizontal size (column width)
	Start      int
	End        int
}

VerticalLine represents a line in vertical layout (a column).

type VerticalMetrics

type VerticalMetrics struct {
	// Advance is the vertical advance (height) for this text segment.
	Advance float64

	// InlineSize is the inline dimension (width in vertical layout).
	InlineSize float64

	// BlockSize is the block dimension (height in vertical layout).
	BlockSize float64

	// BaselineOffset is the offset from the baseline.
	BaselineOffset float64
}

VerticalMetrics provides measurements for vertical text layout.

type VerticalTextStyle

type VerticalTextStyle struct {
	WritingMode        WritingMode
	TextOrientation    TextOrientation
	TextCombineUpright TextCombineUpright

	// GlyphOrientationVertical controls glyph rotation in vertical text.
	// Deprecated in favor of TextOrientation, but kept for compatibility.
	// Value in degrees: 0, 90, -90, or auto.
	GlyphOrientationVertical float64
}

VerticalTextStyle configures vertical text layout properties.

func DefaultVerticalTextStyle

func DefaultVerticalTextStyle() VerticalTextStyle

DefaultVerticalTextStyle returns default vertical text style (horizontal layout).

type VerticalWrapOptions

type VerticalWrapOptions struct {
	// MaxBlockSize is the maximum block dimension before wrapping.
	// For vertical text, this is the maximum column height.
	MaxBlockSize float64

	// Style configures vertical text properties.
	Style VerticalTextStyle

	// BaseOptions provides standard wrapping options.
	BaseOptions WrapOptions
}

VerticalWrapOptions extends WrapOptions for vertical text.

type WhiteSpace

type WhiteSpace int

WhiteSpace controls how white space is handled inside an element.

Specification:

const (
	// WhiteSpaceNormal collapses white space sequences and wraps lines.
	// Newlines are treated as spaces.
	WhiteSpaceNormal WhiteSpace = iota

	// WhiteSpacePre preserves all white space and does not wrap.
	// Like HTML <pre> tag.
	WhiteSpacePre

	// WhiteSpaceNoWrap collapses white space but does not wrap lines.
	WhiteSpaceNoWrap

	// WhiteSpacePreWrap preserves white space and wraps lines.
	WhiteSpacePreWrap

	// WhiteSpacePreLine collapses white space sequences but preserves newlines.
	WhiteSpacePreLine

	// WhiteSpaceBreakSpaces preserves white space and allows breaking at spaces.
	WhiteSpaceBreakSpaces
)

type WhiteSpaceCollapse

type WhiteSpaceCollapse int

WhiteSpaceCollapse controls how white space sequences are handled.

Specification:

const (
	// WhiteSpaceCollapseCollapse collapses sequences of white space into single space.
	WhiteSpaceCollapseCollapse WhiteSpaceCollapse = iota

	// WhiteSpaceCollapsePreserve preserves all white space.
	WhiteSpaceCollapsePreserve

	// WhiteSpaceCollapsePreserveBreaks collapses white space but preserves line breaks.
	WhiteSpaceCollapsePreserveBreaks

	// WhiteSpaceCollapsePreserveSpaces preserves space characters but collapses other whitespace.
	WhiteSpaceCollapsePreserveSpaces

	// WhiteSpaceCollapseBreakSpaces like preserve but allows breaking at spaces.
	WhiteSpaceCollapseBreakSpaces
)

type WhiteSpaceTrim

type WhiteSpaceTrim int

WhiteSpaceTrim controls trimming of whitespace at box boundaries.

Specification:

const (
	// WhiteSpaceTrimNone disables trimming.
	WhiteSpaceTrimNone WhiteSpaceTrim = iota

	// WhiteSpaceTrimDiscardBefore trims whitespace at start of box.
	WhiteSpaceTrimDiscardBefore

	// WhiteSpaceTrimDiscardAfter trims whitespace at end of box.
	WhiteSpaceTrimDiscardAfter

	// WhiteSpaceTrimDiscardInner trims whitespace between boxes.
	WhiteSpaceTrimDiscardInner
)

type WordBreak

type WordBreak int

WordBreak controls word breaking rules for CJK and other scripts.

Specification:

const (
	// WordBreakNormal uses default line break rules.
	WordBreakNormal WordBreak = iota

	// WordBreakBreakAll allows breaks between any characters for non-CJK scripts.
	WordBreakBreakAll

	// WordBreakKeepAll prevents breaks between CJK characters.
	// Only breaks at whitespace and punctuation.
	WordBreakKeepAll

	// WordBreakBreakWord is like normal, but allows breaking within words
	// if there are no acceptable break points in the line.
	WordBreakBreakWord
)

type WordSpaceTransform

type WordSpaceTransform int

WordSpaceTransform transforms word separators between styles.

Specification:

const (
	// WordSpaceTransformNone performs no transformation.
	WordSpaceTransformNone WordSpaceTransform = iota

	// WordSpaceTransformSpace preserves/converts to space character.
	WordSpaceTransformSpace

	// WordSpaceTransformIdeographicSpace converts to ideographic space (U+3000).
	WordSpaceTransformIdeographicSpace

	// WordSpaceTransformAutoPhrase enables auto phrase detection.
	WordSpaceTransformAutoPhrase
)

type WrapControl

type WrapControl int

WrapControl specifies wrap behavior before/after an element.

Specification:

const (
	// WrapControlAuto uses normal line breaking rules.
	WrapControlAuto WrapControl = iota

	// WrapControlAvoid avoids breaking before/after if possible.
	WrapControlAvoid

	// WrapControlAlways forces a break before/after.
	WrapControlAlways
)

type WrapInside

type WrapInside int

WrapInside controls whether line breaking is allowed within an element.

Specification:

const (
	// WrapInsideAuto allows normal line breaking within the element.
	WrapInsideAuto WrapInside = iota

	// WrapInsideAvoid suppresses line breaking within the element.
	WrapInsideAvoid
)

type WrapOptions

type WrapOptions struct {
	// MaxWidth is the maximum width for wrapped lines in abstract units.
	// For terminals: character cells (e.g., 40 means 40 columns)
	// For canvas: pixels (e.g., 400.0 means 400 pixels)
	// Units are determined by the MeasureFunc configuration.
	MaxWidth float64

	// BreakWords allows breaking in the middle of words if necessary.
	// If false, only breaks at UAX #14 line break opportunities.
	BreakWords bool

	// PreserveNewlines keeps existing newline characters as line breaks.
	PreserveNewlines bool
}

WrapOptions configures text wrapping behavior.

type WrapPoint

type WrapPoint struct {
	Position int         // Position in text (rune index)
	Before   WrapControl // Wrap behavior before this position
	After    WrapControl // Wrap behavior after this position
}

WrapPoint represents a position where wrapping behavior is controlled.

type WritingMode

type WritingMode int

WritingMode specifies the block flow direction. Based on CSS Writing Modes Module Level 4: https://www.w3.org/TR/css-writing-modes-4/#block-flow

const (
	// WritingModeHorizontalTB flows top to bottom, inline left to right.
	// This is the default for Latin scripts.
	WritingModeHorizontalTB WritingMode = iota

	// WritingModeVerticalRL flows right to left, inline top to bottom.
	// Used in traditional Chinese, Japanese, Korean typography.
	WritingModeVerticalRL

	// WritingModeVerticalLR flows left to right, inline top to bottom.
	// Used in some Mongolian and certain historical scripts.
	WritingModeVerticalLR

	// WritingModeSidewaysRL flows right to left with characters rotated 90° clockwise.
	// Used for mixed scripts in vertical layout.
	WritingModeSidewaysRL

	// WritingModeSidewaysLR flows left to right with characters rotated 90° counter-clockwise.
	WritingModeSidewaysLR
)

type XOffsetInfo

type XOffsetInfo struct {
	// Position in the text (rune index)
	Position int

	// CharXOffset is the x-offset of the character's left edge
	CharXOffset float64

	// CharWidth is the width of the character
	CharWidth float64

	// IsTrailing indicates if offset is in trailing half of character
	// Used for determining cursor position: before or after character
	IsTrailing bool

	// IsWithinLine indicates if the offset is within the line's width
	IsWithinLine bool
}

XOffsetInfo contains information about a position found at an x-offset.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL