Skip to content

Commit 5a4c03c

Browse files
committed
Handle more incomplete expressions in cursor_context_to_quoted
1 parent 9154c8b commit 5a4c03c

File tree

2 files changed

+39
-16
lines changed

2 files changed

+39
-16
lines changed

lib/elixir/src/elixir_tokenizer.erl

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,10 @@ tokenize([$: | String] = Original, Line, Column, Scope, Tokens) ->
551551
NewScope = maybe_warn_for_ambiguous_bang_before_equals(atom, Unencoded, Rest, Line, Column, Scope),
552552
Token = {atom, {Line, Column, nil}, Atom},
553553
tokenize(Rest, Line, Column + 1 + Length, NewScope, [Token | Tokens]);
554-
empty ->
554+
empty when Scope#elixir_tokenizer.cursor_completion == false ->
555555
unexpected_token(Original, Line, Column, Scope, Tokens);
556+
empty ->
557+
tokenize([], Line, Column, Scope, Tokens);
556558
{error, Reason} ->
557559
error(Reason, Original, Scope, Tokens)
558560
end;
@@ -565,17 +567,24 @@ tokenize([H | T], Line, Column, Scope, Tokens) when ?is_digit(H) ->
565567
case tokenize_number(T, [H], 1, false) of
566568
{error, Reason, Original} ->
567569
error({Line, Column, Reason, Original}, T, Scope, Tokens);
568-
{[I | _], _Number, Original, _Length} when ?is_upcase(I); ?is_downcase(I); I == $_ ->
569-
Msg =
570-
io_lib:format(
571-
"invalid character ~ts after number ~ts. If you intended to write a number, "
572-
"make sure to add the proper punctuation character after the number (space, comma, etc). "
573-
"If you meant to write an identifier, note that identifiers in Elixir cannot start with numbers. "
574-
"Unexpected token: ",
575-
[[I], Original]
576-
),
577-
578-
error({Line, Column, Msg, [I]}, T, Scope, Tokens);
570+
{[I | Rest], Number, Original, _Length} when ?is_upcase(I); ?is_downcase(I); I == $_ ->
571+
if
572+
Number == 0, (I =:= $x) orelse (I =:= $o) orelse (I =:= $b), Rest == [],
573+
Scope#elixir_tokenizer.cursor_completion /= false ->
574+
tokenize([], Line, Column, Scope, Tokens);
575+
576+
true ->
577+
Msg =
578+
io_lib:format(
579+
"invalid character ~ts after number ~ts. If you intended to write a number, "
580+
"make sure to add the proper punctuation character after the number (space, comma, etc). "
581+
"If you meant to write an identifier, note that identifiers in Elixir cannot start with numbers. "
582+
"Unexpected token: ",
583+
[[I], Original]
584+
),
585+
586+
error({Line, Column, Msg, [I]}, T, Scope, Tokens)
587+
end;
579588
{Rest, Number, Original, Length} when is_integer(Number) ->
580589
Token = {int, {Line, Column, Number}, Original},
581590
tokenize(Rest, Line, Column + Length, Scope, [Token | Tokens]);
@@ -679,9 +688,16 @@ tokenize(String, Line, Column, Scope, Tokens) ->
679688
{keyword, Atom, Type, Rest, Length} ->
680689
tokenize_keyword(Type, Rest, Line, Column, Atom, Length, Scope, Tokens);
681690

682-
empty ->
691+
empty when Scope#elixir_tokenizer.cursor_completion == false ->
683692
unexpected_token(String, Line, Column, Scope, Tokens);
684693

694+
empty ->
695+
case String of
696+
[$~, L] when ?is_upcase(L); ?is_downcase(L) -> tokenize([], Line, Column, Scope, Tokens);
697+
[$~] -> tokenize([], Line, Column, Scope, Tokens);
698+
_ -> unexpected_token(String, Line, Column, Scope, Tokens)
699+
end;
700+
685701
{error, Reason} ->
686702
error(Reason, String, Scope, Tokens)
687703
end.

lib/elixir/test/elixir/code_fragment_test.exs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -857,16 +857,14 @@ defmodule CodeFragmentTest do
857857
test "maps and structs" do
858858
assert cc2q("%") == s2q("__cursor__()")
859859
assert cc2q("%{") == s2q("%{__cursor__()}")
860+
assert cc2q("%{bar:") == s2q("%{__cursor__()}")
860861
assert cc2q("%{bar: ") == s2q("%{bar: __cursor__()}")
861862
assert cc2q("%{bar: baz,") == s2q("%{bar: baz, __cursor__()}")
862863

863864
assert cc2q("%Foo") == s2q("__cursor__()")
864865
assert cc2q("%Foo{") == s2q("%Foo{__cursor__()}")
865866
assert cc2q("%Foo{bar: ") == s2q("%Foo{bar: __cursor__()}")
866867
assert cc2q("%Foo{bar: baz,") == s2q("%Foo{bar: baz, __cursor__()}")
867-
868-
assert {:error, {_, "unexpected token: ", "\":\" (column 9, code point U+003A)"}} =
869-
cc2q("%Foo{bar:")
870868
end
871869

872870
test "removes tokens until opening" do
@@ -908,6 +906,15 @@ defmodule CodeFragmentTest do
908906
assert cc2q("foo(bar do :done end |>") == s2q("foo(__cursor__())")
909907
end
910908

909+
test "incomplete expressions" do
910+
assert cc2q("foo(123, :") == s2q("foo(123, __cursor__())")
911+
assert cc2q("foo(123, %") == s2q("foo(123, __cursor__())")
912+
assert cc2q("foo(123, 0x") == s2q("foo(123, __cursor__())")
913+
assert cc2q("foo(123, ~") == s2q("foo(123, __cursor__())")
914+
assert cc2q("foo(123, ~r") == s2q("foo(123, __cursor__())")
915+
assert cc2q("foo(123, ~r/") == s2q("foo(123, __cursor__())")
916+
end
917+
911918
test "options" do
912919
opts = [columns: true]
913920
assert cc2q("foo(", opts) == s2q("foo(__cursor__())", opts)

0 commit comments

Comments
 (0)