method.go

  1package ansi
  2
  3// Method is a type that represents the how the renderer should calculate the
  4// display width of cells.
  5type Method uint8
  6
  7// Display width modes.
  8const (
  9	WcWidth Method = iota
 10	GraphemeWidth
 11)
 12
 13// StringWidth returns the width of a string in cells. This is the number of
 14// cells that the string will occupy when printed in a terminal. ANSI escape
 15// codes are ignored and wide characters (such as East Asians and emojis) are
 16// accounted for.
 17func (m Method) StringWidth(s string) int {
 18	return stringWidth(m, s)
 19}
 20
 21// Truncate truncates a string to a given length, adding a tail to the end if
 22// the string is longer than the given length. This function is aware of ANSI
 23// escape codes and will not break them, and accounts for wide-characters (such
 24// as East-Asian characters and emojis).
 25func (m Method) Truncate(s string, length int, tail string) string {
 26	return truncate(m, s, length, tail)
 27}
 28
 29// TruncateLeft truncates a string to a given length, adding a prefix to the
 30// beginning if the string is longer than the given length. This function is
 31// aware of ANSI escape codes and will not break them, and accounts for
 32// wide-characters (such as East-Asian characters and emojis).
 33func (m Method) TruncateLeft(s string, length int, prefix string) string {
 34	return truncateLeft(m, s, length, prefix)
 35}
 36
 37// Cut the string, without adding any prefix or tail strings. This function is
 38// aware of ANSI escape codes and will not break them, and accounts for
 39// wide-characters (such as East-Asian characters and emojis). Note that the
 40// [left] parameter is inclusive, while [right] isn't.
 41func (m Method) Cut(s string, left, right int) string {
 42	return cut(m, s, left, right)
 43}
 44
 45// Hardwrap wraps a string or a block of text to a given line length, breaking
 46// word boundaries. This will preserve ANSI escape codes and will account for
 47// wide-characters in the string.
 48// When preserveSpace is true, spaces at the beginning of a line will be
 49// preserved.
 50// This treats the text as a sequence of graphemes.
 51func (m Method) Hardwrap(s string, length int, preserveSpace bool) string {
 52	return hardwrap(m, s, length, preserveSpace)
 53}
 54
 55// Wordwrap wraps a string or a block of text to a given line length, not
 56// breaking word boundaries. This will preserve ANSI escape codes and will
 57// account for wide-characters in the string.
 58// The breakpoints string is a list of characters that are considered
 59// breakpoints for word wrapping. A hyphen (-) is always considered a
 60// breakpoint.
 61//
 62// Note: breakpoints must be a string of 1-cell wide rune characters.
 63func (m Method) Wordwrap(s string, length int, breakpoints string) string {
 64	return wordwrap(m, s, length, breakpoints)
 65}
 66
 67// Wrap wraps a string or a block of text to a given line length, breaking word
 68// boundaries if necessary. This will preserve ANSI escape codes and will
 69// account for wide-characters in the string. The breakpoints string is a list
 70// of characters that are considered breakpoints for word wrapping. A hyphen
 71// (-) is always considered a breakpoint.
 72//
 73// Note: breakpoints must be a string of 1-cell wide rune characters.
 74func (m Method) Wrap(s string, length int, breakpoints string) string {
 75	return wrap(m, s, length, breakpoints)
 76}
 77
 78// DecodeSequence decodes the first ANSI escape sequence or a printable
 79// grapheme from the given data. It returns the sequence slice, the number of
 80// bytes read, the cell width for each sequence, and the new state.
 81//
 82// The cell width will always be 0 for control and escape sequences, 1 for
 83// ASCII printable characters, and the number of cells other Unicode characters
 84// occupy. It uses the uniseg package to calculate the width of Unicode
 85// graphemes and characters. This means it will always do grapheme clustering
 86// (mode 2027).
 87//
 88// Passing a non-nil [*Parser] as the last argument will allow the decoder to
 89// collect sequence parameters, data, and commands. The parser cmd will have
 90// the packed command value that contains intermediate and prefix characters.
 91// In the case of a OSC sequence, the cmd will be the OSC command number. Use
 92// [Cmd] and [Param] types to unpack command intermediates and prefixes as well
 93// as parameters.
 94//
 95// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the
 96// validity of other data sequences, OSC, DCS, etc, will require checking for
 97// the returned sequence terminator bytes such as ST (ESC \\) and BEL).
 98//
 99// We store the command byte in [Cmd] in the most significant byte, the
