Skip to content

Commit

Permalink
Align number values to the right
Browse files Browse the repository at this point in the history
  • Loading branch information
msaraiva committed Jan 23, 2022
1 parent 7c0b1ed commit 3722216
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 14 deletions.
51 changes: 38 additions & 13 deletions lib/formatter_plugin.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,35 @@ defmodule Samples.FormatterPlugin do
end)

positions = Enum.reverse(positions)
{rows, widths} = walk(code, 1, 1, positions, [], {[[]], %{}, 0})
last_col_index = map_size(widths) - 1
{rows, cols_info} = walk(code, 1, 1, positions, [], {[[]], %{}, 0})
last_col_index = map_size(cols_info) - 1

for row <- rows do
Enum.map_join(row, " | ", fn
{^last_col_index, value} ->
value
align_value(value, cols_info[last_col_index], true)

{col_index, value} ->
offset = if col_index == 0, do: String.duplicate(" ", column_offset), else: ""
offset <> String.pad_trailing(value, widths[col_index])
offset <> align_value(value, cols_info[col_index], false)
end)
end
|> Enum.join("\n")
end

defp align_value(value, cols_info, last_col?) do
cond do
cols_info.is_number? ->
String.pad_leading(value, cols_info.width)

last_col? ->
value

true ->
String.pad_trailing(value, cols_info.width)
end
end

defp walk("\r\n" <> rest, line, _column, positions, buffer, acc) do
acc = acc |> add_cell(buffer) |> new_line(positions)
walk(rest, line + 1, 1, positions, [], acc)
Expand All @@ -145,23 +158,35 @@ defmodule Samples.FormatterPlugin do
walk(rest, line, column + 1, positions, [<<c::utf8>> | buffer], acc)
end

defp walk(<<>>, _line, _column, _positions, _buffer, {rows, widths, _col_index}) do
{Enum.reverse(rows), widths}
defp walk(<<>>, _line, _column, _positions, _buffer, {rows, cols_info, _col_index}) do
{Enum.reverse(rows), cols_info}
end

defp add_cell({[cells | rows], widths, col_index}, cell) do
defp add_cell({[cells | rows], cols_info, col_index}, cell) do
value = cell |> Enum.reverse() |> to_string() |> String.trim()
width = String.length(value)
widths = Map.update(widths, col_index, width, &max(&1, width))
{[[{col_index, value} | cells] | rows], widths, col_index + 1}
is_number? = is_number?(value)
info = %{width: width, is_number?: is_number?}

cols_info =
Map.update(cols_info, col_index, info, fn info ->
%{width: max(info.width, width), is_number?: info.is_number? or is_number?}
end)

{[[{col_index, value} | cells] | rows], cols_info, col_index + 1}
end

defp is_number?(value) do
value = String.replace(value, "_", "")
match?({_, ""}, Float.parse(value)) or match?({_, ""}, Integer.parse(value))
end

defp new_line({[cells | rows], widths, _col_index}, []) do
{[Enum.reverse(cells) | rows], widths, 0}
defp new_line({[cells | rows], cols_info, _col_index}, []) do
{[Enum.reverse(cells) | rows], cols_info, 0}
end

defp new_line({[cells | rows], widths, _col_index}, _positions) do
{[[] | [Enum.reverse(cells) | rows]], widths, 0}
defp new_line({[cells | rows], cols_info, _col_index}, _positions) do
{[[] | [Enum.reverse(cells) | rows]], cols_info, 0}
end

defp get_code_by_range(code, range) do
Expand Down
2 changes: 1 addition & 1 deletion test/ex_samples_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ defmodule ExSamplesTest do
test "with diferent types" do
samples do
%{} | :string | :integer | :float | :atom | :boolean
types | "some string" | 42 | 14.33 | :foo | true
types | "some string" | 42 | 14.33 | :foo | true
end

assert types.string == "some string"
Expand Down
20 changes: 20 additions & 0 deletions test/formatter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,24 @@ defmodule Samples.FormatterPluginTest do
end
"""
end

test "align columns with numbers to the right" do
code = """
samples do
:id | :name | :currency | :language | :population | :inflation
1 | "Brazil" | "Real (BRL)" | "Portuguese" | 204451000 | 7.70
3 | "Austria" | "Euro (EUR)" | "German" | 8623073 | 2.45
1234 | "Sweden" | "Swedish krona (SEK)" | "Swedish" | 9801616 | 3.60
end
"""

assert Samples.FormatterPlugin.format(code, []) == """
samples do
:id | :name | :currency | :language | :population | :inflation
1 | "Brazil" | "Real (BRL)" | "Portuguese" | 204_451_000 | 7.70
3 | "Austria" | "Euro (EUR)" | "German" | 8_623_073 | 2.45
1234 | "Sweden" | "Swedish krona (SEK)" | "Swedish" | 9_801_616 | 3.60
end
"""
end
end

0 comments on commit 3722216

Please sign in to comment.