Skip to content

Commit bceda78

Browse files
committed
Consider surround context until end whenever possible
1 parent 6d82912 commit bceda78

File tree

2 files changed

+85
-37
lines changed

2 files changed

+85
-37
lines changed

Diff for: lib/elixir/lib/code/fragment.ex

+21-5
Original file line numberDiff line numberDiff line change
@@ -619,15 +619,15 @@ defmodule Code.Fragment do
619619
{reversed_pre, post} = adjust_position(reversed_pre, post)
620620

621621
case take_identifier(post, []) do
622-
{_, [], _} ->
622+
:none ->
623623
maybe_operator(reversed_pre, post, line, opts)
624624

625625
{:identifier, reversed_post, rest} ->
626626
{rest, _} = strip_spaces(rest, 0)
627627
reversed = reversed_post ++ reversed_pre
628628

629629
case codepoint_cursor_context(reversed, opts) do
630-
{{:struct, acc}, offset} ->
630+
{{:struct, acc}, offset} when acc != [] ->
631631
build_surround({:struct, acc}, reversed, line, offset)
632632

633633
{{:alias, acc}, offset} ->
@@ -729,15 +729,31 @@ defmodule Code.Fragment do
729729
do: take_identifier(t, [h | acc])
730730

731731
defp take_identifier(rest, acc) do
732-
with {[?. | t], _} <- strip_spaces(rest, 0),
732+
{stripped, _} = strip_spaces(rest, 0)
733+
734+
with [?. | t] <- stripped,
733735
{[h | _], _} when h in ?A..?Z <- strip_spaces(t, 0) do
734736
take_alias(rest, acc)
735737
else
736-
_ -> {:identifier, acc, rest}
738+
# Consider it an identifier if we are at the end of line
739+
# or if we have spaces not followed by . (call) or / (arity)
740+
_ when acc == [] and (rest == [] or (hd(rest) in @space and hd(stripped) not in ~c"/.")) ->
741+
{:identifier, acc, rest}
742+
743+
# If we are immediately followed by a container, we are still part of the identifier.
744+
# We don't consider << as it _may_ be an operator.
745+
_ when acc == [] and hd(stripped) in ~c"({[" ->
746+
{:identifier, acc, rest}
747+
748+
_ when acc == [] ->
749+
:none
750+
751+
_ ->
752+
{:identifier, acc, rest}
737753
end
738754
end
739755

740-
defp take_alias([h | t], acc) when h not in @non_identifier,
756+
defp take_alias([h | t], acc) when h in ?A..?Z or h in ?a..?z or h in ?0..9 or h == ?_,
741757
do: take_alias(t, [h | acc])
742758

743759
defp take_alias(rest, acc) do

Diff for: lib/elixir/test/elixir/code_fragment_test.exs

+64-32
Original file line numberDiff line numberDiff line change
@@ -428,49 +428,50 @@ defmodule CodeFragmentTest do
428428
end
429429

430430
test "column out of range" do
431-
assert CF.surround_context("hello", {1, 20}) == :none
431+
assert CF.surround_context("hello", {1, 20}) ==
432+
%{begin: {1, 1}, context: {:local_or_var, ~c"hello"}, end: {1, 6}}
432433
end
433434

434435
test "local_or_var" do
435-
for i <- 1..8 do
436+
for i <- 1..9 do
436437
assert CF.surround_context("hello_wo", {1, i}) == %{
437438
context: {:local_or_var, ~c"hello_wo"},
438439
begin: {1, 1},
439440
end: {1, 9}
440441
}
441442
end
442443

443-
assert CF.surround_context("hello_wo", {1, 9}) == :none
444+
assert CF.surround_context("hello_wo ", {1, 10}) == :none
444445

445-
for i <- 2..9 do
446+
for i <- 2..10 do
446447
assert CF.surround_context(" hello_wo", {1, i}) == %{
447448
context: {:local_or_var, ~c"hello_wo"},
448449
begin: {1, 2},
449450
end: {1, 10}
450451
}
451452
end
452453

453-
assert CF.surround_context(" hello_wo", {1, 10}) == :none
454+
assert CF.surround_context(" hello_wo ", {1, 11}) == :none
454455

