sequences.py

Module providing ‘sequence awareness’.

class Sequence(sequence_text: str, term: Terminal)[source]

A “sequence-aware” version of the base str class.

This unicode-derived class understands the effect of escape sequences of printable length, allowing a properly implemented rjust(), ljust(), center(), and length().

Note

that other than Sequence.padd(), this is just a thin layer over wcwidth, kept by name for API compatibility.

Class constructor.

Parameters:
  • sequence_text (str) – A string that may contain sequences.

  • term (blessed.Terminal) – Terminal instance.

ljust(width: SupportsIndex, fillchar: str = ' ') str[source]

Return string containing sequences, left-adjusted.

Parameters:
  • width (int) – Total width given to left-adjust text.

  • fillchar (str) – String for padding right-of text.

Returns:

String of text, left-aligned by width.

Return type:

str

rjust(width: SupportsIndex, fillchar: str = ' ') str[source]

Return string containing sequences, right-adjusted.

Parameters:
  • width (int) – Total width given to right-adjust text.

  • fillchar (str) – String for padding left-of text.

Returns:

String of text, right-aligned by width.

Return type:

str

center(width: SupportsIndex, fillchar: str = ' ') str[source]

Return string containing sequences, centered.

Parameters:
  • width (int) – Total width given to center text.

  • fillchar (str) – String for padding left and right-of text.

Returns:

String of text, centered by width.

Return type:

str

truncate(width: SupportsIndex) str[source]

Truncate a string in a sequence-aware manner.

Any printable characters beyond width are removed, while all sequences remain in place. Horizontal sequences are first expanded by padd().

Wide characters (such as CJK or emoji) that would partially exceed width are replaced with space padding to maintain exact width.

SGR (terminal styling) sequences are propagated: the result begins with any active style at the start position and ends with a reset sequence if styles were active.

Parameters:

width (int) – The printable width to truncate the string to.

Return type:

str

Returns:

String truncated to exactly width printable characters.

length() int[source]

Return the printable length of string containing sequences.

Returns the maximum horizontal cursor extent reached while processing the string. Backspace and cursor-left movements do not reduce the length below the maximum position reached.

Some characters may consume more than one cell, mainly CJK (Chinese, Japanese, Korean) and Emojis and some kinds of symbols.

For example:

>>> from blessed import Terminal
>>> from blessed.sequences import Sequence
>>> term = Terminal()
>>> msg = term.clear + term.red('コンニチハ')
>>> Sequence(msg, term).length()
10

Note

Although accounted for, strings containing sequences such as term.clear will not give accurate returns, it is not considered lengthy (a length of 0).

strip(chars: str | None = None) str[source]

Return string of sequences, leading and trailing whitespace removed.

Parameters:

chars (str) – Remove characters in chars instead of whitespace.

Return type:

str

Returns:

string of sequences with leading and trailing whitespace removed.

lstrip(chars: str | None = None) str[source]

Return string of all sequences and leading whitespace removed.

Parameters:

chars (str) – Remove characters in chars instead of whitespace.

Return type:

str

Returns:

string of sequences with leading removed.

rstrip(chars: str | None = None) str[source]

Return string of all sequences and trailing whitespace removed.

Parameters:

chars (str) – Remove characters in chars instead of whitespace.

Return type:

str

Returns:

string of sequences with trailing removed.

strip_seqs() str[source]

Return text stripped of only its terminal sequences.

Return type:

str

Returns:

Text with terminal sequences removed

padd(strip: bool = False) str[source]

Return non-destructive horizontal movement as destructive spacing.

Parameters:

strip (bool) – Strip terminal sequences

Return type:

str

Returns:

Text adjusted for horizontal movement

class SequenceTextWrapper(width: int = 70, *, control_codes: Literal['parse', 'strict', 'ignore'] = 'parse', tabsize: int = 8, ambiguous_width: int = 1, **kwargs: Any)[source]

Sequence-aware text wrapper extending textwrap.TextWrapper.

