go-runewidth

repository·master·Indexed 20 days ago

https://github.com/mattn/go-runewidth

A Go library for calculating the fixed visual width of individual characters or strings in terminal or fixed-width environments. It accounts for multi-column characters, Unicode grapheme clusters, and East Asian width. The package provides utilities for string truncation, wrapping, padding, and custom width configurations via the Condition type.

Tokens
1.4K
Snippets
7
Records
8
Agent score
22%

What's inside go-runewidth

  1. Use Condition for custom width configurations

    master

    If the default behavior (based on the RUNEWIDTH_EASTASIAN environment variable) does not suit your needs, use the Condition struct to define custom width rules.

    Configuration Options

    • EastAsianWidth: Set to true to treat CJK characters as double-width.
    • StrictEmojiNeutral: If true, emoji handling follows strict rules. If false, it may help with broken font rendering by treating some emojis as double-width.
    • ZeroWidthJoiner: (Deprecated) No longer has an effect as ZWJ sequences are handled via grapheme segmentation.

    Performance Optimization

    If you are performing many width calculations with a custom Condition, call CreateLUT() to generate an in-memory lookup table. This significantly speeds up RuneWidth and StringWidth calls. Note: CreateLUT should not be called concurrently with other operations on the same Condition instance, and must be re-called if you change the condition's settings.

    import "github.com/mattn/go-runewidth"
    
    cond := runewidth.NewCondition()
    cond.EastAsianWidth = true
    cond.StrictEmojiNeutral = false
    
    // Optimize for high-frequency calls
    cond.CreateLUT()
    
    width := cond.StringWidth("some string")
  2. Calculate the visual width of a string with runewidth.StringWidth

    master

    Use runewidth.StringWidth to determine the fixed visual width of a string. This is useful for handling characters that occupy more than one column in a terminal or fixed-width environment (such as East Asian characters or symbols).

    runewidth.StringWidth("つのだ☆HIRO") == 12
  3. Truncate strings to a specific cell width

    master

    The library provides several ways to truncate strings so they fit within a specific number of terminal cells:

    • Truncate(s string, w int, tail string): Truncates the string s to width w and appends a tail (e.g., ...).
    • TruncateLeft(s string, w int, prefix string): Cuts w cells from the beginning of s and prepends a prefix.
    • TruncatePrefix(s string, w int, prefix string): Cuts the beginning of s so the result fits in w cells, with prefix prepended.

    All these functions respect grapheme clusters to avoid cutting in the middle of an emoji or combining character sequence.

    import "github.com/mattn/go-runewidth"
    
    // Truncate with a tail
    // If s is "Hello World" and w is 5, result is "Hello..."
    res := runewidth.Truncate("Hello World", 5, "...")
  4. Check if a rune is Ambiguous, Combining, or Neutral

    master

    The package provides utility functions to inspect the width properties of individual runes:

    • IsAmbiguousWidth(r rune): Returns true if the rune has an ambiguous width (often used in CJK contexts).
    • IsCombiningWidth(r rune): Returns true if the rune is a combining character (width 0).
    • IsNeutralWidth(r rune): Returns true if the rune is a neutral width character.
  5. Wrap text to a specific cell width

    master

    Use Wrap(s string, w int) to wrap a string into multiple lines so that no line exceeds w cells. The function inserts newline characters (\n) when the next rune would cause the current line to exceed the width limit. It respects existing newlines in the input string.

    import "github.com/mattn/go-runewidth"
    
    wrapped := runewidth.Wrap("This is a long string that needs wrapping", 10)
  6. Pad strings with spaces using FillLeft and FillRight

    master

    To align text in a terminal, use these functions to pad a string to a target width w:

    • FillLeft(s string, w int): Prepends spaces to the beginning of s until it reaches width w.
    • FillRight(s string, w int): Appends spaces to the end of s until it reaches width w.
    import "github.com/mattn/go-runewidth"
    
    leftPadded := runewidth.FillLeft("text", 10)  // "      text"
    rightPadded := runewidth.FillRight("text", 10) // "text      "
  7. Calculate string display width with StringWidth

    master

    Use StringWidth(s string) to calculate the visual width of a string in terminal cells. This function accounts for Unicode grapheme clusters (like emojis or combining characters) to ensure the returned width matches how the string actually renders. It uses a fast path for ASCII strings and handles complex graphemes via the uax29 segmentation logic.

    For custom configurations (e.g., different handling of East Asian width or emoji neutrality), use the Condition type instead of the package-level functions.

    import "github.com/mattn/go-runewidth"
    
    width := runewidth.StringWidth("Hello, 世界!")
    // width will correctly account for the multi-cell CJK characters
  8. Calculate rune display width with RuneWidth

    master

    Use RuneWidth(r rune) to get the number of cells a single Unicode rune occupies. This follows Unicode TR#11. It uses the DefaultCondition for its calculation.

    If you need to control whether East Asian width is enabled or how emojis are treated, instantiate a Condition and call its RuneWidth method.

    import "github.com/mattn/go-runewidth"
    
    width := runewidth.RuneWidth('世')
    // width will be 2 for CJK characters in a CJK locale