This commit is contained in:
Jeff Clement 2025-03-08 20:32:06 -07:00
parent 6471e799a8
commit 931e9d4aee
Signed by: jeff
GPG key ID: 3BCB43A3F0E1D7DA
93 changed files with 6881 additions and 8 deletions

View file

@ -0,0 +1,96 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Basic folding' do
def self.fold(content)
it("properly folds \n#{content}") do
expect(content).to fold_lines
end
end
fold <<~EOF
defmodule M do # fold
end # fold
"not in fold"
EOF
fold <<~EOF
defmodule M do # fold
def some_func do # fold
end # fold
end # fold
"not in fold"
EOF
fold <<~EOF
defmodule M do
def some_func do # fold
end # fold
end
"not in fold"
EOF
fold <<~EOF
if true do # fold
end # fold
"not in fold"
EOF
fold <<~EOF
if true do # fold
nil # fold
else # fold
nil # fold
end # fold
"not in fold"
EOF
fold <<~EOF
defmodule M do
def some_func do
[ # fold
:hello, # fold
:world # fold
] # fold
:hello_world
end
end
EOF
fold <<~EOF
defmodule M do
def some_func do
{ # fold
:hello, # fold
:world # fold
} # fold
:hello_world
end
end
EOF
fold <<~EOF
defmodule M do
def some_func do
%{ # fold
hello: "a", # fold
world: "b" # fold
} # fold
:hello_world
end
end
EOF
fold <<~EOF
defmodule M do
def some_func do
%User{ # fold
hello: "a", # fold
world: "b" # fold
} # fold
:hello_world
end
end
EOF
end

View file

@ -0,0 +1,89 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting anonymous functions' do
i <<~EOF
def do
some_func = fn x -> x end
end
EOF
i <<~EOF
def do
some_func = function do x -> x end
end
EOF
i <<~EOF
def test do
assert_raise Queue.Empty, fn ->
Q.new |> Q.deq!
end
end
EOF
i <<~EOF
defmodule Test do
def lol do
Enum.map([1,2,3], fn x ->
x * 3
end)
end
end
EOF
i <<~EOF
fizzbuzz = fn
0, 0, _ -> "FizzBuzz"
0, _, _ -> "Fizz"
_, 0, _ -> "Buzz"
_, _, x -> x
end
EOF
i <<~EOF
fizzbuzz = function do
0, 0, _ -> "FizzBuzz"
0, _, _ -> "Fizz"
_, 0, _ -> "Buzz"
_, _, x -> x
end
EOF
i <<~EOF
{:ok, 0} = Mod.exec!(cmd, fn progress ->
if event_handler do
event_handler.({:progress_updated, progress})
end
end
)
EOF
i <<~EOF
defp handle_chunk(:err, line, state) do
update_in(state[:stderr], fn
true -> true
false -> false
end)
Map.update(state, :stderr, [line], &(&1 ++ [line]))
end
EOF
i <<~EOF
defp handle_chunk(:err, line, state) do
update_in(state[:stderr], fn
hello -> :ok
world -> :ok
end)
Map.update(state, :stderr, [line], &(&1 ++ [line]))
end
EOF
i <<~EOF
fn ->
end
EOF
end

View file

@ -0,0 +1,569 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Basic indenting' do
i <<~EOF
defmodule Hello do
EOF
i <<~EOF
defmodule Hello do
def some_func do
EOF
i <<~EOF
defmodule Hello do
def some_func do
end
EOF
i <<~EOF
defmodule Hello do
def some_func do
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
IO.puts "hello world"
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
IO.puts "hello world"
end
def some_other_func do
IO.puts "hello world"
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
IO.puts "hello world"
end
def some_other_func do
IO.puts "hello world"
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
IO.puts "hello world"
end
def some_other_func do
IO.puts "hello world"
IO.puts "hello world"
IO.puts "hello world"
IO.puts "hello world"
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
IO.puts "hello world"
end
def some_other_func do
if blah? do
blah
else
not_blah
end
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
IO.puts "hello world"
end
def some_other_func do
if blah? do
blah
else
not_blah
end
if blah? do
blah
else
not_blah
end
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
IO.puts "hello world"
end
def some_other_func do
if blah? do
blah
if blah? do
blah
else
not_blah
end
else
not_blah
end
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
cond do
{:abc} -> false
_ -> true
end
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
cond do
{:abc} -> false
_ -> true
end
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
cond do
{:abc} ->
say_hello
say_goodbye
_ ->
say_hello
say_goodbye
end
end
end
EOF
i <<~EOF
defmodule Hello.World do
def some_func do
cond do
{:abc} ->
cond do
{:abc} ->
say_hello
say_goodbye
_ ->
say_hello
say_goodbye
end
say_hello
say_goodbye
_ ->
say_hello
say_goodbye
end
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
case word do
:one -> :two
:high -> :low
end
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
case word do
:one -> :two
:high -> :low
end
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
case word do
:one ->
:two
:high ->
:low
end
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
case word do
:one ->
case word do
:one ->
:two
:high ->
:low
end
:two
:high ->
:low
end
end
end
EOF
i <<~EOF
defmodule Hello do
defmacro hello do
quote do
blah
end
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
unless blah do
blah
end
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
if stinky?, do: clean
if smelly?, do: clean
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
name =
"one"
street =
"two"
end
end
EOF
%w(= == === != !== <= >= <> && || + - * / ~~~ ^^^ <<< >>> ||| &&&).each do |bin_op|
i <<~EOF
defmodule Hello do
def hello do
name #{bin_op}
"one"
street #{bin_op}
"two"
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
name #{bin_op} "one"
street #{bin_op} "two"
end
end
EOF
end
i <<~EOF
defmodule Hi do
def hi do
fn hello ->
:world
end
end
end
EOF
i <<~EOF
defmodule Hello do
def hello do
name = "one"
street = "two"
end
end
EOF
i <<~EOF
defmodule Hi do
def hi do
fn hello -> :world end
fn hello -> :world end
end
end
EOF
i <<~EOF
defmodule Hi do
def hi do
fn hello ->
case hello do
:one ->
case word do
:one ->
:two
:high ->
:low
end
:two
:high ->
:low
end
end
end
end
EOF
i <<~EOF
hello =
"str"
|> Pipe.do_stuff
|> Pipe.do_stuff
|> Pipe.do_stuff
|> Pipe.do_stuff(fn ->
more stuff
end)
|> Pipe.do_stuff
EOF
i <<~EOF
defmodule Hi do
defp hi do
:hello
end
defp hi do
:hello
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
[
:one,
:two,
fn ->
:three
end,
:four
]
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
{
:one,
:two,
fn ->
:three
end,
:four
}
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
%Struct{
:one,
:two,
fn ->
:three
end,
:four
}
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
%{
:one,
:two,
fn ->
:three
end,
:four
}
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
try do
raise "boom"
rescue
e in errs ->
IO.puts "one"
_ ->
IO.puts "one"
end
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
try do
raise "wtf"
catch
e ->
IO.puts "one"
_ ->
IO.puts "one"
end
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
receive do
{:hello, world} ->
:ok
after
1000 ->
IO.puts "one"
2000 ->
IO.puts "one"
end
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
receive do
{:hello, world} ->
:ok
_ ->
:err
end
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
fn
:ok ->
IO.puts :ok
_ ->
IO.puts :err
end
end
end
EOF
i <<~EOF
defmodule Hi do
defp hi do
fn
:ok -> IO.puts :ok
_ -> IO.puts :err
end
end
end
EOF
i <<~EOF
fun2 = fn :foo ->
:bar
'end'
end
EOF
i <<~EOF
fun2 = fn :foo ->
:bar
'end'
end
EOF
i <<~EOF
fun3 = fn :foo ->
:bar
:send
end
EOF
i <<~EOF
defmodule Hi do
def hello_world do
"end"
'end'
end
EOF
end

View file

@ -0,0 +1,60 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Binary operators' do
i <<~EOF
word =
"h"
<> "e"
<> "l"
<> "l"
<> "o"
IO.puts word
EOF
i <<~EOF
def hello do
expected = "hello"
<> "world"
IO.puts expected
end
EOF
i <<~EOF
def hello do
expected =
"hello"
<> "world"
IO.puts expected
end
EOF
i <<~EOF
alias Rumbl.Repo
alias Rumbl.Category
for category <- ~w(Action Drama Romance Comedy Sci-fi) do
Repo.get_by(Category, name: category) ||
Repo.insert!(%Category{name: category})
end
EOF
i <<~EOF
data = [
"blah",
"blah2", # *
"blah3"
]
EOF
i <<~EOF
data = [
"blah",
# +
"blah2",
"blah3"
]
EOF
end

View file

