Skip to content

Commit a618213

Browse files
committed
Support escaping of terminators in uppercase sigils heredocs for consistency, closes #11390
1 parent 58455c1 commit a618213

File tree

5 files changed

+29
-16
lines changed

5 files changed

+29
-16
lines changed

lib/elixir/lib/code/formatter.ex

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ defmodule Code.Formatter do
270270
{doc, state} =
271271
entries
272272
|> prepend_heredoc_line()
273-
|> interpolation_to_algebra(:heredoc, state, @double_heredoc, @double_heredoc)
273+
|> interpolation_to_algebra(~s["""], state, @double_heredoc, @double_heredoc)
274274

275275
{force_unfit(doc), state}
276276

@@ -292,7 +292,7 @@ defmodule Code.Formatter do
292292
{doc, state} =
293293
entries
294294
|> prepend_heredoc_line()
295-
|> list_interpolation_to_algebra(:heredoc, state, @single_heredoc, @single_heredoc)
295+
|> list_interpolation_to_algebra(~s['''], state, @single_heredoc, @single_heredoc)
296296

297297
{force_unfit(doc), state}
298298

@@ -355,7 +355,7 @@ defmodule Code.Formatter do
355355
defp quoted_to_algebra({:__block__, meta, [list]}, _context, state) when is_list(list) do
356356
case meta[:delimiter] do
357357
~s['''] ->
358-
string = list |> List.to_string() |> escape_heredoc()
358+
string = list |> List.to_string() |> escape_heredoc(~s['''])
359359
{@single_heredoc |> concat(string) |> concat(@single_heredoc) |> force_unfit(), state}
360360

361361
~s['] ->
@@ -369,7 +369,7 @@ defmodule Code.Formatter do
369369

370370
defp quoted_to_algebra({:__block__, meta, [string]}, _context, state) when is_binary(string) do
371371
if meta[:delimiter] == ~s["""] do
372-
string = escape_heredoc(string)
372+
string = escape_heredoc(string, ~s["""])
373373
{@double_heredoc |> concat(string) |> concat(@double_heredoc) |> force_unfit(), state}
374374
else
375375
string = escape_string(string, @double_quote)
@@ -1339,7 +1339,7 @@ defmodule Code.Formatter do
13391339
{doc, state} =
13401340
entries
13411341
|> prepend_heredoc_line()
1342-
|> interpolation_to_algebra(:heredoc, state, doc, closing_delimiter)
1342+
|> interpolation_to_algebra(opening_delimiter, state, doc, closing_delimiter)
13431343

13441344
{force_unfit(doc), state}
13451345
else
@@ -1548,11 +1548,13 @@ defmodule Code.Formatter do
15481548
end
15491549
end
15501550

1551-
defp escape_heredoc(string) do
1551+
defp escape_heredoc(string, escape) do
1552+
string = String.replace(string, escape, "\\" <> escape)
15521553
heredoc_to_algebra(["" | String.split(string, "\n")])
15531554
end
15541555

1555-
defp escape_string(string, :heredoc) do
1556+
defp escape_string(string, <<_, _, _>> = escape) do
1557+
string = String.replace(string, escape, "\\" <> escape)
15561558
heredoc_to_algebra(String.split(string, "\n"))
15571559
end
15581560

lib/elixir/src/elixir_interpolation.erl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ extract([$\n | Rest], Buffer, Output, Line, _Column, Scope, Interpol, Last) ->
3737
extract([$\\, Last | Rest], Buffer, Output, Line, Column, Scope, Interpol, Last) ->
3838
extract(Rest, [Last | Buffer], Output, Line, Column+2, Scope, Interpol, Last);
3939

40+
extract([$\\, Last, Last, Last | Rest], Buffer, Output, Line, Column, Scope, Interpol, [Last, Last, Last] = All) ->
41+
extract(Rest, [Last, Last, Last | Buffer], Output, Line, Column+4, Scope, Interpol, All);
42+
4043
extract([$\\, $#, ${ | Rest], Buffer, Output, Line, Column, Scope, true, Last) ->
4144
extract(Rest, [${, $#, $\\ | Buffer], Output, Line, Column+1, Scope, true, Last);
4245

lib/elixir/test/elixir/kernel/binary_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ defmodule Kernel.BinaryTest do
4747
)
4848
end
4949

50+
test "heredoc with heredoc inside interpolation" do
51+
assert """
52+
1
53+
#{"""
54+
2
55+
"""}
56+
""" == "1\n2\n\n"
57+
end
58+
5059
test "UTF-8" do
5160
assert byte_size(" ゆんゆん") == 13
5261
end

lib/elixir/test/elixir/kernel/sigils_test.exs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ bar) in ["foo\\\nbar", "foo\\\r\nbar"]
4242
"""
4343
end
4444

45+
test "sigil S with escaping" do
46+
assert "\"" == ~S"\""
47+
48+
assert "\"\"\"\n" == ~S"""
49+
\"""
50+
"""
51+
end
52+
4553
test "sigil s/S expand to binary when possible" do
4654
assert Macro.expand(quote(do: ~s(foo)), __ENV__) == "foo"
4755
assert Macro.expand(quote(do: ~S(foo)), __ENV__) == "foo"

lib/elixir/test/elixir/string_test.exs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@ defmodule StringTest do
55

66
doctest String
77

8-
test "heredoc with heredoc inside interpolation" do
9-
assert """
10-
1
11-
#{"""
12-
2
13-
"""}
14-
""" == "1\n2\n\n"
15-
end
16-
178
test "next_codepoint/1" do
189
assert String.next_codepoint("ésoj") == {"é", "soj"}
1910
assert String.next_codepoint(<<255>>) == {<<255>>, ""}

0 commit comments

Comments
 (0)