Skip to content

Commit 41b73a8

Browse files
authored
Fix handling of columns and indentation (#183)
1 parent 7a6a304 commit 41b73a8

File tree

2 files changed

+96
-2
lines changed

2 files changed

+96
-2
lines changed

lib/sourceror.ex

+47-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ defmodule Sourceror do
123123
"""
124124
@spec parse_string(String.t(), Keyword.t()) :: {:ok, Macro.t()} | {:error, term()}
125125
def parse_string(source, opts \\ []) do
126-
opts = Keyword.take(opts, [:line, :column])
126+
opts = Keyword.take(opts, [:line, :column, :indentation])
127+
128+
{source, opts} = maybe_apply_columns_fix(source, opts)
127129

128130
with {:ok, quoted, comments} <- string_to_quoted(source, opts ++ to_quoted_opts()) do
129131
{:ok, Sourceror.Comments.merge_comments(quoted, comments)}
@@ -135,12 +137,55 @@ defmodule Sourceror do
135137
"""
136138
@spec parse_string!(String.t()) :: Macro.t()
137139
def parse_string!(source, opts \\ []) do
138-
opts = Keyword.take(opts, [:line, :column])
140+
opts = Keyword.take(opts, [:line, :column, :indentation])
141+
142+
{source, opts} = maybe_apply_columns_fix(source, opts)
139143

140144
{quoted, comments} = string_to_quoted!(source, opts ++ to_quoted_opts())
141145
Sourceror.Comments.merge_comments(quoted, comments)
142146
end
143147

148+
cond do
149+
Version.match?(System.version(), ">= 1.16.0 and < 1.19.0") ->
150+
defp maybe_apply_columns_fix(source, opts) do
151+
{source, opts} =
152+
case Keyword.get(opts, :column) do
153+
start_column when is_integer(start_column) ->
154+
source = String.duplicate(" ", start_column - 1) <> source
155+
opts = Keyword.delete(opts, :column)
156+
{source, opts}
157+
158+
_ ->
159+
{source, opts}
160+
end
161+
162+
apply_indentation_fix(source, opts)
163+
end
164+
165+
Version.match?(System.version(), "< 1.19.0") ->
166+
defp maybe_apply_columns_fix(source, opts) do
167+
apply_indentation_fix(source, opts)
168+
end
169+
170+
true ->
171+
defp maybe_apply_columns_fix(source, opts) do
172+
{source, opts}
173+
end
174+
end
175+
176+
defp apply_indentation_fix(source, opts) do
177+
case Keyword.get(opts, :indentation) do
178+
indentation when is_integer(indentation) ->
179+
opts = Keyword.delete(opts, :indentation)
180+
source = indent(source, " ", indentation - 1)
181+
182+
{source, opts}
183+
184+
_ ->
185+
{source, opts}
186+
end
187+
end
188+
144189
defp to_quoted_opts do
145190
[
146191
literal_encoder: &{:ok, {:__block__, &2, [&1]}},

test/sourceror_test.exs

+49
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,55 @@ defmodule SourcerorTest do
336336
assert {:hello, meta, _} = Sourceror.parse_string!(string, column: 42)
337337
assert meta[:column] == 42
338338
end
339+
340+
test "the column is reset after the first line" do
341+
string = ~S"""
342+
foo do
343+
bar
344+
end
345+
"""
346+
347+
assert {:foo, foo_meta,
348+
[
349+
[{{:__block__, _, [:do]}, {:bar, bar_meta, _}}]
350+
]} = Sourceror.parse_string!(string, column: 10)
351+
352+
assert foo_meta[:column] == 10
353+
# Would be 13 if it didn't reset
354+
assert bar_meta[:column] == 3
355+
end
356+
357+
test "allows setting the indentation" do
358+
string = ~S"""
359+
foo do
360+
bar
361+
end
362+
"""
363+
364+
assert {:foo, foo_meta,
365+
[
366+
[{{:__block__, _, [:do]}, {:bar, bar_meta, _}}]
367+
]} = Sourceror.parse_string!(string, indentation: 5)
368+
369+
assert foo_meta[:column] == 5
370+
assert bar_meta[:column] == 7
371+
end
372+
373+
test "allows setting both column and indentation" do
374+
string = ~S"""
375+
foo do
376+
bar
377+
end
378+
"""
379+
380+
assert {:foo, foo_meta,
381+
[
382+
[{{:__block__, _, [:do]}, {:bar, bar_meta, _}}]
383+
]} = Sourceror.parse_string!(string, column: 10, indentation: 5)
384+
385+
assert foo_meta[:column] == 14
386+
assert bar_meta[:column] == 7
387+
end
339388
end
340389

341390
describe "parse_expression/2" do

0 commit comments

Comments
 (0)