@ -0,0 +1,109 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting blocks' do
i <<~EOF
do
something
end
EOF
i <<~EOF
defmodule Test do
def lol do
IO.inspect :end
end
end
EOF
i <<~EOF
defmodule Hello do
def name, do: IO.puts "bobmarley"
# expect next line starting here
def name(param) do
param
end
end
EOF
i <<~EOF
defmodule Hello do
def name, do: IO.puts "bobmarley"
def name(param) do
param
end
end
EOF
i <<~EOF
def f do
if true, do: 42
end
EOF
i <<~EOF
def f do
x = :do
end
EOF
i <<~EOF
defmodule Test do
def test do
one =
user
|> build_assoc(:videos)
|> Video.changeset()
other =
user2
|> build_assoc(:videos)
|> Video.changeset()
end
end
EOF
i <<~EOF
defmodule MyMod do
def how_are_you do
IO.puts "I'm filling bad :("
IO.puts "really bad"
end
end
EOF
i <<~EOF
defmodule MyMod do
def how_are_you do
"function return"
end
end
EOF
i <<~EOF
scope "/", API do
pipe_through :api # Use the default browser stack
get "/url", Controller, :index
post "/url", Controller, :create
end
EOF
i <<~EOF
def hello do
{:ok, _} = TaskRunner.TaskStore.start_link(name: @task_store)
{:ok, _} = Workspace.start_link
{:ok, pending_task_sup} = TaskRunner.PendingTaskSupervisor.start_link
end
EOF
i <<~EOF
def handle_info(:tick, state = %{policy_iteration: []}) do
state = put_in(state[:policy_iteration], state.policy)
{:noreply, state}
end
EOF
end

View file

@ -0,0 +1,111 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting case statements' do
i <<~EOF
case some_function do
:ok ->
:ok
{ :error, :message } ->
{ :error, :message }
end
EOF
i <<~EOF
case Connection.open(rabbitmq) do
{:ok, conn} ->
Woody.info "CONNECTION_SUCCESSFUL"
{:ok, chan} = Channel.open(conn)
{:error, error} ->
Woody.info "CONNECTION_FAILED"
:timer.sleep(10000)
end
EOF
i <<~EOF
defmodule M do
defp _fetch(result, key, deep_key) do
case _fetch(result, key) do
{:ok, val} ->
case _fetch(val, deep_key) do
:error -> {:error, :deep}
res -> res
end
:error -> {:error, :shallow}
end
end
EOF
i <<~EOF
case Connection.open(rabbitmq) do
{:ok, conn} ->
Woody.info "CONNECTION_SUCCESSFUL"
{:ok, chan} = Channel.open(conn)
{:error, error} ->
Woody.info "CONNECTION_FAILED"
:timer.sleep(10000)
end
EOF
i <<~'EOF'
decoded_msg = case JSON.decode(msg) do
{:error, _} ->
a = "a"
b = "dasdas"
">#{a}<>#{b}<"
{:ok, decoded} -> decoded
end
EOF
i <<~EOF
case Repo.insert(changeset) do
{:ok, user} ->
conn
|> put_flash(:info, "%{user.name} created!")
|> redirect(to: user_path(conn, :index))
{:error, changeset} ->
render(conn, "new.html", changeset: changeset)
end
EOF
i <<~EOF
case st do
sym ->
code = if true do
:ok
else
:error
end
Logger.info(code)
st
end
EOF
i <<~EOF
case world do
"apple" ->
IO.puts "its an apple"
IO.puts "no really, its an apple"
"orange" ->
IO.puts "its not an apple"
IO.puts "believe it or not"
end
EOF
i <<~EOF
case o do
a ->
e(fn -> f end)
end
EOF
i <<~EOF
case pattern do
:* -> :ok
_ -> :error
end
EOF
end

View file

@ -0,0 +1,56 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting *after* comments' do
i <<~EOF
# do
IO.puts :test
EOF
i <<~EOF
defmodule Foo do
def run do
list =
File.read!("/path/to/file")
|> String.split()
# now start a new line
# used to start here
# but now starts here
end
end
EOF
i <<~EOF
defmodule Foo do
def run(task) when task in [:t1, :t2] do
end
# now starts a new line
# use to start here
# but now starts here
end
EOF
i <<~EOF
receive do
{{:lock_ready, ^key}, ^pid} ->
after
# NOTE: @jbodah 2017-03-28: we should do some math to adjust the timeout
timeout ->
{:error, :timed_out_waiting_for_lock}
end
EOF
it "bulk indenting comments" do
expect(<<~EOF).to be_elixir_indentation
defmodule Test do
# SELECT *
# FROM table
# WHERE column = 123
# AND another_column = 456
end
EOF
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting cond statements' do
i <<~EOF
cond do
foo -> 1
bar -> 2
end
EOF
end

View file

@ -0,0 +1,28 @@
require 'spec_helper'
describe 'def indentation' do
i <<~EOF
def handle_call({:release_lock, key}, _from, state) do
case get_lock(state, key) do
nil ->
{:reply, {:error, :already_unlocked}, state}
_ ->
new_state = delete_lock(state, key)
{:reply, :ok, new_state}
end
end
def
EOF
i <<~EOF
defmodule Hello do
def hello do
end
#{"\n" * 40}
def world do
end
end
EOF
end

View file

@ -0,0 +1,34 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting documentation' do
i <<~EOF
defmodule Test do
@doc """
end
"""
end
EOF
it "bulk indenting doc blocks" do
expect(<<~EOF).to be_elixir_indentation
defmodule Test do
@doc """
do not reindent
any indent that i do
please
"""
end
EOF
end
i <<~EOF
defmodule Test do
@doc """
it should
have reasonable
default start indent when typed
"""
EOF
end

View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting Ecto queries' do
i <<~EOF
defmodule New do
def do_query do
from user in Users,
select: user.name,
join: signup in Signups, where: user.id == signup.user_id
end
end
EOF
i <<~EOF
def smth do
from = 1
to = 7
end
EOF
i <<~EOF
fromin,
EOF
i <<~EOF
query = from u in query, select: u.city
EOF
i <<~EOF
def do_query do
where = [category: "fresh and new"]
order_by = [desc: :published_at]
select = [:id, :title, :body]
from Post, where: ^where, order_by: ^order_by, select: ^select
end
EOF
i <<~EOF
def alphabetical(query) do
from c in query, order_by: c.name
end
EOF
end

View file

@ -0,0 +1,26 @@
require 'spec_helper'
describe 'EctoEnum' do
i <<~EOF
defmodule Onemedical.Types do
import EctoEnum
defenum(Work.Occupation, :work_occupation, [
:actor, :architect, :athlete, :baker, :bank_clerk, :banker, :barber, :blogger,
:bricklayer, :broadcaster, :builder, :captain, :carpenter, :choreographer,
:computer_engineer, :computer_programmer, :custom_officer, :dancer, :designer,
:director, :doctor, :driver, :editor, :entertainer, :engineer, :facility_manager,
:farmer, :fashion_designer, :geologist, :goldsmith, :graphic_designer, :hairdresser,
:host_hostess, :house_girl, :interior_designer, :judge, :land_surveyor, :lecturer,
:make_up_artist, :manager, :mechanic, :midwife, :model, :music_director, :musician,
:nanny, :nurse, :pastor, :paediatrician, :photographer, :physicist, :pilot, :plumber,
:police_officer, :printer, :producer, :publisher, :quality_inspector, :radiographer,
:real_estate_agent, :referee, :refuse_collector, :registrar, :safety_engineer, :sales_manager,
:script_writer, :secretary, :security_guard, :shoemaker, :songwriter, :sound_engineer,
:stock_broker, :surveyor, :tailor, :teacher, :telecommunications_engineer, :usher,
:waiter, :writer, :zookeeper, :other])
defenum(Work.Type, :work_type, [
:full_time, :part_time, :volunteer, :temporary
])
end
EOF
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting eelixir' do
it 'anonymous function' do
expect(<<~EOF).to be_eelixir_indentation
<%= form_for @changeset, user_path(@conn, :create), fn f -> %>
It is obviously true
<% end %>
EOF
end
it 'if..do..end' do
expect(<<~EOF).to be_eelixir_indentation
<%= if true do %>
It is obviously true
<% end %>
EOF
end
it 'if..do..else..end' do
expect(<<~EOF).to be_eelixir_indentation
<%= if true do %>
It is obviously true
<% else %>
This will never appear
<% end %>
EOF
end
end

View file

@ -0,0 +1,263 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting embedded views' do
i <<~EOF
def render(assigns) do
~L"""
<div>
Some content
</div>
"""
end
EOF
i <<~EOF
def render(assigns) do
~H"""
<div class="theres a-/ in the class names from tailwind">
<div class="some more classes">
This is immediately nested
<div>
<input type="number" value="2" />
There's a self-closing tag
</div>
</div>
</div>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<div id="123456">
Some content
</div>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<div
id="123456"
>
Some content
</div>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<div />
<p>Some paragraph</p>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<div>
it
<div>
keeps
<div>
nesting
</div>
</div>
</div>
"""
end
EOF
i <<~EOF
def render(assgins) do
~L"""
<div>
<%= for i <- iter do %>
<div><%= i %></div>
<% end %>
</div>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<%= live_component @socket,
Component,
id: "<%= @id %>",
user: @user do
%>
<main>
<header>
<h1>Some Header</h1>
</header>
<section>
<h1>Some Section</h1>
<p>
I'm some text
</p>
</section>
</main>
<% end %>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<%= render_component,
@socket,
Component do %>
<p>Multi-line opening eex tag that takes a block</p>
<% end %>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<div>
<%= render_component,
@socket,
Component %>
</div>
<%= render_component,
@socket,
Component %>
<p>Multi-line single eex tag</p>
"""
end
EOF
i <<~EOF
def render(assigns) do
~H"""
<Component
foo={{
foo: [
'one',
'two',
'three'
],
bar: %{
"foo" => "bar"
}
}}
/>
"""
end
EOF
i <<~EOF
def render(assigns) do
~L"""
<%= live_component @socket,
Component,
id: "<%= @id %>",
team: @team do
%>
<div>
<div>
<div>
A deeply nested tree
<div>
with trailing whitespace
</div>
</div>
</div>
</div>
<div id="id-ends-with-greater-than->"
propWithEexTag="<%= @id %>"
anotherProp="foo"
/>
<%= for i <- iter do %>
<div><%= i %></div>
<% end %>
<div
opts={{
opt1: "optA",
opt2: "optB"
}}
id="hi"
bye="hi" />
<ul>
<li :for={{ item <- @items }}>
{{ item }}
</li>
</ul>
<div id="hi">
Hi <p>hi</p>
I'm ok, ok?
<div>
hi there!
</div>
<div>
<div>
<p>hi</p>
<hr />
</div>
</div>
</div>
<Some.Surface.Component />
<Another
prop="prop"
prop2="prop2"
>
<div>content</div>
</Another>
<div foo />
<div>hi</div>
<div>
<div>
content
</div>
<div />
<div>
content in new div after a self-closing div
</div>
</div>
<p
id="<%= @id %>"
class="multi-line opening single letter p tag"
>
<%= @solo.eex_tag %>
<Nested
prop="nested"
>
content
</Nested>
</p>
<% end %>
"""
end
EOF
end

