Skip to content

Commit e3e4fac

Browse files
committed
Update formatter to look for AST comments
1 parent 9b9e308 commit e3e4fac

File tree

1 file changed

+68
-53
lines changed

1 file changed

+68
-53
lines changed

lib/elixir/lib/code/formatter.ex

Lines changed: 68 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,21 @@ defmodule Code.Formatter do
641641
paren_fun_to_algebra(paren_fun, min_line, max_line, state)
642642
end
643643

644-
defp block_to_algebra({:__block__, _, []}, min_line, max_line, state) do
645-
block_args_to_algebra([], min_line, max_line, state)
644+
defp block_to_algebra({:__block__, meta, args}, _min_line, _max_line, state) when args in [[], [nil]] do
645+
inner_comments = meta[:inner_comments] || []
646+
comments_docs =
647+
Enum.map(inner_comments, fn comment ->
648+
comment = format_comment(comment)
649+
{comment.text, @empty, 1}
650+
end)
651+
652+
docs = merge_algebra_with_comments(comments_docs, @empty)
653+
654+
case docs do
655+
[] -> {@empty, state}
656+
[line] -> {line, state}
657+
lines -> {lines |> Enum.reduce(&line(&2, &1)) |> force_unfit(), state}
658+
end
646659
end
647660

648661
defp block_to_algebra({:__block__, _, [_, _ | _] = args}, min_line, max_line, state) do
@@ -1827,7 +1840,12 @@ defmodule Code.Formatter do
18271840
end
18281841

18291842
{args_docs, comments?, state} =
1830-
quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, arg_to_algebra)
1843+
case args do
1844+
[] ->
1845+
quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, arg_to_algebra)
1846+
_ ->
1847+
quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, arg_to_algebra)
1848+
end
18311849

18321850
cond do
18331851
args_docs == [] ->
@@ -2089,85 +2107,81 @@ defmodule Code.Formatter do
20892107
end
20902108

20912109
## Quoted helpers for comments
2092-
2093-
defp quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, fun) do
2094-
{pre_comments, state} =
2095-
get_and_update_in(state.comments, fn comments ->
2096-
Enum.split_while(comments, fn %{line: line} -> line <= min_line end)
2097-
end)
2098-
2099-
{reverse_docs, comments?, state} =
2100-
if state.comments == [] do
2101-
each_quoted_to_algebra_without_comments(args, acc, state, fun)
2102-
else
2103-
each_quoted_to_algebra_with_comments(args, acc, max_line, state, false, fun)
2104-
end
2110+
defp quoted_to_algebra_with_comments(args, acc, _min_line, _max_line, state, fun) do
2111+
{reverse_docs, comments?, state} = each_quoted_to_algebra_with_comments(args, acc, state, fun, false)
21052112

21062113
docs = merge_algebra_with_comments(Enum.reverse(reverse_docs), @empty)
2107-
{docs, comments?, update_in(state.comments, &(pre_comments ++ &1))}
2114+
2115+
{docs, comments?, state}
21082116
end
21092117

2110-
defp each_quoted_to_algebra_without_comments([], acc, state, _fun) do
2111-
{acc, false, state}
2118+
defp each_quoted_to_algebra_with_comments([], acc, state, _fun, comments?) do
2119+
{acc, comments?, state}
21122120
end
21132121

2114-
defp each_quoted_to_algebra_without_comments([arg | args], acc, state, fun) do
2122+
defp each_quoted_to_algebra_with_comments([arg | args], acc, state, fun, comments?) do
21152123
{doc_triplet, state} = fun.(arg, args, state)
2116-
acc = [doc_triplet | acc]
2117-
each_quoted_to_algebra_without_comments(args, acc, state, fun)
2118-
end
21192124

2120-
defp each_quoted_to_algebra_with_comments([], acc, max_line, state, comments?, _fun) do
2121-
{acc, comments, comments?} = extract_comments_before(max_line, acc, state.comments, comments?)
2122-
{acc, comments?, %{state | comments: comments}}
2123-
end
21242125

2125-
defp each_quoted_to_algebra_with_comments([arg | args], acc, max_line, state, comments?, fun) do
21262126
case traverse_line(arg, {@max_line, @min_line}) do
21272127
{@max_line, @min_line} ->
2128-
{doc_triplet, state} = fun.(arg, args, state)
21292128
acc = [doc_triplet | acc]
2130-
each_quoted_to_algebra_with_comments(args, acc, max_line, state, comments?, fun)
2129+
each_quoted_to_algebra_with_comments(args, acc, state, fun, comments?)
21312130

