Skip to content

Commit 3a2ce69

Browse files
committed
Update formatter to look for AST comments
1 parent 0c799e5 commit 3a2ce69

File tree

1 file changed

+68
-53
lines changed

1 file changed

+68
-53
lines changed

lib/elixir/lib/code/formatter.ex

+68-53
Original file line numberDiff line numberDiff line change
@@ -638,8 +638,21 @@ defmodule Code.Formatter do
638638
paren_fun_to_algebra(paren_fun, min_line, max_line, state)
639639
end
640640

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

645658
defp block_to_algebra({:__block__, _, [_, _ | _] = args}, min_line, max_line, state) do
@@ -1822,7 +1835,12 @@ defmodule Code.Formatter do
18221835
end
18231836

18241837
{args_docs, comments?, state} =
1825-
quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, arg_to_algebra)
1838+
case args do
1839+
[] ->
1840+
quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, arg_to_algebra)
1841+
_ ->
1842+
quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, arg_to_algebra)
1843+
end
18261844

18271845
cond do
18281846
args_docs == [] ->
@@ -2084,85 +2102,81 @@ defmodule Code.Formatter do
20842102
end
20852103

20862104
## Quoted helpers for comments
2087-
2088-
defp quoted_to_algebra_with_comments(args, acc, min_line, max_line, state, fun) do
2089-
{pre_comments, state} =
2090-
get_and_update_in(state.comments, fn comments ->
2091-
Enum.split_while(comments, fn %{line: line} -> line <= min_line end)
2092-
end)
2093-
2094-
{reverse_docs, comments?, state} =
2095-
if state.comments == [] do
2096-
each_quoted_to_algebra_without_comments(args, acc, state, fun)
2097-
else
2098-
each_quoted_to_algebra_with_comments(args, acc, max_line, state, false, fun)
2099-
end
2105+
defp quoted_to_algebra_with_comments(args, acc, _min_line, _max_line, state, fun) do
2106+
{reverse_docs, comments?, state} = each_quoted_to_algebra_with_comments(args, acc, state, fun, false)
21002107

21012108
docs = merge_algebra_with_comments(Enum.reverse(reverse_docs), @empty)
2102-
{docs, comments?, update_in(state.comments, &(pre_comments ++ &1))}
2109+
2110+
{docs, comments?, state}
21032111
end
21042112

2105-
defp each_quoted_to_algebra_without_comments([], acc, state, _fun) do
2106-
{acc, false, state}
2113+
defp each_quoted_to_algebra_with_comments([], acc, state, _fun, comments?) do
2114+
{acc, comments?, state}
21072115
end
21082116

2109-
defp each_quoted_to_algebra_without_comments([arg | args], acc, state, fun) do
2117+
defp each_quoted_to_algebra_with_comments([arg | args], acc, state, fun, comments?) do
21102118
{doc_triplet, state} = fun.(arg, args, state)
2111-
acc = [doc_triplet | acc]
2112-
each_quoted_to_algebra_without_comments(args, acc, state, fun)
2113-
end
21142119

2115-
defp each_quoted_to_algebra_with_comments([], acc, max_line, state, comments?, _fun) do
2116-
{acc, comments, comments?} = extract_comments_before(max_line, acc, state.comments, comments?)
2117-
{acc, comments?, %{state | comments: comments}}
2118-
end
21192120

2120-
defp each_quoted_to_algebra_with_comments([arg | args], acc, max_line, state, comments?, fun) do
21212121
case traverse_line(arg, {@max_line, @min_line}) do
21222122
{@max_line, @min_line} ->
2123-
{doc_triplet, state} = fun.(arg, args, state)
21242123
acc = [doc_triplet | acc]
2125-
each_quoted_to_algebra_with_comments(args, acc, max_line, state, comments?, fun)
2124+
each_quoted_to_algebra_with_comments(args, acc, state, fun, comments?)
21262125