View file

@ -0,0 +1,32 @@
require 'spec_helper'
describe 'exunit' do
i <<~EOF
test "test" do
Mod.fun(fn ->
map = %Mod.Map{
id: "abc123",
state: "processing",
submod: %Mod.Submod{
options: %{}
}
}
EOF
i <<~EOF
test "test" do
Mod.fun(fn ->
map = %Mod.Map{
id: "abc123",
fun: fn ->
IO.inspect :hello
IO.inspect %{
this_is: :a_map
}
end,
submod: %Mod.Submod{
options: %{}
}
}
EOF
end

View file

@ -0,0 +1,41 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting if clauses' do
i <<~EOF
if foo do
bar
end
EOF
i <<~EOF
if foo do
bar
else
baz
end
EOF
i <<~EOF
def test do
"else"
end
EOF
i <<~EOF
if true do
else
end
EOF
i <<~EOF
def exec(command, progress_func \\ fn(_, state) -> state end, key \\ nil, output \\ nil) do
if key do
with_cache(key, output, fn -> do_exec(command, progress_func) end)
else
do_exec(command, progress_func)
end
end
EOF
end

View file

@ -0,0 +1,29 @@
require 'spec_helper'
describe 'Keywords' do
i <<~EOF
def handle_call({:get_in_line_for_lock, key}, from, state) do
queue = state[:queues][key] || :queue.new
queue = queue.in(from, queue)
hello
end
EOF
# Has cond in milliseconds
i <<~EOF
if arg[:arg] do
finish_time = Timex.Duration.now
start_time = Mod.Mod.arg(@attr, fun(state))
duration = Timex.Duration.diff(finish_time, start_time, :milliseconds)
Mod.fun(:arg, arg, arg: arg, arg: arg, arg)
e
EOF
i <<~EOF
Logger.metadata(
task_id: state.recipe.task_id,
hashed_id: state.recipe.config.some_id,
task
)
EOF
end

View file

@ -0,0 +1,205 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting lists' do
i <<~EOF
def example do
[ :foo,
:bar,
:baz ]
end
EOF
i <<~EOF
[
[
:foo
]
]
EOF
i <<~EOF
def project do
[ name: "mix",
version: "0.1.0",
deps: deps ]
end
EOF
i <<~EOF
def config do
[ name:
"John" ]
end
EOF
i <<~EOF
def test do
[ { :cowboy, github: "extend/cowboy" },
{ :dynamo, "0.1.0-dev", github: "elixir-lang/dynamo" },
{ :ecto, github: "elixir-lang/ecto" },
{ :pgsql, github: "semiocast/pgsql" } ]
end
EOF
i <<~EOF
def test do
[ [:a, :b, :c],
[:d, :e, :f] ]
end
EOF
i <<~EOF
def test do
[ app: :first,
version: "0.0.1",
dynamos: [First.Dynamo],
compilers: [:elixir, :dynamo, :ecto, :app],
env: [prod: [compile_path: "ebin"]],
compile_path: "tmp/first/ebin",
deps: deps ]
end
EOF
i <<~EOF
def project do
[
{ :bar, path: "deps/umbrella/apps/bar" },
{ :umbrella, path: "deps/umbrella" }
]
end
EOF
i <<~EOF
def test do
a = [
%{
foo: 1,
bar: 2
}
]
b = %{
[
:foo,
:bar
]
}
[
a,
b
]
end
EOF
i <<~EOF
def create(conn, %{
"grant_type" => "password",
"username" => username,
"password" => password
}) do
1
end
EOF
i <<~EOF
def double(x) do
add(
x,
y
)
end
EOF
i <<~EOF
def double(x) do
add(
x,
y,
w,
z
)
end
EOF
i <<~EOF
def double(x) do
result = add(
x,
z
)
div(result, 2)
end
EOF
i <<~EOF
defmodule Module do
@person1 { name: "name",
age: 18,
enabled?: true }
@person2 { name: "other name",
age: 21,
enabled?: false }
end
EOF
i <<~EOF
def test_another_feature do
assert json_response(conn, 200) == %{
"results" => [
%{
"id" => result.id,
}
]
}
end
EOF
i <<~EOF
defmodule Mod do
def test do
foo == %{
}
assert json_response == %{
"id" => "identifier"
}
end
end
EOF
i <<~EOF
defmodule Mod do
def fun do
json_logger = Keyword.merge(Application.get_env(:logger, :json_logger, []), options)
Application.put_env(:logger, :json_logger, json_logger)
level = Keyword.get(json_logger, :level)
%{level: level, output: :console}
end
end
EOF
i <<~EOF
defmodule Mod do
def fun do
Enum.each(s.routing_keys, fn k -> Queue.bind(chan, s.queue, s.exchange, routing_key: k) end)
Basic.consume(chan, s.queue, nil, no_ack: true)
end
end
EOF
i <<~EOF
def init(_) do
children = [
worker(QueueSet, [[name: @queue_set]]),
worker(Producer, [[name: @producer]]),
worker(ConsumerSupervisor, [[{@producer, max_demand: @max_executors}]])
]
supervise(children, strategy: :one_for_one)
end
EOF
end

View file

@ -0,0 +1,13 @@
require 'spec_helper'
describe 'Macros' do
i <<~EOF
defmodule DeadboltTest do
use ExUnit.Case
doctest Deadbolt
hello
end
EOF
end

View file

@ -0,0 +1,47 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Map indent' do
i <<~'EOF'
DrMock.mock(fn ->
params = %{
}
end)
EOF
i <<~EOF
x = %{
foo: :bar
}
y = :foo
EOF
i <<~EOF
x =
%{ foo: :bar }
y = :foo
EOF
i <<~EOF
x = %{
foo: :bar }
y = :foo
EOF
i <<~EOF
test "test" do
Mod.fun(fn ->
map = %Mod.Map{
id: "abc123",
state: "processing",
submod: %Mod.Submod{
options: %{}
}
}
EOF
end

View file

@ -0,0 +1,145 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting pipeline' do
i <<~EOF
"a,b,c,d"
|> String.split(",")
|> Enum.reverse
EOF
i <<~EOF
[ h | t ] = "a,b,c,d"
|> String.split(",")
|> Enum.reverse
EOF
i <<~EOF
def test do
[ h | t ] = "a,b,c,d"
|> String.split(",")
|> Enum.reverse
{ :ok, h }
end
EOF
i <<~EOF
def test do
my_post = Post
|> where([p], p.id == 10)
|> where([p], u.user_id == 1)
|> select([p], p)
end
EOF
i <<~EOF
def test do
"a,b,c,d"
|> String.split(",")
|> Enum.first
|> case do
"a" -> "A"
_ -> "Z"
end
end
EOF
i <<~EOF
defrecord RECORD, field_a: nil, field_b: nil
rec = RECORD.new
|> IO.inspect
EOF
i <<~EOF
defmodule MyMod do
def export_info(users) do
{:ok, infos} = users
|> Enum.map(fn (u) -> do_something(u) end)
|> Enum.map(fn (u) ->
do_even_more(u)
end)
|> finall_thing
infos
end
end
EOF
i <<~EOF
def build_command(input, output) do
"embedded=here"
|>
end
EOF
i <<~EOF
def build_command(input, output) do
'embedded=here'
|>
EOF
i <<~EOF
def build_command(input, output) do
%{:hello => :world}
|>
end
EOF
%w(<= >= == != === !== =~).each do |op|
i <<~EOF
def build_command(input, output) do
true #{op} false
|> IO.inspect
end
EOF
end
i <<~EOF
upcased_names = names
|> Enum.map(fn name ->
String.upcase(name)
end)
IO.inspect names
EOF
i <<~EOF
upcased_names = names
|> Enum.map(fn name ->
String.upcase(name) end)
IO.inspect names
EOF
i <<~EOF
upcased_names = names
|> Enum.map(fn name ->
String.upcase(name)
end)
|> do_stuff
EOF
i <<~EOF
def hello do
do_something
|> Pipe.to_me
{:ok}
end
EOF
i <<~EOF
defmodule MyModule do
def do_stuff do
name =
"Dr. Zaius"
|> determine_name
hello
end
end
EOF
end

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting quote statements' do
i <<~EOF
defmacro foo do
quote do
unquote(foo)
end
end
EOF
i <<~EOF
defmacro foo do
if 1 = 1 do
quote do
unquote(foo)
end
end
end
EOF
end

View file

@ -0,0 +1,22 @@
require 'spec_helper'
describe 'receive indent' do
i <<~EOF
receive do
after
end
EOF
i <<~EOF
def obtain_lock(pid, key, timeout \\ 60_000) do
case GenServer.call(pid, {:obtain_lock, key}) do
:will_notify ->
receive do
after
timeout ->
end
res -> res
end
end
EOF
end

View file

@ -0,0 +1,18 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting strings' do
it "bulk indenting strings" do
expect(<<~EOF).to be_elixir_indentation
defp sql do
"""
SELECT *
FROM table
WHERE column = 123
AND another_column = 456
"""
end
EOF
end
end

View file

@ -0,0 +1,23 @@
require 'spec_helper'
describe 'defstruct' do
i <<~EOF
defmodule A do
defmodule State do
defstruct field: nil, field: nil, field: nil,
field: [], field: nil, field: 0,
field: false, field: %{}
end
defmodule State do
defstruct field: nil, field: nil, field: nil
end
defmodule State do
defstruct field: nil,
field: [],
field: false
end
end
EOF
end

View file

@ -0,0 +1,41 @@
require 'spec_helper'
describe 'try indent' do
i <<~EOF
try do
rescue
end
EOF
i <<~EOF
try do
catch
end
EOF
i <<~EOF
try do
after
end
EOF
i <<~EOF
test "it proceses the command" do
out = "testfile"
try do
cmd = "thing \#{@test_file} \#{out}"
{:ok, 0, _} = Thing.exec(cmd)
after
File.rm!(out)
end
end
EOF
i <<~EOF
try do
foo()
else
value -> value
end
EOF
end

View file

@ -0,0 +1,29 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Indenting tuples' do
i <<~EOF
def xpto do
{ :a,
:b,
:c }
end
EOF
i <<~EOF
def method do
{
:bar,
path: "deps/umbrella/apps/bar"
}
end
EOF
i <<~EOF
x = [
{:text, "asd {"},
{:text, "qwe"},
]
EOF
end

View file

@ -0,0 +1,121 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'with' do
i <<~EOF
with {:ok, msg} <- Msgpax.unpack(payload) do
{:ok, rebuild(msg)}
else
error -> error
end
EOF
i <<~EOF
with {:ok, width} <- Map.fetch(opts, :width),
double_width = width * 2,
{:ok, height} <- Map.fetch(opts, :height)
do
{:ok, double_width * height}
end
EOF
i <<~EOF
with {:ok, width} <- Map.fetch(opts, :width),
double_width = width * 2,
{:ok, height} <- Map.fetch(opts, :height),
do: {:ok, double_width * height}
EOF
i <<~EOF
with {:ok, width} <- Map.fetch(opts, :width),
{:ok, height} <- Map.fetch(opts, :height)
do
{:ok, width * height}
else
:error ->
{:error, :wrong_data}
end
EOF
i <<~EOF
with {:ok, width} <- Map.fetch(opts, :width),
{:ok, height} <- Map.fetch(opts, :height),
do:
{:ok,
width * height * height * height * height * height * height * height * height * height *
height * height * height * height * height * height * height},
else: (:error -> {:error, :wrong_data})
EOF
i <<~'EOF'
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config
import_config "#{Mix.env}.exs"
EOF
i <<~'EOF'
with {:ok, %File.Stat{size: size}} when size > 0 <- File.stat(first_frame_path) do
File.rename(first_frame_path, output_path)
{:ok, %Result{path: output_path}}
else
error ->
{:error, error}
end
EOF
i <<~'EOF'
def resend_confirmation(username) when is_binary(username) do
with user = %User{confirmed_at: nil} <- get_by(username: username) do
{:ok, user} =
user
|> DB.add_confirm_token
|> update_user()
Log.info(%Log{user: user.id, message: "send new confirmation"})
send_welcome(user)
{:ok, user}
else
nil ->
{:error, "not found"}
%User{email: email} ->
Email.already_confirmed(email)
{:error, "already confirmed"}
end
end
EOF
i <<~'EOF'
def create_user(params) do
profile = UserProfile.registration_changeset(%UserProfile{}, params)
user_cs =
%User{}
|> User.registration_changeset(params)
|> put_assoc(:user_profile, profile)
with {:ok, user} <- Repo.insert(user_cs, returning: false) do
Log.info(%Log{user: user.id, message: "user created"})
send_welcome(user)
{:ok, user}
end
end
EOF
i <<~'EOF'
def my_function do
with :ok <- some_call,
:ok <- another_call do
end
end
EOF
i <<~'EOF'
with {:ok, foo} <- thing(1),
{:ok, bar} <- thing(2) do
foo + bar
end
EOF
end

View file

@ -0,0 +1,322 @@
require 'rspec/expectations'
require 'tmpdir'
require 'vimrunner'
require 'vimrunner/rspec'
GVIM_PATH_FILE = File.expand_path('../../.gvim_path', __FILE__)
class Buffer
FOLD_PLACEHOLDER = '<!-- FOLD -->'.freeze
def initialize(vim, type)
@file = ".fixture.#{type}"
@vim = vim
end
def reindent(content)
with_file content do
min_indent = content.each_line.map { |line| line[/\s*/].size }.min
cmd = "ggVG:s/\\s\\{0,#{min_indent}}//" # remove all indentation
cmd += 'gg=G' # force vim to indent the file
@vim.normal cmd
end
end
def type(content)
with_file do
@vim.normal 'gg'
lines = content.each_line
count = lines.count
@vim.type("i")
lines.each_with_index do |line, index|
@vim.type("#{line.strip}")
@vim.type("<CR>") if index < count - 1
end
end
end
def syntax(content, pattern)
with_file content
# Using this function with a `pattern` that is not in `content` is pointless.
#
# @vim.search() silently fails if a pattern is not found and the cursor
# won't move. So, if the current cursor position happens to sport the
# expected syntax group already, this can lead to false positive tests.
#
# We work around this by using Vim's search() function, which returns 0 if
# there is no match.
if @vim.echo("search(#{pattern.inspect})") == '0'
return []
end
syngroups = @vim.echo <<~EOF
map(synstack(line('.'), col('.')), 'synIDattr(v:val, "name")')
EOF
# From: "['elixirRecordDeclaration', 'elixirAtom']"
# To: ["elixirRecordDeclaration", "elixirAtom"]
syngroups.gsub!(/["'\[\]]/, '').split(', ')
end
def fold_and_replace(content, fold_on_line)
with_file content do
cmd = ":set foldmethod=syntax<CR>"
cmd += "zO"
cmd += "#{fold_on_line}G"
cmd += "zc"
cmd += "cc#{FOLD_PLACEHOLDER}<Esc>"
cmd += ":.s/\s*//<CR>"
@vim.normal(cmd)
end
end
private
def with_file(content = nil)
edit_file(content)
yield if block_given?
@vim.normal ":w<CR>"
@vim.normal ":redraw<CR>"
IO.read(@file)
end
def edit_file(content)
File.write(@file, content) if content
@vim.edit @file
end
end
class Differ
def self.diff(result, expected)
instance.diff(result, expected)
end
def self.instance
@instance ||= new
end
def initialize
@differ = RSpec::Support::Differ.new(
object_preparer: -> (object) do
RSpec::Matchers::Composable.surface_descriptions_in(object)
end,
color: RSpec::Matchers.configuration.color?
)
end
def diff(result, expected)
@differ.diff_as_string(result, expected)
end
end
module ExBuffer
def self.new
Buffer.new(VIM, :ex)
end
end
module EexBuffer
def self.new
Buffer.new(VIM, :eex)
end
end
module HeexBuffer
def self.new
Buffer.new(VIM, :heex)
end
end
module LeexBuffer
def self.new
Buffer.new(VIM, :leex)
end
end
module SurfaceBuffer
def self.new
Buffer.new(VIM, :sface)
end
end
RSpec::Matchers.define :be_typed_with_right_indent do |syntax|
buffer = Buffer.new(VIM, syntax || :ex)
match do |code|
@typed = buffer.type(code)
@typed == code
end
failure_message do |code|
<<~EOM
Expected
#{@typed}
to be indented as
#{code}
when typed
EOM
end
end
{
be_elixir_indentation: :ex,
be_eelixir_indentation: :eex,
be_heelixir_indentation: :heex,
be_leelixir_indentation: :leex,
be_surface_indentation: :sface
}.each do |matcher, type|
RSpec::Matchers.define matcher do
buffer = Buffer.new(VIM, type)
match do |code|
reindented = buffer.reindent(code)
reindented == code
end
failure_message do |code|
<<~EOM
Expected
#{buffer.reindent(code)}
to be indented as
#{code}
when bulk indented
EOM
end
end
end
{
include_elixir_syntax: :ex,
include_eelixir_syntax: :eex,
include_heelixir_syntax: :heex,
include_leelixir_syntax: :leex,
include_surface_syntax: :sface
}.each do |matcher, type|
RSpec::Matchers.define matcher do |syntax, pattern|
buffer = Buffer.new(VIM, type)
match do |code|
buffer.syntax(code, pattern).include? syntax.to_s
end
failure_message do |code|
<<~EOF
expected #{buffer.syntax(code, pattern)}
to include syntax '#{syntax}'
for pattern: /#{pattern}/
in:
#{code}
EOF
end
failure_message_when_negated do |code|
<<~EOF
expected #{buffer.syntax(code, pattern)}
*NOT* to include syntax '#{syntax}'
for pattern: /#{pattern}/
in:
#{code}
EOF
end
end
end
RSpec::Matchers.define :fold_lines do
buffer = Buffer.new(VIM, :ex)
match do |code|
@code = code
pattern = /# fold\s*$/
placeholder_set = false
@expected = code.each_line.reduce([]) do |acc, line|
if line =~ pattern
if !placeholder_set
placeholder_set = true
acc << (Buffer::FOLD_PLACEHOLDER + "\n")
end
else
acc << line
end
acc
end.join
fold_on_line = code.each_line.find_index { |l| l =~ pattern } + 1
@actual = buffer.fold_and_replace(code, fold_on_line)
@expected == @actual
end
failure_message do |code|
<<~EOF
Folded
#{@code}
and unexpectedly got
#{@actual}
EOF
end
end
Vimrunner::RSpec.configure do |config|
config.reuse_server = true
config.start_vim do
VIM =
if File.exist?(GVIM_PATH_FILE)
Vimrunner::Server.new(executable: File.read(GVIM_PATH_FILE).rstrip).start
else
Vimrunner.start_gvim
end
VIM.add_plugin(File.expand_path('..', __dir__))
cmd = ':filetype off<CR>'
cmd += ':filetype plugin indent on<CR>'
cmd += ':autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o<CR>' # disable automatic comment continuation
cmd += ":set ignorecase<CR>" # make sure we test ignorecase
VIM.normal(cmd)
VIM
end
end
RSpec.configure do |config|
config.order = :random
# Run a single spec by adding the `focus: true` option
config.filter_run_including focus: true
config.run_all_when_everything_filtered = true
end
RSpec::Core::ExampleGroup.instance_eval do
def i(str)
gen_tests(:it, str)
end
def ip(str)
gen_tests(:pending, str)
end
private
def gen_tests(method, str)
send method, "\n#{str}" do
expect(str).to be_elixir_indentation
end
send method, "typed: \n#{str}" do
expect(str).to be_typed_with_right_indent
end
end
end

View file

@ -0,0 +1,48 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Alias syntax' do
it 'colorize only module alias' do
str = "Enum.empty?(...)"
expect(str).to include_elixir_syntax('elixirAlias', 'Enum')
expect(str).to include_elixir_syntax('elixirOperator', '\.')
expect(str).to include_elixir_syntax('elixirId', 'empty?')
end
it 'colorize the module alias even if it starts with `!`' do
expect(<<~EOF).to include_elixir_syntax('elixirAlias', 'Enum')
!Enum.empty?(...)
EOF
end
it 'does not colorize the preceding ! in an alias' do
expect(<<~EOF).not_to include_elixir_syntax('elixirAlias', '!')
!Enum.empty?(...)
EOF
end
it 'does not colorize words starting with lowercase letters' do
expect(<<~EOF).not_to include_elixir_syntax('elixirAlias', 'aEnum')
aEnum.empty?(...)
EOF
end
it 'colorizes numbers in aliases' do
str = "S3Manager"
expect(str).to include_elixir_syntax('elixirAlias', 'S')
expect(str).to include_elixir_syntax('elixirAlias', '3')
expect(str).to include_elixir_syntax('elixirAlias', 'Manager')
end
it 'colorize dots in module alias' do
str = "Foo.Bar.Baz.fun(...)"
expect(str).to include_elixir_syntax('elixirAlias', 'Foo')
expect(str).to include_elixir_syntax('elixirAlias', '\.\(Bar\)\@=')
expect(str).to include_elixir_syntax('elixirAlias', 'Bar')
expect(str).to include_elixir_syntax('elixirAlias', '\.\(Baz\)\@=')
expect(str).to include_elixir_syntax('elixirAlias', 'Baz')
expect(str).to include_elixir_syntax('elixirOperator', '\.\(fun\)\@=')
expect(str).to include_elixir_syntax('elixirId', 'fun')
end
end

View file

@ -0,0 +1,32 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Anonymous function syntax' do
it 'anonymous function' do
expect(<<~'EOF').to include_elixir_syntax('elixirAnonymousFunction', 'fn')
fn(_, state) -> state end
EOF
end
it 'as a default argument' do
expect(<<~'EOF').to include_elixir_syntax('elixirAnonymousFunction', 'fn')
def exec(func \\ fn(_, state) -> state end) do
end
EOF
end
it 'as a default argument in a module' do
str = <<~'EOF'
defmodule HelloWorld do
def exec(func \\ fn(_, state) -> state end) do
end
end
EOF
expect(str).to include_elixir_syntax('elixirAnonymousFunction', 'fn')
# Test that the syntax properly closed
expect(str).to include_elixir_syntax('elixirBlockDefinition', '^end')
end
end

View file

@ -0,0 +1,91 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Atom syntax' do
KEYWORDS = %w(
def
defp
defmodule
defprotocol
defimpl
defrecord
defrecordp
defmacro
defmacrop
defdelegate
defoverridable
defexception
defcallback
defstruct
)
it '`atom:` style keyword used as an atom' do
KEYWORDS.each do |kw|
expect(<<~EOF).to include_elixir_syntax('elixirAtom', kw), "expected #{kw} to be an elixirAtom"
defmodule XmlElement do
require Record
import Record, only: [#{kw}: 2, extract: 2]
end
EOF
end
end
it '`:atom =>` style keyword used as an atom' do
KEYWORDS.each do |kw|
expect(<<~EOF).to include_elixir_syntax('elixirAtom', kw), "expected #{kw} to be an elixirAtom"
defmodule XmlElement do
require Record
import Record, only: [:#{kw} => 2, :extract => 2]
end
EOF
end
end
it 'atoms as part of a comprehension' do
s = 'for kvp <- map, do: &atomize_key/1, into: %{}'
expect(s).to include_elixir_syntax('elixirAtom', 'do')
expect(s).to include_elixir_syntax('elixirAtom', 'into')
end
it 'defoverridable' do
expect(<<~EOF).to include_elixir_syntax('elixirAtom', 'init:')
defmodule Test do
defmacro __using__(_options) do
quote do
def init(args) do
{:ok, args}
end
defoverridable init: 1
end
end
end
EOF
expect(<<~EOF).to include_elixir_syntax('elixirAtom', 'init:')
defmodule Test do
defmacro __using__(_options) do
quote do
def init(args) do
{:ok, args}
end
defoverridable [init: 1]
end
end
end
EOF
end
it '`Atom:` style atoms used in keyword list' do
expect(<<~EOF).to include_elixir_syntax('elixirAtom', 'Protocols:')
def project do
[
docs: [
groups_for_modules: [
Protocols: [Enumerable],
]
]
]
end
EOF
end
end

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Syntax case statements' do
it ':* is recognized as an atom' do
expect(<<~EOF).to include_elixir_syntax('elixirAtom', '\*')
case pattern do
:* -> :ok
_ -> :error
end
EOF
end
end

View file

@ -0,0 +1,32 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Comments syntax' do
it 'full line comment' do
expect(<<~EOF).to include_elixir_syntax('elixirComment', '#\ this\ is\ a\ comment')
# this is a comment
EOF
end
it 'end line comment' do
expect(<<~EOF).to include_elixir_syntax('elixirComment', '#\ this\ is\ a\ comment')
IO.puts "some text" # this is a comment
EOF
end
it 'after arguments' do
t = <<~EOF
def foo(<<
0 :: 1, # Foo
1 :: size(1), # Bar
# Blah
baz :: 8, # Baz
>>), do: baz
EOF
expect(t).to include_elixir_syntax('elixirComment', '#\ Foo')
expect(t).to include_elixir_syntax('elixirComment', '#\ Bar')
expect(t).to include_elixir_syntax('elixirComment', '#\ Blah')
expect(t).to include_elixir_syntax('elixirComment', '#\ Baz')
end
end

View file

@ -0,0 +1,30 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Defmodule syntax' do
it 'defines `defmodule` keyword as elixirModuleDefine' do
expect(<<~EOF).to include_elixir_syntax('elixirModuleDefine', 'defmodule')
defmodule HelloPhoenix.HelloController do
EOF
end
it 'defines module name as elixirModuleDeclaration' do
str = "defmodule HelloPhoenix.HelloController do"
expect(str).to include_elixir_syntax('elixirModuleDeclaration', 'HelloPhoenix')
expect(str).to include_elixir_syntax('elixirModuleDeclaration', '\.')
expect(str).to include_elixir_syntax('elixirModuleDeclaration', 'HelloController')
end
it 'does not define module name as elixirAlias' do
expect(<<~EOF).not_to include_elixir_syntax('elixirAlias', 'HelloPhoenix.HelloController')
defmodule HelloPhoenix.HelloController do
EOF
end
it 'defines `do` keyword as elixirBlock' do
expect(<<~EOF).to include_elixir_syntax('elixirBlock', 'do')
defmodule HelloPhoenix.HelloController do
EOF
end
end

View file

@ -0,0 +1,218 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'documentation syntax' do
describe 'string' do
it 'doc in double quotes' do
ex = '@doc "foo"'
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
expect(ex).to include_elixir_syntax('elixirDocStringDelimiter', '"')
end
it 'doc in sigil_S' do
ex = '@doc ~S(foo)'
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', 'S')
end
end
describe 'heredoc' do
it 'doc with multiline content' do
ex = <<~'EOF'
@callbackdoc """
foo
"""
EOF
expect(ex).to include_elixir_syntax('elixirVariable', 'doc')
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
expect(ex).to include_elixir_syntax('elixirDocStringDelimiter', '"""')
end
it 'doc with sigil_S triple double-quoted multiline content' do
ex = <<~'EOF'
@doc ~S"""
foo
"""
EOF
expect(ex).to include_elixir_syntax('elixirVariable', 'doc')
expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', 'S"""')
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
end
it 'doc with sigil_S triple double-quoted multiline content with parentheses' do
ex = <<~'EOF'
@doc(~S"""
foo
""")
EOF
expect(ex).to include_elixir_syntax('elixirVariable', 'doc')
expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', 'S"""')
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
end
it 'doc with sigil_S triple single-quoted multiline content' do
ex = <<~'EOF'
@doc ~S'''
foo
'''
EOF
expect(ex).to include_elixir_syntax('elixirVariable', 'doc')
expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', "S'''")
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
end
it 'doc with sigil_S triple single-quoted multiline content with parentheses' do
ex = <<~'EOF'
@doc(~S'''
foo
''')
EOF
expect(ex).to include_elixir_syntax('elixirVariable', 'doc')
expect(ex).to include_elixir_syntax('elixirDocSigilDelimiter', "S'''")
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
end
it 'doc with triple single-quoted multiline content is not a doc string' do
ex = <<~'EOF'
@doc '''
foo
'''
EOF
expect(ex).not_to include_elixir_syntax('elixirDocString', 'foo')
end
it 'doc with multiline escaped' do
ex = <<~'EOF'
@doc """
foo
```
@xxx \"""
bar
\"""
```
baz
"""
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
expect(ex).to include_elixir_syntax('elixirDocString', 'bar')
expect(ex).to include_elixir_syntax('elixirDocString', 'baz')
end
it 'doc skip interpolation' do
ex = <<~'EOF'
@doc """
foo #{bar}
"""
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'foo')
expect(ex).to include_elixir_syntax('elixirDocStringDelimiter', '"""')
expect(ex).to include_elixir_syntax('elixirInterpolation', 'bar')
end
it 'doc with doctest' do
ex = <<~'EOF'
@doc """
doctest
iex> Enum.map [1, 2, 3], fn(x) ->
...> x * 2
...> end
[2, 4, 6]
"""
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'doctest')
expect(ex).to include_elixir_syntax('elixirDocTest', 'map')
expect(ex).to include_elixir_syntax('elixirDocTest', 'x \* 2')
expect(ex).to include_elixir_syntax('elixirDocTest', '2, 4, 6')
end
describe 'doctest without newline after' do
it 'with heredoc' do
ex = <<~'EOF'
@doc """
doctest
iex> 1 + 2
3
"""
def some_fun(x), do: x
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'doctest')
expect(ex).to include_elixir_syntax('elixirDocTest', '1 + 2')
expect(ex).to include_elixir_syntax('elixirDefine', 'def')
end
it 'with double quote' do
ex = <<~'EOF'
@doc "
doctest
iex> \"bob\"
\"bob\"
"
def some_fun(x), do: x
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'doctest')
expect(ex).to include_elixir_syntax('elixirDocTest', 'bob')
expect(ex).to include_elixir_syntax('elixirDefine', 'def')
end
it 'with sigil_S' do
ex = <<~'EOF'
@doc ~S(
doctest
iex> to_string("bob"\)
"bob"
)
def some_fun(x), do: x
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'doctest')
expect(ex).to include_elixir_syntax('elixirDocTest', 'bob')
expect(ex).to include_elixir_syntax('elixirDefine', 'def')
end
it 'with sigil_s' do
ex = <<~'EOF'
@doc ~s(
doctest
iex> to_string("bob"\)
"bob"
)
def some_fun(x), do: x
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'doctest')
expect(ex).to include_elixir_syntax('elixirDocTest', 'bob')
expect(ex).to include_elixir_syntax('elixirDefine', 'def')
end
end
it 'doc with inline code' do
ex = <<~'EOF'
@doc """
doctest with inline code `List.wrap([])`
"""
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'doctest')
expect(ex).to include_elixir_syntax('elixirDocString', 'wrap')
end
describe "use markdown for docs" do
before(:each) { VIM.command("let g:elixir_use_markdown_for_docs = 1") }
after(:each) { VIM.command("let g:elixir_use_markdown_for_docs = 0") }
it 'doc with inline code' do
ex = <<~'EOF'
@doc """
doc with inline code `List.wrap([])`
"""
EOF
expect(ex).to include_elixir_syntax('elixirDocString', 'inline')
expect(ex).to include_elixir_syntax('markdownCode', 'wrap')
end
end
end
end

