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}