@@ -23,18 +23,23 @@ type WordWrap struct {
2323 Newline []rune
2424 KeepNewlines bool
2525 HardWrap bool
26- TabReplace string // since tabs can have differrent lengths, replace them with this when hardwrap is enabled
26+ TabReplace string // since tabs can have different lengths, replace them with this when hardwrap is enabled
2727 PreserveSpaces bool
2828
2929 buf bytes.Buffer // processed and, in line, accepted bytes
3030 space bytes.Buffer // pending continues spaces bytes
3131 word ansi.Buffer // pending continues word bytes
3232
33- lineLen int // the visible length of the line not accorat for tabs
33+ lineLen int // the visible length of the line not accurate for tabs
3434 ansi bool
3535
36- wroteBegin bool // mark is since the last newline something has writen to the buffer (for ansi restart)
36+ wroteBegin bool // mark is since the last newline something has written to the buffer (for ansi restart)
3737 lastAnsi bytes.Buffer // hold last active ansi sequence
38+
39+ // the following are used to remove leading zeros from the single arguments of the ansi-sequence, but still detect single zeros:
40+ // \x1B[0031;0000m => \x1B[31;0m
41+ newArgument bool
42+ leadingZero bool
3843}
3944
4045// NewWriter returns a new instance of a word-wrapping writer, initialized with
@@ -64,8 +69,8 @@ func String(s string, limit int) string {
6469 return string (Bytes ([]byte (s ), limit ))
6570}
6671
67- // HardWrap is a shorthand for declaring a new hardwraping WordWrap instance,
68- // since varibale length characters can not be hard wraped to a fixed length,
72+ // HardWrap is a shorthand for declaring a new hardwrapping WordWrap instance,
73+ // since variable length characters can not be hard wrapped to a fixed length,
6974// tabs will be replaced by TabReplace, use according amount of spaces.
7075func HardWrap (s string , limit int , tabReplace string ) string {
7176 f := NewWriter (limit )
@@ -77,22 +82,22 @@ func HardWrap(s string, limit int, tabReplace string) string {
7782 return f .String ()
7883}
7984
80- // addes pending spaces to the buf(fer) and then resets the space buffer.
85+ // adds pending spaces to the buf(fer) and then resets the space buffer.
8186func (w * WordWrap ) addSpace () {
8287 if w .space .Len () <= w .Limit - w .lineLen {
8388 w .lineLen += w .space .Len ()
84- w .buf .Write (w .space .Bytes ())
89+ _ , _ = w .buf .Write (w .space .Bytes ())
8590 } else {
8691 length := w .space .Len ()
8792 first := w .Limit - w .lineLen
88- w .buf .WriteString (strings .Repeat (" " , first ))
93+ _ , _ = w .buf .WriteString (strings .Repeat (" " , first ))
8994 length -= first
9095 for length >= w .Limit {
91- w .buf .WriteString ("\n " + strings .Repeat (" " , w .Limit ))
96+ _ , _ = w .buf .WriteString ("\n " + strings .Repeat (" " , w .Limit ))
9297 length -= w .Limit
9398 }
9499 if length > 0 {
95- w .buf .WriteString ("\n " + strings .Repeat (" " , length ))
100+ _ , _ = w .buf .WriteString ("\n " + strings .Repeat (" " , length ))
96101 }
97102 w .lineLen = length
98103 }
@@ -113,10 +118,10 @@ func (w *WordWrap) addNewLine() {
113118 w .addSpace ()
114119 }
115120 if w .lastAnsi .Len () != 0 {
116- // end ansi befor linebreak
117- w .buf .WriteString ("\x1b [0m" )
121+ // end ansi before linebreak
122+ _ , _ = w .buf .WriteString ("\x1B [0m" )
118123 }
119- w .buf .WriteRune ('\n' )
124+ _ , _ = w .buf .WriteRune ('\n' )
120125 w .lineLen = 0
121126 w .space .Reset ()
122127 w .wroteBegin = false
@@ -149,25 +154,60 @@ func (w *WordWrap) Write(b []byte) (int, error) {
149154 for _ , c := range s {
150155 // Restart Ansi after line break if there is more text
151156 if ! w .wroteBegin && ! w .ansi && w .lastAnsi .Len () != 0 {
152- w .buf .Write (w .lastAnsi .Bytes ())
157+ _ , _ = w .buf .Write (w .lastAnsi .Bytes ())
153158 w .addWord ()
154159 }
155160 w .wroteBegin = true
156161 if c == '\x1B' {
157162 // ANSI escape sequence
158- w .word .WriteRune (c )
159- w .lastAnsi .WriteRune (c )
163+ _ , _ = w .word .WriteRune (c )
164+ _ , _ = w .lastAnsi .WriteRune (c )
160165 w .ansi = true
166+ w .newArgument = true
161167 } else if w .ansi {
162- w .word .WriteRune (c )
163- w .lastAnsi .WriteRune (c )
168+
169+ // ignore leading zeros but remember single ones.
170+ if c == '0' && w .newArgument {
171+ w .leadingZero = true
172+ continue
173+ }
174+ w .newArgument = false
175+ // if a digit other then zero is encountered reset leading zero since we can ignore the leading zeroes if there where any.
176+ if inGroup ([]rune {'1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' }, c ) {
177+ w .leadingZero = false
178+ }
179+
180+ // check if new ANSI-argument starts
181+ if inGroup ([]rune {'[' , ';' }, c ) {
182+ w .newArgument = true
183+ // if w.leadingZero is here, we know that its a valid zero => reset and restart sequence.
184+ if w .leadingZero {
185+ // since we are still in the middle of the sequence and have reset the last ansi, we have to restart a new sequence:
186+ w .lastAnsi .Reset ()
187+ _ , _ = w .lastAnsi .WriteString ("\x1B [" )
188+ w .leadingZero = false
189+ _ , _ = w .word .WriteString ("0m\x1B [" )
190+ // "\x1B[31;0;32m" => "\x1B[31;0m\x1B[32m"
191+ continue // dont write "replace" semicolon
192+ }
193+ }
194+
195+ _ , _ = w .lastAnsi .WriteRune (c )
196+
164197 if (c >= 0x40 && c <= 0x5a ) || (c >= 0x61 && c <= 0x7a ) {
198+ // dont restart lastAnsi since its a end of a sequence. (not in the middle of one)
199+ if w .leadingZero {
200+ _ , _ = w .word .WriteRune ('0' )
201+
202+ w .lastAnsi .Reset ()
203+ w .leadingZero = false
204+ }
165205 // ANSI sequence terminated
166206 w .ansi = false
167207 }
168- if c == 'm' && strings . HasSuffix ( w . lastAnsi . String (), " \x1b [0m" ) {
169- w . lastAnsi . Reset ( )
170- }
208+
209+ _ , _ = w . word . WriteRune ( c )
210+
171211 } else if inGroup (w .Newline , c ) {
172212 // end of current line
173213 // see if we can add the content of the space buffer to the current line
@@ -191,10 +231,10 @@ func (w *WordWrap) Write(b []byte) (int, error) {
191231 // valid breakpoint
192232 w .addSpace ()
193233 w .addWord ()
194- w .buf .WriteRune (c )
234+ _ , _ = w .buf .WriteRune (c )
195235 } else if w .HardWrap && w .lineLen + w .word .PrintableRuneWidth ()+ runewidth .RuneWidth (c )+ w .space .Len () == w .Limit {
196- // Word is at the limite -> begin new word
197- w .word .WriteRune (c )
236+ // Word is at the limit -> begin new word
237+ _ , _ = w .word .WriteRune (c )
198238 w .addWord ()
199239 } else {
200240 // any other character
@@ -224,13 +264,13 @@ func (w *WordWrap) Close() error {
224264}
225265
226266// Bytes returns the word-wrapped result as a byte slice.
227- // Make sure to have closed the worwrapper, befor calling it.
267+ // Make sure to have closed the wordwrapper, before calling it.
228268func (w * WordWrap ) Bytes () []byte {
229269 return w .buf .Bytes ()
230270}
231271
232272// String returns the word-wrapped result as a string.
233- // Make sure to have closed the worwrapper, befor calling it.
273+ // Make sure to have closed the wordwrapper, before calling it.
234274func (w * WordWrap ) String () string {
235275 return w .buf .String ()
236276}
0 commit comments