View file

@ -0,0 +1,61 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Embedded Elixir syntax' do
it 'elixir' do
expect('<%= if true do %>').to include_eelixir_syntax('elixirKeyword', 'if')
expect('<%= if true do %>').to include_eelixir_syntax('elixirBoolean', 'true')
end
it 'expression' do
expect('<%= if true do %>').to include_eelixir_syntax('eelixirExpression', 'if')
expect('<% end %>').to include_eelixir_syntax('eelixirExpression', 'end')
end
it 'quote' do
expect('<%% def f %>').to include_eelixir_syntax('eelixirQuote', 'def')
end
it 'comment' do
expect('<%# foo bar baz %>').to include_eelixir_syntax('eelixirComment', 'foo')
end
it 'delimiters' do
expect('<% end %>').to include_eelixir_syntax('eelixirDelimiter', '<%')
expect('<% end %>').to include_eelixir_syntax('eelixirDelimiter', '%>')
end
end
describe 'Embedded Live Elixir syntax' do
it 'elixir' do
expect('<%= if true do %>').to include_leelixir_syntax('elixirKeyword', 'if')
expect('<%= if true do %>').to include_leelixir_syntax('elixirBoolean', 'true')
end
it 'expression' do
expect('<%= if true do %>').to include_leelixir_syntax('eelixirExpression', 'if')
expect('<% end %>').to include_leelixir_syntax('eelixirExpression', 'end')
end
it 'quote' do
expect('<%% def f %>').to include_leelixir_syntax('eelixirQuote', 'def')
end
it 'comment' do
expect('<%# foo bar baz %>').to include_leelixir_syntax('eelixirComment', 'foo')
end
it 'delimiters' do
expect('<% end %>').to include_leelixir_syntax('eelixirDelimiter', '<%')
expect('<% end %>').to include_leelixir_syntax('eelixirDelimiter', '%>')
end
end
describe 'Embedded Surface syntax' do
it 'elixir' do
expect('{{ @foo }}').to include_surface_syntax('elixirVariable', 'foo')
expect('{{ @foo }}').to include_surface_syntax('surfaceDelimiter', '{{')
expect('{{ @foo }}').to include_surface_syntax('surfaceDelimiter', '}}')
end
end