455-
for i <- 1..6 do
456+
for i <- 1..7 do
456457
assert CF.surround_context("hello!", {1, i}) == %{
457458
context: {:local_or_var, ~c"hello!"},
458459
begin: {1, 1},
459460
end: {1, 7}
460461
}
461462
end
462463

463-
assert CF.surround_context("hello!", {1, 7}) == :none
464+
assert CF.surround_context("hello! ", {1, 8}) == :none
464465

465-
for i <- 1..5 do
466+
for i <- 1..6 do
466467
assert CF.surround_context("안녕_세상", {1, i}) == %{
467468
context: {:local_or_var, ~c"안녕_세상"},
468469
begin: {1, 1},
469470
end: {1, 6}
470471
}
471472
end
472473

473-
assert CF.surround_context("안녕_세상", {1, 6}) == :none
474+
assert CF.surround_context("안녕_세상 ", {1, 6}) == :none
474475

475476
# Keywords are not local or var
476477
for keyword <- ~w(do end after catch else rescue fn true false nil)c do
@@ -484,46 +485,77 @@ defmodule CodeFragmentTest do
484485
end
485486
end
486487

487-
test "local call" do
488+
test "local + operator" do
488489
for i <- 1..8 do
490+
assert CF.surround_context("hello_wo+", {1, i}) == %{
491+
context: {:local_or_var, ~c"hello_wo"},
492+
begin: {1, 1},
493+
end: {1, 9}
494+
}
495+
end
496+
497+
assert CF.surround_context("hello_wo+", {1, 9}) == %{
498+
begin: {1, 9},
499+
context: {:operator, ~c"+"},
500+
end: {1, 10}
501+
}
502+
503+
for i <- 1..9 do
504+
assert CF.surround_context("hello_wo +", {1, i}) == %{
505+
context: {:local_or_var, ~c"hello_wo"},
506+
begin: {1, 1},
507+
end: {1, 9}
508+
}
509+
end
510+
511+
assert CF.surround_context("hello_wo +", {1, 10}) == %{
512+
begin: {1, 10},
513+
context: {:operator, ~c"+"},
514+
end: {1, 11}
515+
}
516+
end
517+
518+
test "local call" do
519+
for i <- 1..9 do
489520
assert CF.surround_context("hello_wo(", {1, i}) == %{
490521
context: {:local_call, ~c"hello_wo"},
491522
begin: {1, 1},
492523
end: {1, 9}
493524
}
494525
end
495526

496-
assert CF.surround_context("hello_wo(", {1, 9}) == :none
527+
assert CF.surround_context("hello_wo(", {1, 10}) == :none
497528

498-
for i <- 1..8 do
529+
for i <- 1..9 do
499530
assert CF.surround_context("hello_wo (", {1, i}) == %{
500531
context: {:local_call, ~c"hello_wo"},
501532
begin: {1, 1},
502533
end: {1, 9}
503534
}
504535
end
505536

506-
assert CF.surround_context("hello_wo (", {1, 9}) == :none
537+
assert CF.surround_context("hello_wo (", {1, 10}) == :none
538+
assert CF.surround_context("hello_wo (", {1, 11}) == :none
507539

508-
for i <- 1..6 do
540+
for i <- 1..7 do
509541
assert CF.surround_context("hello!(", {1, i}) == %{
510542
context: {:local_call, ~c"hello!"},
511543
begin: {1, 1},
512544
end: {1, 7}
513545
}
514546
end
515547

516-
assert CF.surround_context("hello!(", {1, 7}) == :none
548+
assert CF.surround_context("hello!(", {1, 8}) == :none
517549

518-
for i <- 1..5 do
550+
for i <- 1..6 do
519551
assert CF.surround_context("안녕_세상(", {1, i}) == %{
520552
context: {:local_call, ~c"안녕_세상"},
521553
begin: {1, 1},
522554
end: {1, 6}
523555
}
524556
end
525557

526-
assert CF.surround_context("안녕_세상(", {1, 6}) == :none
558+
assert CF.surround_context("안녕_세상(", {1, 7}) == :none
527559
end
528560

529561
test "local arity" do
@@ -651,47 +683,47 @@ defmodule CodeFragmentTest do
651683
end
652684