100// prefix byte in the next byte, and the intermediate byte in the least
101// significant byte. This is done to avoid using a struct to store the command
102// and its intermediates and prefixes. The command byte is always the least
103// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the
104// command, intermediate, and prefix bytes. Note that we only collect the last
105// prefix character and intermediate byte.
106//
107// The [p.Params] slice will contain the parameters of the sequence. Any
108// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type
109// to unpack the parameters.
110//
111// Example:
112//
113//	var state byte // the initial state is always zero [NormalState]
114//	p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional)
115//	input := []byte("\x1b[31mHello, World!\x1b[0m")
116//	for len(input) > 0 {
117//		seq, width, n, newState := DecodeSequence(input, state, p)
118//		log.Printf("seq: %q, width: %d", seq, width)
119//		state = newState
120//		input = input[n:]
121//	}
122func (m Method) DecodeSequence(data []byte, state byte, p *Parser) (seq []byte, width, n int, newState byte) {
123	return decodeSequence(m, data, state, p)
124}
125
126// DecodeSequenceInString decodes the first ANSI escape sequence or a printable
127// grapheme from the given data. It returns the sequence slice, the number of
128// bytes read, the cell width for each sequence, and the new state.
129//
130// The cell width will always be 0 for control and escape sequences, 1 for
131// ASCII printable characters, and the number of cells other Unicode characters
132// occupy. It uses the uniseg package to calculate the width of Unicode
133// graphemes and characters. This means it will always do grapheme clustering
134// (mode 2027).
135//
136// Passing a non-nil [*Parser] as the last argument will allow the decoder to
137// collect sequence parameters, data, and commands. The parser cmd will have
138// the packed command value that contains intermediate and prefix characters.
139// In the case of a OSC sequence, the cmd will be the OSC command number. Use
140// [Cmd] and [Param] types to unpack command intermediates and prefixes as well
141// as parameters.
142//
143// Zero [Cmd] means the CSI, DCS, or ESC sequence is invalid. Moreover, checking the
144// validity of other data sequences, OSC, DCS, etc, will require checking for
145// the returned sequence terminator bytes such as ST (ESC \\) and BEL).
146//
147// We store the command byte in [Cmd] in the most significant byte, the
148// prefix byte in the next byte, and the intermediate byte in the least
149// significant byte. This is done to avoid using a struct to store the command
150// and its intermediates and prefixes. The command byte is always the least
151// significant byte i.e. [Cmd & 0xff]. Use the [Cmd] type to unpack the
152// command, intermediate, and prefix bytes. Note that we only collect the last
153// prefix character and intermediate byte.
154//
155// The [p.Params] slice will contain the parameters of the sequence. Any
156// sub-parameter will have the [parser.HasMoreFlag] set. Use the [Param] type
157// to unpack the parameters.
158//
159// Example:
160//
161//	var state byte // the initial state is always zero [NormalState]
162//	p := NewParser(32, 1024) // create a new parser with a 32 params buffer and 1024 data buffer (optional)
163//	input := []byte("\x1b[31mHello, World!\x1b[0m")
164//	for len(input) > 0 {
165//		seq, width, n, newState := DecodeSequenceInString(input, state, p)
166//		log.Printf("seq: %q, width: %d", seq, width)
167//		state = newState
168//		input = input[n:]
169//	}
170func (m Method) DecodeSequenceInString(data string, state byte, p *Parser) (seq string, width, n int, newState byte) {
171	return decodeSequence(m, data, state, p)
172}