View file

@ -0,0 +1,174 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'ExUnit syntax' do
it 'test macro' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitMacro', 'test')
test 'that stuff works' do
assert true
end
EOF
end
it 'describe macro' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitMacro', 'describe')
describe 'some_function/1' do
test 'that stuff works' do
assert true
end
end
EOF
end
it 'setup macro' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitMacro', 'setup')
setup do
IO.puts "hi mom"
end
test 'that stuff works' do
assert true
end
EOF
end
it 'setup_all macro' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitMacro', 'setup_all')
setup_all do
IO.puts "hi mom"
end
test 'that stuff works' do
assert true
end
EOF
end
it 'on_exit macro' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitMacro', 'on_exit')
setup_all do
IO.puts "hi mom"
on_exit fn() ->
do_something
end
end
test 'that stuff works' do
assert true
end
EOF
end
it 'assert' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'assert')
test 'that stuff works' do
assert true
end
EOF
end
it 'assert_in_delta' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'assert_in_delta')
test 'that stuff works' do
assert_in_delta true
end
EOF
end
it 'assert_raise' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'assert_raise')
test 'that stuff works' do
assert_raise true
end
EOF
end
it 'assert_receive' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'assert_receive')
test 'that stuff works' do
assert_receive true
end
EOF
end
it 'assert_received' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'assert_received')
test 'that stuff works' do
assert_received true
end
EOF
end
it 'catch_error' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'catch_error')
test 'that stuff works' do
catch_error true
end
EOF
end
it 'catch_exit' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'catch_exit')
test 'that stuff works' do
catch_exit true
end
EOF
end
it 'catch_throw' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'catch_throw')
test 'that stuff works' do
catch_throw true
end
EOF
end
it 'flunk' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'flunk')
test 'that stuff works' do
flunk true
end
EOF
end
it 'refute' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'refute')
test 'that stuff works' do
refute true
end
EOF
end
it 'refute_in_delta' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'refute_in_delta')
test 'that stuff works' do
refute_in_delta true
end
EOF
end
it 'refute_receive' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'refute_receive')
test 'that stuff works' do
refute_receive true
end
EOF
end
it 'refute_received' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitAssert', 'refute_received')
test 'that stuff works' do
refute_received true
end
EOF
end
it 'doctest' do
expect(<<~EOF).to include_elixir_syntax('elixirExUnitMacro', 'doctest')
module MyTest do
doctest MyModule
end
EOF
end
end