653685
test "alias" do
654-
for i <- 1..8 do
686+
for i <- 1..9 do
655687
assert CF.surround_context("HelloWor", {1, i}) == %{
656688
context: {:alias, ~c"HelloWor"},
657689
begin: {1, 1},
658690
end: {1, 9}
659691
}
660692
end
661693

662-
assert CF.surround_context("HelloWor", {1, 9}) == :none
694+
assert CF.surround_context("HelloWor ", {1, 10}) == :none
663695

664-
for i <- 2..9 do
696+
for i <- 2..10 do
665697
assert CF.surround_context(" HelloWor", {1, i}) == %{
666698
context: {:alias, ~c"HelloWor"},
667699
begin: {1, 2},
668700
end: {1, 10}
669701
}
670702
end
671703

672-
assert CF.surround_context(" HelloWor", {1, 10}) == :none
704+
assert CF.surround_context(" HelloWor ", {1, 11}) == :none
673705

674-
for i <- 1..9 do
706+
for i <- 1..10 do
675707
assert CF.surround_context("Hello.Wor", {1, i}) == %{
676708
context: {:alias, ~c"Hello.Wor"},
677709
begin: {1, 1},
678710
end: {1, 10}
679711
}
680712
end
681713

682-
assert CF.surround_context("Hello.Wor", {1, 10}) == :none
714+
assert CF.surround_context("Hello.Wor ", {1, 11}) == :none
683715

684-
for i <- 1..11 do
716+
for i <- 1..12 do
685717
assert CF.surround_context("Hello . Wor", {1, i}) == %{
686718
context: {:alias, ~c"Hello.Wor"},
687719
begin: {1, 1},
688720
end: {1, 12}
689721
}
690722
end
691723

692-
assert CF.surround_context("Hello . Wor", {1, 12}) == :none
724+
assert CF.surround_context("Hello . Wor ", {1, 13}) == :none
693725

694-
for i <- 1..15 do
726+
for i <- 1..16 do
695727
assert CF.surround_context("Foo . Bar . Baz", {1, i}) == %{
696728
context: {:alias, ~c"Foo.Bar.Baz"},
697729
begin: {1, 1},
@@ -858,15 +890,15 @@ defmodule CodeFragmentTest do
858890
end: {1, 15}
859891
}
860892

861-
for i <- 2..9 do
893+
for i <- 2..10 do
862894
assert CF.surround_context("%HelloWor", {1, i}) == %{
863895
context: {:struct, ~c"HelloWor"},
864896
begin: {1, 1},
865897
end: {1, 10}
866898
}
867899
end
868900

869-
assert CF.surround_context("%HelloWor", {1, 10}) == :none
901+
assert CF.surround_context("%HelloWor ", {1, 11}) == :none
870902

871903
# With dot
872904
assert CF.surround_context("%Hello.Wor", {1, 1}) == %{
@@ -875,15 +907,15 @@ defmodule CodeFragmentTest do
875907
end: {1, 11}
876908
}
877909

878-
for i <- 2..10 do
910+
for i <- 2..11 do
879911
assert CF.surround_context("%Hello.Wor", {1, i}) == %{
880912
context: {:struct, ~c"Hello.Wor"},
881913
begin: {1, 1},
882914
end: {1, 11}
883915
}
884916
end
885917

886-
assert CF.surround_context("%Hello.Wor", {1, 11}) == :none
918+
assert CF.surround_context("%Hello.Wor ", {1, 12}) == :none
887919

888920
# With spaces
889921
assert CF.surround_context("% Hello . Wor", {1, 1}) == %{
@@ -892,15 +924,15 @@ defmodule CodeFragmentTest do
892924
end: {1, 14}
893925
}
894926

895-
for i <- 2..13 do
927+
for i <- 2..14 do
896928
assert CF.surround_context("% Hello . Wor", {1, i}) == %{
897929
context: {:struct, ~c"Hello.Wor"},
898930
begin: {1, 1},
899931
end: {1, 14}
900932
}
901933
end
902934

903-
assert CF.surround_context("% Hello . Wor", {1, 14}) == :none
935+
assert CF.surround_context("% Hello . Wor ", {1, 15}) == :none
904936
end
905937

906938
test "module attributes" do

0 commit comments

Comments
 (0)