Skip to content

Commit 5e20208

Browse files
author
Thomaz Leite
committed
Reimplement IO.ANSI do_format
This avoids copying partial lists, and handles nested improper lists.
1 parent b5cea26 commit 5e20208

File tree

1 file changed

+28
-27
lines changed

1 file changed

+28
-27
lines changed

lib/elixir/lib/io/ansi.ex

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ defmodule IO.ANSI do
154154
["Hello, ", "\e[31m", "\e[1m", "world!", "\e[0m"]
155155
"""
156156
def format(chardata, emit \\ terminal?) do
157-
do_format(chardata, [], emit, :maybe)
157+
do_format(chardata, [], [], emit, :maybe)
158158
end
159159

160160
@doc ~S"""
@@ -174,39 +174,40 @@ defmodule IO.ANSI do
174174
["\e[1m", 87, 111, 114, 100]
175175
"""
176176
def format_fragment(chardata, emit \\ terminal?) do
177-
do_format(chardata, [], emit, false)
177+
do_format(chardata, [], [], emit, false)
178178
end
179179

180-
defp do_format([], buffer, _emit, append_reset) do
181-
if append_reset == true do
182-
Enum.reverse(buffer) ++ [IO.ANSI.reset]
183-
else
184-
Enum.reverse(buffer)
180+
defp do_format([term | rest], rem, acc, emit, append_reset) do
181+
do_format(term, [rest | rem], acc, emit, append_reset)
182+
end
183+
184+
defp do_format(term, rem, acc, true, append_reset) when is_atom(term) do
185+
try do
186+
do_format([], rem, [acc | [apply(IO.ANSI, term, [])]], true, !!append_reset)
187+
rescue
188+
_ in UndefinedFunctionError ->
189+
raise ArgumentError, message: "invalid ANSI sequence specification: #{term}"
185190
end
186191
end
187192

188-
defp do_format(chardata, buffer, emit, append_reset) when not is_list(chardata) do
189-
do_format([chardata], buffer, emit, append_reset)
193+
defp do_format(term, rem, acc, false, append_reset) when is_atom(term) do
194+
do_format([], rem, acc, false, append_reset)
190195
end
191196

192-
defp do_format(chardata, buffer, emit, append_reset) do
193-
[elem|rest] = chardata
194-
195-
cond do
196-
is_atom(elem) and emit ->
197-
try do
198-
do_format(rest, [apply(IO.ANSI, elem, [])|buffer], emit, !!append_reset)
199-
rescue
200-
_ in UndefinedFunctionError ->
201-
raise ArgumentError, message: "invalid ANSI sequence specification: #{elem}"
202-
end
203-
is_atom(elem) and not emit ->
204-
do_format(rest, buffer, emit, append_reset)
205-
is_list(elem) ->
206-
do_format(elem ++ rest, buffer, emit, append_reset)
207-
true ->
208-
do_format(rest, [elem|buffer], emit, append_reset)
209-
end
197+
defp do_format(term, rem, acc, emit, append_reset) when not is_list(term) do
198+
do_format([], rem, [acc | [term]], emit, append_reset)
199+
end
200+
201+
defp do_format([], [next | rest], acc, emit, append_reset) do
202+
do_format(next, rest, acc, emit, append_reset)
203+
end
204+
205+
defp do_format([], [], acc, true, true) do
206+
[acc | IO.ANSI.reset]
207+
end
208+
209+
defp do_format([], [], acc, _emit, _append_reset) do
210+
acc
210211
end
211212

212213
@doc ~S"""

0 commit comments

Comments
 (0)