This wrapper properly handles terminal escape sequences and Unicode grapheme clusters when calculating text width for wrapping.

This implementation is based on the SequenceTextWrapper from the ‘blessed’ library, with contributions from Avram Lubkin and grayjk.

The key difference from the blessed implementation is the addition of grapheme cluster support via iter_graphemes(), providing width calculation for ZWJ emoji sequences, VS-16 emojis and variations, regional indicator flags, and combining characters.

OSC 8 hyperlinks are handled specially: when a hyperlink must span multiple lines, each line receives complete open/close sequences with a shared id parameter, ensuring terminals treat the fragments as a single hyperlink for hover underlining. If the original hyperlink already has an id parameter, it is preserved; otherwise, one is generated.

Initialize the wrapper.

Parameters:
  • width – Maximum line width in display cells.

  • control_codes – How to handle control sequences (see width()).

  • tabsize – Tab stop width for tab expansion.

  • ambiguous_width – Width to use for East Asian Ambiguous (A) characters.

  • kwargs – Additional arguments passed to textwrap.TextWrapper.

Generate unique hyperlink id as 8-character hex string.

_width(text: str) int[source]

Measure text width accounting for sequences.

_strip_sequences(text: str) str[source]

Strip all terminal sequences from text.

_extract_sequences(text: str) str[source]

Extract only terminal sequences from text.

_split(text: str) list[str][source]

Sequence-aware variant of textwrap.TextWrapper._split().

This method ensures that terminal escape sequences don’t interfere with the text splitting logic, particularly for hyphen-based word breaking. It builds a position mapping from stripped text to original text, calls the parent’s _split on stripped text, then maps chunks back.

OSC hyperlink sequences are treated as word boundaries:

>>> wrap('foo \x1b]8;;https://example.com\x07link\x1b]8;;\x07 bar', 6)
['foo', '\x1b]8;;https://example.com\x07link\x1b]8;;\x07', 'bar']

Both BEL (\x07) and ST (\x1b\\) terminators are supported.

_wrap_chunks(chunks: list[str]) list[str][source]

Wrap chunks into lines using sequence-aware width.

Override TextWrapper._wrap_chunks to use _width instead of len. Follows stdlib’s algorithm: greedily fill lines, handle long words. Also handle OSC hyperlink processing. When hyperlinks span multiple lines, each line gets complete open/close sequences with matching id parameters for hover underlining continuity per OSC 8 spec.

Track hyperlink state through text.

Parameters:
  • text – Text to scan for hyperlink sequences.

  • state – Current state or None if outside hyperlink.

Returns:

Updated state after processing text.

_handle_long_word(reversed_chunks: list[str], cur_line: list[str], cur_len: int, width: int) None[source]

Sequence-aware textwrap.TextWrapper._handle_long_word().

This method ensures that word boundaries are not broken mid-sequence, and respects grapheme cluster boundaries when breaking long words.

_map_stripped_pos_to_original(text: str, stripped_pos: int) int[source]

Map a position in stripped text back to original text position.

_find_break_position(text: str, max_width: int) int[source]

Find string index in text that fits within max_width cells.

_find_first_grapheme_end(text: str) int[source]

Find the end position of the first grapheme.

_rstrip_visible(text: str) str[source]

Strip trailing visible whitespace, preserving trailing sequences.

iter_parse(term: Terminal, text: str) Iterator[Tuple[str, Termcap | None]][source]

Generator yields (text, capability) for characters of text.

value for capability may be None, where text is str of length 1. Otherwise, text is a full matching sequence of given capability.

Note

Previously used by SequenceTextWrapper, sequence-aware text wrapping now exists in wcwidth as wcwidth.wrap(). This function is kept for API compatibility and used by measure_length().

measure_length(text: str, term: Terminal) int[source]

Kept for API compatibility.

Return type:

int

Returns:

Length of the first sequence in the string

Deprecated since version 1.30.0.