21272126
{doc_start, doc_end} ->
2128-
{acc, comments, comments?} =
2129-
extract_comments_before(doc_start, acc, state.comments, comments?)
2127+
{leading_comments, trailing_comments} =
2128+
case arg do
2129+
{_, meta, _} ->
2130+
leading_comments = meta[:leading_comments] || []
2131+
trailing_comments = meta[:trailing_comments] || []
2132+
{leading_comments, trailing_comments}
2133+
2134+
{{_, left_meta, _}, {_, right_meta, _}} ->
2135+
leading_comments = left_meta[:leading_comments] || []
2136+
trailing_comments = right_meta[:trailing_comments] || []
2137+
2138+
{leading_comments, trailing_comments}
2139+
_ ->
2140+
{[], []}
2141+
end
21302142

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

2133-
{acc, comments, comments?} =
2134-
extract_comments_trailing(doc_start, doc_end, acc, state.comments, comments?)
2145+
leading_docs = build_leading_comments([], leading_comments, doc_start)
2146+
trailing_docs = build_trailing_comments([], trailing_comments)
21352147

2136-
acc = [adjust_trailing_newlines(doc_triplet, doc_end, comments) | acc]
2137-
state = %{state | comments: comments}
2138-
each_quoted_to_algebra_with_comments(args, acc, max_line, state, comments?, fun)
2148+
doc_triplet = adjust_trailing_newlines(doc_triplet, doc_end, trailing_comments)
2149+
2150+
acc = Enum.concat([trailing_docs, [doc_triplet], leading_docs, acc])
2151+
2152+
each_quoted_to_algebra_with_comments(args, acc, state, fun, comments?)
21392153
end
21402154
end
21412155

2142-
defp extract_comments_before(max, acc, [%{line: line} = comment | rest], _) when line < max do
2143-
%{previous_eol_count: previous, next_eol_count: next, text: doc} = comment
2144-
acc = [{doc, @empty, next} | add_previous_to_acc(acc, previous)]
2145-
extract_comments_before(max, acc, rest, true)
2146-
end
2156+
defp build_leading_comments(acc, [], _), do: acc
21472157

2148-
defp extract_comments_before(_max, acc, rest, comments?) do
2149-
{acc, rest, comments?}
2158+
defp build_leading_comments(acc, [comment | rest], doc_start) do
2159+
comment = format_comment(comment)
2160+
%{previous_eol_count: previous, next_eol_count: next, text: doc, line: line} = comment
2161+
# If the comment is on the same line as the document, we need to adjust the newlines
2162+
# such that the comment is placed right above the document line.
2163+
next = if line == doc_start, do: 1, else: next
2164+
acc = [{doc, @empty, next} | add_previous_to_acc(acc, previous)]
2165+
build_leading_comments(acc, rest, doc_start)
21502166
end
21512167

21522168
defp add_previous_to_acc([{doc, next_line, newlines} | acc], previous) when newlines < previous,
21532169
do: [{doc, next_line, previous} | acc]
21542170

21552171
defp add_previous_to_acc(acc, _previous),
21562172
do: acc
2173+
defp build_trailing_comments(acc, []), do: acc
21572174

2158-
defp extract_comments_trailing(min, max, acc, [%{line: line, text: doc_comment} | rest], _)
2159-
when line >= min and line <= max do
2160-
acc = [{doc_comment, @empty, 1} | acc]
2161-
extract_comments_trailing(min, max, acc, rest, true)
2162-
end
2163-
2164-
defp extract_comments_trailing(_min, _max, acc, rest, comments?) do
2165-
{acc, rest, comments?}
2175+
defp build_trailing_comments(acc, [comment | rest]) do
2176+
comment = format_comment(comment)
2177+
%{previous_eol_count: previous, next_eol_count: next, text: doc} = comment
2178+
acc = [{doc, @empty, next} | acc]
2179+
build_trailing_comments(acc, rest)
21662180
end
21672181

21682182
# If the document is immediately followed by comment which is followed by newlines,
@@ -2174,6 +2188,7 @@ defmodule Code.Formatter do
21742188

21752189
defp adjust_trailing_newlines(doc_triplet, _, _), do: doc_triplet
21762190

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

0 commit comments

Comments
 (0)