View file

@ -0,0 +1,20 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'function syntax' do
it 'doesnt treat underscored functions like unsued variables' do
expect(<<~EOF).to include_elixir_syntax('elixirId', '__ensure_defimpl__')
defp derive(protocol, for, struct, opts, env) do
# ... code ...
__ensure_defimpl__(protocol, for, env)
EOF
expect(<<~EOF).not_to include_elixir_syntax('elixirUnusedVariable', '__ensure_defimpl__')
defp derive(protocol, for, struct, opts, env) do
# ... code ...
__ensure_defimpl__(protocol, for, env)
EOF
end
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'defguard syntax' do
it 'defines `defguard` keyword as elixirGuard' do
expect(<<~EOF).to include_elixir_syntax('elixirGuard', 'defguard')
defguard some_guard(x) when is_integer(x)
EOF
end
it 'defines `defguardp` keyword as elixirPrivateGuard' do
expect(<<~EOF).to include_elixir_syntax('elixirPrivateGuard', 'defguardp')
defguardp some_private_guard(x) when is_integer(x)
EOF
end
end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Kernel function syntax' do
it 'kernel function used as an atom key in a keyword list outside of a block' do
expect(<<~EOF).not_to include_elixir_syntax('elixirKeyword', 'length')
do
plug Plug.Parsers, length: 400_000_000
end
EOF
end
it 'kernel function used as an atom key in a keyword list contained in a block' do
expect(<<~EOF).not_to include_elixir_syntax('elixirKeyword', 'length')
plug Plug.Parsers, length: 400_000_000
EOF
end
end

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Keyword syntax' do
it 'for used as keyword' do
expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'for')
for v <- [1, 3, 3]
EOF
end
it 'case used as keyword' do
expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'case')
case true do
EOF
end
it 'raise used as keyword' do
expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'raise')
raise "oops"
EOF
expect(<<~EOF).to include_elixir_syntax('elixirKeyword', 'raise')
raise ArgumentError, message: "invalid argument foo"
EOF
end
end

