Skip to content

Commit 9d1f7d9

Browse files
committed
Make formatter able to highlight more than one line
1 parent ccfe882 commit 9d1f7d9

File tree

2 files changed

+101
-33
lines changed

2 files changed

+101
-33
lines changed

lib/gradient/anno.ex

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
defmodule Gradient.Anno do
2+
@type anno :: keyword()
3+
@type location :: {non_neg_integer(), pos_integer()}
4+
@type line :: non_neg_integer()
5+
6+
@max_col 1000
7+
8+
@spec end_location(anno()) :: location()
9+
def end_location(anno) when is_list(anno) do
10+
case Keyword.fetch(anno, :end_location) do
11+
{:ok, {line, col}} -> {abs_line(line(anno), line), col}
12+
:error -> line(anno)
13+
end
14+
end
15+
16+
def end_location(anno), do: {line(anno), @max_col}
17+
18+
def end_line(anno) when is_list(anno) do
19+
case Keyword.fetch(anno, :end_location) do
20+
{:ok, {line, _}} -> abs_line(line(anno), line)
21+
:error -> line(anno)
22+
end
23+
end
24+
25+
def end_line(anno), do: line(anno)
26+
27+
@spec line(anno()) :: line()
28+
def line(anno), do: :erl_anno.line(:erl_anno.from_term(anno))
29+
30+
@spec location(anno()) :: location()
31+
def location(anno) do
32+
case :erl_anno.location(:erl_anno.from_term(anno)) do
33+
{line, col} -> {line, col}
34+
line -> {line, 1}
35+
end
36+
end
37+
38+
def abs_line(startl, endl) when startl > endl, do: 2 * startl - endl
39+
def abs_line(_, endl), do: endl
40+
end

lib/gradient/elixir_fmt.ex

+61-33
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ defmodule Gradient.ElixirFmt do
2323
alias Gradient.ElixirType
2424
alias Gradient.ElixirExpr
2525
alias Gradient.Types
26+
alias Gradient.Anno
2627

2728
@type colors_opts() :: [
2829
use_colors: boolean(),
@@ -311,54 +312,81 @@ defmodule Gradient.ElixirFmt do
311312
context
312313
|> Enum.with_index(1)
313314
|> filter_context(anno, 2)
314-
|> underscore_line(anno, opts)
315+
|> maybe_underscore_lines(anno, opts)
315316
|> Enum.join("\n")
316317
end
317318

318-
def filter_context(lines, loc, ctx_size \\ 1) do
319-
line = :erl_anno.line(loc)
320-
range = (line - ctx_size)..(line + ctx_size)
319+
def filter_context(lines, anno, ctx_size \\ 1) do
320+
line = Anno.line(anno)
321+
end_line = Anno.end_line(anno)
322+
range = (line - ctx_size)..(end_line + ctx_size)
321323

322324
Enum.filter(lines, fn {_, number} -> number in range end)
323325
end
324326

325-
def end_location(anno) when is_list(anno) do
326-
Keyword.get(anno, :end_location, :undefined)
327-
end
328-
def end_location(_anno) do
329-
:undefined
330-
end
331-
332-
def underscore_line(lines, anno, opts) do
333-
line = :erl_anno.line(anno)
334-
column = :erl_anno.column(anno)
335-
IO.inspect(column, label: "COLUMN")
336-
endl = end_location(anno)
337-
IO.inspect(endl, label: "END LOCATION")
327+
def maybe_underscore_lines(lines, anno, opts) do
328+
Anno.location(anno) |> IO.inspect(label: "START LOC")
329+
Anno.end_location(anno) |> IO.inspect(label: "END LOC")
338330

339331
Enum.map(lines, fn {str, n} ->
340-
if(n == line) do
332+
if need_underscore?(n, anno) do
341333
colors = get_colors_with_default(opts)
342-
{:ok, use_colors} = Keyword.fetch(colors, :use_colors)
343-
{:ok, color} = Keyword.fetch(colors, :underscored_line)
344-
{bef, aft} = split_at_col(str, column)
345-
indent = to_string(n) <> " " <> bef
346-
347-
[
348-
indent,
349-
[
350-
IO.ANSI.underline(),
351-
IO.ANSI.format_fragment([color, aft], use_colors),
352-
IO.ANSI.reset()
353-
]
354-
]
334+
underscore_line(str, n, anno, colors)
355335
else
356-
to_string(n) <> " " <> str
336+
[to_string(n), " ", str]
357337
end
358338
end)
359339
end
360340

361-
def split_at_col(str, col) when is_integer(col), do: String.split_at(str, col - 1)
341+
def underscore_line(str, n, anno, colors) do
342+
{start_line, start_col} = Anno.location(anno)
343+
{end_line, end_col} = Anno.end_location(anno)
344+
345+
case n do
346+
l when l == start_line and l == end_line ->
347+
{prefix, str} = split_at_col(str, start_col)
348+
{str, suffix} = split_at_col(str, end_col - start_col)
349+
[prefix, make_underscore(str, colors), suffix]
350+
351+
^start_line ->
352+
{prefix, str} = split_at_col(str, start_col)
353+
[prefix, make_underscore(str, colors)]
354+
355+
^end_line ->
356+
{str, suffix} = split_at_col(str, end_col)
357+
[indent, str] = separate_indent(str)
358+
[indent, make_underscore(str, colors), suffix]
359+
360+
_otherwise ->
361+
separate_indent(str)
362+
end
363+
|> add_line_number(n)
364+
end
365+
366+
def add_line_number(iolist, n), do: [to_string(n), " ", iolist]
367+
368+
def separate_indent(str) do
369+
trim_str = String.trim(str)
370+
indent = gen_indent(String.length(str) - String.length(trim_str))
371+
[indent, trim_str]
372+
end
373+
374+
def gen_indent(length), do: Stream.cycle(' ') |> Stream.take(length) |> Enum.to_list()
375+
376+
def make_underscore(text, colors) do
377+
{:ok, use_colors} = Keyword.fetch(colors, :use_colors)
378+
{:ok, color} = Keyword.fetch(colors, :underscored_line)
379+
380+
[
381+
IO.ANSI.underline(),
382+
IO.ANSI.format_fragment([color, text], use_colors),
383+
IO.ANSI.reset()
384+
]
385+
end
386+
387+
def need_underscore?(index, anno), do: index >= Anno.line(anno) && index <= Anno.end_line(anno)
388+
389+
def split_at_col(str, col) when is_integer(col), do: String.split_at(str, col)
362390
def split_at_col(str, _), do: {"", str}
363391

364392
def get_ex_file_path([{:attribute, 1, :file, {path, 1}} | _]), do: {:ok, path}

0 commit comments

Comments
 (0)