@@ -51,121 +51,41 @@ show(io::IO, ::MIME"text/plain", s::Splat) = show(io, s)
5151const possible_ansi_regex = r" \x 1B(?:[@-Z\\ -_\[ ])"
5252const start_ansi_regex = r" \G (?:[@-Z\\ -_]|\[ [0-?]*[ -/]*[@-~])"
5353
54- const text_colors = Dict {Union{Symbol,Int},String} (
55- :black => " \0 33[30m" ,
56- :red => " \0 33[31m" ,
57- :green => " \0 33[32m" ,
58- :yellow => " \0 33[33m" ,
59- :blue => " \0 33[34m" ,
60- :magenta => " \0 33[35m" ,
61- :cyan => " \0 33[36m" ,
62- :white => " \0 33[37m" ,
63- :light_black => " \0 33[90m" , # gray
64- :light_red => " \0 33[91m" ,
65- :light_green => " \0 33[92m" ,
66- :light_yellow => " \0 33[93m" ,
67- :light_blue => " \0 33[94m" ,
68- :light_magenta => " \0 33[95m" ,
69- :light_cyan => " \0 33[96m" ,
70- :light_white => " \0 33[97m" ,
71- :normal => " \0 33[0m" ,
72- :default => " \0 33[39m" ,
73- :bold => " \0 33[1m" ,
74- :underline => " \0 33[4m" ,
75- :blink => " \0 33[5m" ,
76- :reverse => " \0 33[7m" ,
77- :hidden => " \0 33[8m" ,
78- :nothing => " " ,
79- )
80-
81- for i in 0 : 255
82- text_colors[i] = String ([' \0 33' , ' [' , ' 3' , ' 8' , ' ;' , ' 5' , ' ;' , string (i)... , ' m' ])
83- end
84-
85- const ansi_code_index = Dict {String,Int8} (x[2 : end ] => 6 for x in values (text_colors) if ! isempty (x))
86- merge! (ansi_code_index, Dict {String,Int8} (
87- " [1m" => 1 , # bold
88- " [4m" => 2 , # underline
89- " [5m" => 3 , # blink
90- " [7m" => 4 , # reverse
91- " [8m" => 5 , # hidden
92- " [22m" => - 1 , # remove bold
93- " [24m" => - 2 , # remove underline
94- " [25m" => - 3 , # remove blink
95- " [27m" => - 4 , # remove reverse
96- " [28m" => - 5 , # remove hidden
97- " [39m" => - 6 , # reset default color
98- " [0m" => 0 # reset everything
99- ))
100-
101- function find_lastidx_withcolor (str, width, chars, truncwidth, start)
102- idx = lastidx = start
103- truncidx = 0 # if str needs to be truncated, index of truncation.
104- wid = textwidth (SubString (str, 1 , idx)) # text width up to idx.
54+ function _find_lastidx (str, width, chars, truncwidth, start)
55+ idx = start
56+ lastidx = idx == 0 ? 0 : prevind (str, idx)
57+ wid = textwidth (SubString (str, 1 , lastidx)) # text width up to lastidx.
10558 if wid ≥ width - truncwidth
106- # ensure that truncidx is correctly set in the main loop
59+ # ensure that truncidx is correctly set in the main loop.
10760 idx = 1
10861 wid = lastidx = 0
10962 end
110- ansi_mask = zero (UInt32) # one-hot encoding of the encountered ansi color characters.
111- # For example, if `ansi_mask == (1 << 7) | (1 << 3) | (1 << 2)`, i.e. if
112- # `ansi_mask == 0b10001100`, then the ansi delimiters number 3 ("blink") and number 2
113- # ("underline") were encountered without their corresponding end delimiter, as well as
114- # an unknown ansi character (represented by the bit in position 7).
63+ truncidx = 0 # if str needs to be truncated, index of truncation.
11564 stop = false # when set, only ansi delimiters will be kept as new characters.
116- firstmatch = 0 # index of the first ansi delimiter
65+ firstmatch = 0 # index of the first ansi delimiter.
66+ noansi = true # set if the substring should be completed with a "\033[0m" delimiter.
11767 while true
11868 str_iter = iterate (str, idx)
11969 isnothing (str_iter) && break
12070 _lastidx = idx
12171 c, idx = str_iter
12272 m = c == ' \0 33' ? match (start_ansi_regex, str, idx) : nothing
12373 stop && isnothing (m) && break
74+ last_lastidx = lastidx
12475 lastidx = _lastidx
12576 if ! isnothing (m)
12677 firstmatch == 0 && (firstmatch = lastidx)
127- ansi_idx = get (ansi_code_index, m. match, Int8 (7 ))
128- if ansi_idx > 0
129- ansi_mask |= (one (UInt32) << (ansi_idx % UInt8)) # set the bit
130- elseif ansi_idx < 0
131- ansi_mask &= ~ (one (UInt32) << (- ansi_idx % UInt8)) # erase the bit
132- else # encountered code "\033[0m" a.k.a. erase all properties
133- ansi_mask = zero (UInt32)
134- end
78+ noansi = m. match == " [0m"
13579 s = sizeof (m. match)
13680 idx += s
137- lastidx += s
81+ lastidx = idx - 1 # the last character of an ansi delimiter is always of size 1.
13882 continue
13983 end
14084 wid += textwidth (c)
141- if wid >= (width - truncwidth) && truncidx == 0
142- truncidx = lastidx
143- end
85+ truncidx == 0 && wid > (width - truncwidth) && (truncidx = last_lastidx)
14486 stop = (wid >= width || c in chars)
14587 end
146- if lastidx < lastindex (str) && truncidx < firstmatch
147- ansi_mask = zero (UInt32) # disregard ansi delimiters if they are truncated away
148- end
149- return lastidx, truncidx, ansi_mask
150- end
151-
152- function find_lastidx_nocolor (str, width, chars, truncwidth)
153- lastidx = 0
154- truncidx = 0
155- idx = 1
156- wid = 0
157- while true
158- str_iter = iterate (str, idx)
159- isnothing (str_iter) && break
160- lastidx = idx
161- c, idx = str_iter
162- wid += textwidth (c)
163- if wid >= (width - truncwidth) && truncidx == 0
164- truncidx = lastidx
165- end
166- (wid >= width || c in chars) && break
167- end
168- return lastidx, truncidx
88+ return lastidx, truncidx, noansi || (lastidx < lastindex (str) && truncidx < firstmatch)
16989end
17090
17191function _truncate_at_width_or_chars (ignore_ansi:: Bool , str, width, chars= " " , truncmark= " …" )
@@ -174,19 +94,15 @@ function _truncate_at_width_or_chars(ignore_ansi::Bool, str, width, chars="", tr
17494 # possible_substring is a subset of str at least as large as the returned string
17595 possible_substring = SubString (str, 1 , thisind (str, min (ncodeunits (str), width+ 1 )))
17696 m = ignore_ansi ? match (possible_ansi_regex, possible_substring) : nothing
177- if isnothing (m)
178- lastidx, truncidx = find_lastidx_nocolor (str, width, chars, truncwidth)
179- ansi_mask = zero (UInt32)
180- else
181- lastidx, truncidx, ansi_mask = find_lastidx_withcolor (str, width, chars, truncwidth, m. offset)
182- end
97+ start_offset = isnothing (m) ? thisind (str, min (ncodeunits (str), width- truncwidth)) : m. offset
98+ lastidx, truncidx, noansi = _find_lastidx (str, width, chars, truncwidth, start_offset)
18399 lastidx == 0 && return " "
184100 str[lastidx] in chars && (lastidx = prevind (str, lastidx))
185101 truncidx == 0 && (truncidx = lastidx)
186102 if lastidx < lastindex (str)
187- return string (SubString (str, 1 , truncidx), iszero (ansi_mask) ? " " : " \0 33[0m" , truncmark)
103+ return string (SubString (str, 1 , truncidx), noansi ? " " : " \0 33[0m" , truncmark)
188104 else
189- return iszero (ansi_mask) ? String (str) : string (str, " \0 33[0m" )
105+ return noansi ? String (str) : string (str, " \0 33[0m" )
190106 end
191107end
192108
0 commit comments