View file

@ -0,0 +1,40 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'List syntax' do
it 'should properly handle "\\\\" inside' do
syntax = <<~EOF
'"\\\\'
var = 1
EOF
expect(syntax).to include_elixir_syntax('elixirId', 'var')
expect(syntax).not_to include_elixir_syntax('elixirString', 'var')
end
it 'recognizes lists' do
syntax = <<~EOF
[
:hello,
:world
]
EOF
expect(syntax).to include_elixir_syntax('elixirListDelimiter', '[')
expect(syntax).to include_elixir_syntax('elixirList', ':hello')
expect(syntax).to include_elixir_syntax('elixirListDelimiter', ']')
end
it 'recognizes lists inside functions' do
syntax = <<~EOF
def hello_world do
[
:hello,
:world
]
end
EOF
expect(syntax).to include_elixir_syntax('elixirListDelimiter', '[')
expect(syntax).to include_elixir_syntax('elixirList', ':hello')
expect(syntax).to include_elixir_syntax('elixirListDelimiter', ']')
end
end

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Map syntax' do
it 'maps' do
str = %q(%{name: "one"})
expect(str).to include_elixir_syntax('elixirMapDelimiter', '%')
expect(str).to include_elixir_syntax('elixirMapDelimiter', '{')
expect(str).to include_elixir_syntax('elixirAtom', 'name:')
expect(str).to include_elixir_syntax('elixirMap', 'name:')
expect(str).to include_elixir_syntax('elixirMapDelimiter', '}')
end
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Module function syntax' do
it 'for used as module function' do
expect(<<~EOF).to include_elixir_syntax('elixirId', 'for')
OverridesDefault.for
EOF
end
it 'case used as module function' do
expect(<<~EOF).to include_elixir_syntax('elixirId', 'case')
OverridesDefault.case
EOF
end
end

View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Numbers syntax' do
describe 'decimal' do
it 'positive is colorized' do
expect('123').to include_elixir_syntax('elixirNumber', '123')
end
it 'negative is colorized' do
expect('-123').to include_elixir_syntax('elixirNumber', '123')
end
end
describe 'hexadecimal' do
it 'positive is colorized' do
expect('0xdeadbeaf').to include_elixir_syntax('elixirNumber', '0xdeadbeaf')
end
it 'negative is colorized' do
expect('-0xdeadbeaf').to include_elixir_syntax('elixirNumber', '0xdeadbeaf')
end
end
describe 'octal' do
it 'positive is colorized' do
expect('0o777').to include_elixir_syntax('elixirNumber', '0o777')
end
it 'negative is colorized' do
expect('-0o777').to include_elixir_syntax('elixirNumber', '0o777')
end
end
describe 'binary' do
it 'positive is colorized' do
expect('0b1011').to include_elixir_syntax('elixirNumber', '0b1011')
end
it 'negative is colorized' do
expect('-0b1011').to include_elixir_syntax('elixirNumber', '0b1011')
end
end
end