21322131
{doc_start, doc_end} ->
2133-
{acc, comments, comments?} =
2134-
extract_comments_before(doc_start, acc, state.comments, comments?)
2132+
{leading_comments, trailing_comments} =
2133+
case arg do
2134+
{_, meta, _} ->
2135+
leading_comments = meta[:leading_comments] || []
2136+
trailing_comments = meta[:trailing_comments] || []
2137+
{leading_comments, trailing_comments}
2138+
2139+
{{_, left_meta, _}, {_, right_meta, _}} ->
2140+
leading_comments = left_meta[:leading_comments] || []
2141+
trailing_comments = right_meta[:trailing_comments] || []
2142+
2143+
{leading_comments, trailing_comments}
2144+
_ ->
2145+
{[], []}
2146+
end
21352147

2136-
{doc_triplet, state} = fun.(arg, args, %{state | comments: comments})
2148+
comments? = leading_comments != [] or trailing_comments != []
21372149

2138-
{acc, comments, comments?} =
2139-
extract_comments_trailing(doc_start, doc_end, acc, state.comments, comments?)
2150+
leading_docs = build_leading_comments([], leading_comments, doc_start)
2151+
trailing_docs = build_trailing_comments([], trailing_comments)
21402152

2141-
acc = [adjust_trailing_newlines(doc_triplet, doc_end, comments) | acc]
2142-
state = %{state | comments: comments}
2143-
each_quoted_to_algebra_with_comments(args, acc, max_line, state, comments?, fun)
2153+
doc_triplet = adjust_trailing_newlines(doc_triplet, doc_end, trailing_comments)
2154+
2155+
acc = Enum.concat([trailing_docs, [doc_triplet], leading_docs, acc])
2156+
2157+
each_quoted_to_algebra_with_comments(args, acc, state, fun, comments?)
21442158
end
21452159
end
21462160

2147-
defp extract_comments_before(max, acc, [%{line: line} = comment | rest], _) when line < max do
2148-
%{previous_eol_count: previous, next_eol_count: next, text: doc} = comment
2149-
acc = [{doc, @empty, next} | add_previous_to_acc(acc, previous)]
2150-
extract_comments_before(max, acc, rest, true)
2151-
end
2161+
defp build_leading_comments(acc, [], _), do: acc
21522162

2153-
defp extract_comments_before(_max, acc, rest, comments?) do
2154-
{acc, rest, comments?}
2163+
defp build_leading_comments(acc, [comment | rest], doc_start) do
2164+
comment = format_comment(comment)
2165+
%{previous_eol_count: previous, next_eol_count: next, text: doc, line: line} = comment
2166+
# If the comment is on the same line as the document, we need to adjust the newlines
2167+
# such that the comment is placed right above the document line.
2168+
next = if line == doc_start, do: 1, else: next
2169+
acc = [{doc, @empty, next} | add_previous_to_acc(acc, previous)]
2170+
build_leading_comments(acc, rest, doc_start)
21552171
end
21562172

21572173
defp add_previous_to_acc([{doc, next_line, newlines} | acc], previous) when newlines < previous,
21582174
do: [{doc, next_line, previous} | acc]
21592175

21602176
defp add_previous_to_acc(acc, _previous),
21612177
do: acc
2178+
defp build_trailing_comments(acc, []), do: acc
21622179

2163-
defp extract_comments_trailing(min, max, acc, [%{line: line, text: doc_comment} | rest], _)
2164-
when line >= min and line <= max do
2165-
acc = [{doc_comment, @empty, 1} | acc]
2166-
extract_comments_trailing(min, max, acc, rest, true)
2167-
end
2168-
2169-
defp extract_comments_trailing(_min, _max, acc, rest, comments?) do
2170-
{acc, rest, comments?}
2180+
defp build_trailing_comments(acc, [comment | rest]) do
2181+
comment = format_comment(comment)
2182+
%{previous_eol_count: previous, next_eol_count: next, text: doc} = comment
2183+
acc = [{doc, @empty, next} | acc]
2184+
build_trailing_comments(acc, rest)
21712185
end
21722186

21732187
# If the document is immediately followed by comment which is followed by newlines,
@@ -2179,6 +2193,7 @@ defmodule Code.Formatter do
21792193

21802194
defp adjust_trailing_newlines(doc_triplet, _, _), do: doc_triplet
21812195

2196+
21822197
defp traverse_line({expr, meta, args}, {min, max}) do
21832198
# This is a hot path, so use :lists.keyfind/3 instead Keyword.fetch!/2
21842199
acc =

0 commit comments

Comments
 (0)