View file

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Operators' do
it 'default argument' do
expect(<<~'EOF').to include_elixir_syntax('elixirOperator', '\\')
def foo(bar \\ :baz)
EOF
expect(<<~EOF).to include_elixir_syntax('elixirOperator', '\/')
def foo(bar // :baz)
EOF
end
it 'in' do
expect(<<~EOF).to include_elixir_syntax('elixirOperator', 'in')
'x' in ['x']
EOF
expect(<<~EOF).not_to include_elixir_syntax('elixirOperator', 'in')
:queue.in x, 5
EOF
end
it 'does not highlight operators inside of elixirIds' do
expect(<<~EOF).not_to include_elixir_syntax('elixirOperator', 'in')
incoming
EOF
end
end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
# encoding: utf-8
require 'spec_helper'
describe 'Record syntax' do
it 'private record symbol' do
expect(<<~EOF).to include_elixir_syntax('elixirAtom', ':user')
defrecordp :user, name: "José", age: 25
EOF
end
end

View file

@ -0,0 +1,146 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Sigil syntax' do
it 'as function argument' do
expect('def f(~s(")), do: true').to include_elixir_syntax('elixirSigilDelimiter', '\~s(')
expect('def f(~s(")), do: true').to include_elixir_syntax('elixirSigil', '"')
expect("def f(~s(')), do: true").to include_elixir_syntax('elixirSigil', "'")
expect('def f(~s(")), do: true').not_to include_elixir_syntax('elixirSigilDelimiter', '"')
end
it 'as function argument multiline content' do
ex = <<~'EOF'
f(
~S"""
foo
""",
bar
)
EOF
expect(ex).to include_elixir_syntax('elixirSigilDelimiter', 'S"""')
expect(ex).to include_elixir_syntax('elixirSigil', 'foo')
end
describe 'upper case' do
it 'string' do
expect('~S(string)').to include_elixir_syntax('elixirSigilDelimiter', 'S')
expect('~S(string)').to include_elixir_syntax('elixirSigil', 'string')
end
it 'character list' do
expect('~C(charlist)').to include_elixir_syntax('elixirSigilDelimiter', 'C')
expect('~C(charlist)').to include_elixir_syntax('elixirSigil', 'charlist')
end
it 'regular expression' do
expect('~R(regex)').to include_elixir_syntax('elixirSigilDelimiter', 'R')
expect('~R(regex)').to include_elixir_syntax('elixirSigil', 'regex')
end
it 'list of words' do
expect('~W(list of words)').to include_elixir_syntax('elixirSigilDelimiter', 'W')
expect('~W(list of words)').to include_elixir_syntax('elixirSigil', 'list')
end
it 'delimited with parenthesis' do
expect('~S(foo bar)').to include_elixir_syntax('elixirSigilDelimiter', '(')
expect('~S(foo bar)').to include_elixir_syntax('elixirSigilDelimiter', ')')
end
it 'delimited with braces' do
expect('~S{foo bar}').to include_elixir_syntax('elixirSigilDelimiter', '{')
expect('~S{foo bar}').to include_elixir_syntax('elixirSigilDelimiter', '}')
end
it 'delimited with brackets' do
expect('~S[foo bar]').to include_elixir_syntax('elixirSigilDelimiter', '[')
expect('~S[foo bar]').to include_elixir_syntax('elixirSigilDelimiter', ']')
end
it 'escapes double quotes unless only preceded by whitespace' do
expect(<<~EOF).to include_elixir_syntax('elixirSigilDelimiter', %q(^\s*\zs"""))
~r"""
foo """
"""
EOF
end
it 'escapes single quotes unless only preceded by whitespace' do
expect(<<~EOF).to include_elixir_syntax('elixirSigilDelimiter', %q(^\s*\zs'''))
~r'''
foo '''
'''
EOF
end
it 'without escapes' do
expect('~S(foo \n bar)').not_to include_elixir_syntax('elixirRegexEscape', '\\')
end
it 'without interpolation' do
expect('~S(foo #{bar})').not_to include_elixir_syntax('elixirInterpolation', 'bar')
end
it 'without escaped parenthesis' do
expect('~S(\( )').not_to include_elixir_syntax('elixirRegexEscapePunctuation', '( ')
end
it 'Live EEx' do
expect('~L"""liveview template"""').to include_elixir_syntax('elixirSigilDelimiter', '"""')
end
it 'Surface EEx' do
expect('~H"""surface template"""').to include_elixir_syntax('elixirSigilDelimiter', '"""')
end
it 'EEx' do
expect('~E"""Phoenix.HTML template"""').to include_elixir_syntax('elixirSigilDelimiter', '"""')
expect('~e"""Phoenix.HTML template"""').to include_elixir_syntax('elixirSigilDelimiter', '"""')
end
end
describe 'lower case' do
it 'string' do
expect('~s(string)').to include_elixir_syntax('elixirSigilDelimiter', 's')
expect('~s(string)').to include_elixir_syntax('elixirSigil', 'string')
end
it 'character list' do
expect('~c(charlist)').to include_elixir_syntax('elixirSigilDelimiter', 'c')
expect('~c(charlist)').to include_elixir_syntax('elixirSigil', 'charlist')
end
it 'regular expression' do
expect('~r(regex)').to include_elixir_syntax('elixirSigilDelimiter', 'r')
expect('~r(regex)').to include_elixir_syntax('elixirSigil', 'regex')
end
it 'list of words' do
expect('~w(list of words)').to include_elixir_syntax('elixirSigilDelimiter', 'w')
expect('~w(list of words)').to include_elixir_syntax('elixirSigil', 'list')
end
it 'with escapes' do
expect('~s(foo \n bar)').to include_elixir_syntax('elixirRegexEscapePunctuation', '\\')
end
it 'with interpolation' do
expect('~s(foo #{bar})').to include_elixir_syntax('elixirInterpolation', 'bar')
end
it 'with escaped parenthesis' do
expect('~s(\( )').to include_elixir_syntax('elixirRegexEscapePunctuation', '( ')
end
it 'interpolation with slashes' do
expect('~s/foo #{bar}/').to include_elixir_syntax('elixirInterpolation', 'bar')
end
it 'escapes with slashes' do
expect('~s/foo \n bar/').to include_elixir_syntax('elixirRegexEscapePunctuation', '\\')
end
end
end

View file

@ -0,0 +1,109 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'String syntax' do
describe 'binary' do
it 'double quoted string' do
expect('foo "test"').to include_elixir_syntax('elixirString', 'test')
end
it 'double quoted string with escaped quote' do
expect('"this \"test is all one string"').to include_elixir_syntax('elixirString', 'test')
end
it 'charlist with escaped quote' do
expect(<<-'EOF').to include_elixir_syntax('elixirCharList', 'test')
'this \'test is all one charlist'
EOF
end
it 'interpolation in string' do
expect('do_something "foo #{test}"').to include_elixir_syntax('elixirInterpolation', 'test')
end
end
describe 'heredoc' do
it 'heredoc must be string' do
ex = <<~EOF
def function do
"""
foo "test"
"""
end
EOF
expect(ex).to include_elixir_syntax('elixirString', 'foo')
expect(ex).to include_elixir_syntax('elixirString', 'test')
end
it 'interpolation in string in heredoc' do
expect(<<~'EOF').to include_elixir_syntax('elixirInterpolation', '#{')
def function do
"""
foo "#{test}"
"""
end
EOF
end
it 'interpolation in heredoc' do
expect(<<~'EOF').to include_elixir_syntax('elixirInterpolation', '#{')
def function do
"""
foo #{test}
"""
end
EOF
end
it 'correctly terminates heredocs with no spaces at the start of the line' do
expect(<<~'EOF'.gsub(/^\s+/, '')).to include_elixir_syntax('elixirAtom', ':bar')
"""
foo
"""
:bar
EOF
expect(<<~'EOF'.gsub(/^\s+/, '')).to include_elixir_syntax('elixirAtom', ':bar')
'''
foo
'''
:bar
EOF
end
it 'interpolation with a tuple' do
str = <<~'EOF'
"Failed sending tasks #{inspect {:unexpected_status_code, s}}"
EOF
expect(str).not_to include_elixir_syntax('elixirInterpolationDelimiter', '}}"$')
expect(str).to include_elixir_syntax('elixirInterpolationDelimiter', '}"$')
end
it 'interpolation with a tuple' do
str = <<~'EOF'
"Failed sending tasks #{inspect %{unexpected_status_code: s}}"
EOF
expect(str).not_to include_elixir_syntax('elixirInterpolationDelimiter', '}}"$')
expect(str).to include_elixir_syntax('elixirInterpolationDelimiter', '}"$')
end
it 'interpolation with a struct' do
str = <<~'EOF'
"Failed sending tasks #{inspect %ResponseStruct{unexpected_status_code: s}}"
EOF
expect(str).not_to include_elixir_syntax('elixirInterpolationDelimiter', '}}"$')
expect(str).to include_elixir_syntax('elixirInterpolationDelimiter', '}"$')
end
it 'strings with embedded braces' do
str = <<~EOF
x = [
{:text, "asd {"},
{:text, "qwe"},
]
EOF
expect(str).to include_elixir_syntax('elixirString', '{"}')
end
end
end

View file

@ -0,0 +1,64 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Struct syntax' do
it 'without defaults' do
expect(<<~EOF).to include_elixir_syntax('elixirAtom', ':name')
defstruct [:name, :age]
EOF
end
it 'with defaults' do
expect(<<~EOF).to include_elixir_syntax('elixirAtom', 'name:')
defstruct name: "john", age: 27
EOF
end
it 'structs' do
str = %q(%MyStruct{name: "one"})
expect(str).to include_elixir_syntax('elixirStructDelimiter', '%')
expect(str).to include_elixir_syntax('elixirStruct', '%')
expect(str).to include_elixir_syntax('elixirAlias', 'MyStruct')
expect(str).to include_elixir_syntax('elixirStruct', 'MyStruct')
expect(str).to include_elixir_syntax('elixirStructDelimiter', '{')
expect(str).to include_elixir_syntax('elixirStruct', '{')
expect(str).to include_elixir_syntax('elixirAtom', 'name:')
expect(str).to include_elixir_syntax('elixirStruct', 'name:')
expect(str).to include_elixir_syntax('elixirStructDelimiter', '}')
end
it 'properly closes strings in structs' do
str = <<~'EOF'
%MyStruct{url: "http://127.0.0.1:#{port}"} # anchor
# this should not be a string still
EOF
expect(str).to include_elixir_syntax('elixirStruct', '{url')
expect(str).to include_elixir_syntax('elixirStringDelimiter', '"http')
expect(str).to include_elixir_syntax('elixirStruct', '"http')
expect(str).to include_elixir_syntax('elixirInterpolationDelimiter', '#{')
expect(str).to include_elixir_syntax('elixirStruct', '#{')
expect(str).to include_elixir_syntax('elixirInterpolationDelimiter', '}"}')
expect(str).to include_elixir_syntax('elixirStruct', '}"}')
expect(str).not_to include_elixir_syntax('elixirStructDelimiter', '}"}')
expect(str).to include_elixir_syntax('elixirStringDelimiter', '"}')
expect(str).to include_elixir_syntax('elixirStruct', '"}')
expect(str).to include_elixir_syntax('elixirStringDelimiter', '"}')
expect(str).to include_elixir_syntax('elixirStruct', '"}')
expect(str).to include_elixir_syntax('elixirStructDelimiter', '} #')
expect(str).to include_elixir_syntax('elixirComment', '# this should not be a string still')
end
end

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Tuple syntax' do
it 'tuples' do
str = %q({:name, "one"})
expect(str).to include_elixir_syntax('elixirTupleDelimiter', '{')
expect(str).to include_elixir_syntax('elixirTuple', '{')
expect(str).to include_elixir_syntax('elixirAtom', ':name')
expect(str).to include_elixir_syntax('elixirTuple', ':name')
expect(str).to include_elixir_syntax('elixirTupleDelimiter', '}')
end
end

View file

@ -0,0 +1,75 @@
# frozen_string_literal: true
require 'spec_helper'
describe 'Variable syntax' do
it 'unused' do
expect(<<~EOF).to include_elixir_syntax('elixirUnusedVariable', '_from')
def handle_call(:pop, _from, [h|stack]) do
{ :reply, h, stack }
end
EOF
end
it 'unused in function body' do
expect(<<~EOF).not_to include_elixir_syntax('elixirUnusedVariable', '_from')
def handle_call(:pop)
Hello._from
end
EOF
end
it 'unused, multiple lines' do
expect(<<~EOF).to include_elixir_syntax('elixirUnusedVariable', '_from')
def handle_call(:pop,
_from,
[h|stack]) do
{ :reply, h, stack }
end
EOF
end
it 'unused, single char' do
expect(<<~EOF).to include_elixir_syntax('elixirUnusedVariable', '_')
def call(:pop, _, [h|stack]) do
{ :reply, h, stack }
end
EOF
end
it 'unused in pattern_match' do
str = <<~EOF
def sign_in(conn, %{
"data" => %{
"type" => "doctor",
"attributes" => %{
"institution_code" => institution_code,
"password" => password,
"email_or_phone" => email_or_phone}}}, _user, _claims) do
:ok
end
EOF
expect(str).to include_elixir_syntax('elixirUnusedVariable', '_user')
expect(str).to include_elixir_syntax('elixirUnusedVariable', '_claims')
end
it 'unused, in anonymous function, inline' do
expect(<<~EOF).to include_elixir_syntax('elixirUnusedVariable', '_unused')
fun = fn _unused -> false end
EOF
end
it 'unused, in anonymous function, multiple lines' do
expect(<<~EOF).to include_elixir_syntax('elixirUnusedVariable', '_unused')
fun = fn
([], _unused) -> true
end
EOF
end
it 'unused, in pattern matching' do
expect(<<~EOF).to include_elixir_syntax('elixirUnusedVariable', '_unused')
_unused = false
EOF
end
end