Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enh(elixir) Improves and fixes many issues with Elixir grammar #3212

Merged
merged 11 commits into from
Jun 5, 2021
8 changes: 7 additions & 1 deletion src/languages/elixir.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export default function(hljs) {
};
const FUNCTION = {
className: 'function',
beginKeywords: 'def defp defmacro',
beginKeywords: 'def defp defmacro defmacrop',
end: /\B\b/, // the mode is ended by the title
contains: [
hljs.inherit(hljs.TITLE_MODE, {
Expand All @@ -180,12 +180,18 @@ export default function(hljs) {
beginKeywords: 'defimpl defmodule defprotocol defrecord',
end: /\bdo\b|$|;/
});
const DEFSTRUCT = {
className: 'class',
beginKeywords: 'defstruct'
// ends immediately
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class is deprecated now. More likely you'd want this to be a newer multi-match rule and then use title.class for the name of the struct... See wren.js for examples. I can also do this myself after though... I already had a few commits patching the other declarations to the newer standard but decided they didn't fit in our regex fix PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... since the struct's name is not part of the defstruct call but it's defined by the module name in which defstruct is called, I think I just need to make defstruct a keyword instead?

Copy link
Member

@joshgoebel joshgoebel Jun 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iex> defmodule User do
...>   defstruct name: "John", age: 27
...> end

Ah, yes, just a keyword then for defstruct... defmodule though would probably be a multi-matcher.

};
const ELIXIR_DEFAULT_CONTAINS = [
STRING,
UPCASE_SIGIL,
LOWERCASE_SIGIL,
hljs.HASH_COMMENT_MODE,
CLASS,
DEFSTRUCT,
FUNCTION,
{
begin: '::'
Expand Down
6 changes: 6 additions & 0 deletions test/markup/elixir/function-title.expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">f!</span></span>, <span class="hljs-symbol">do:</span> IO.puts <span class="hljs-string">&quot;hello world&quot;</span>

<span class="hljs-function"><span class="hljs-keyword">defp</span> <span class="hljs-title">f?</span></span>, <span class="hljs-symbol">do:</span> <span class="hljs-keyword">true</span>

<span class="hljs-function"><span class="hljs-keyword">defmacro</span> <span class="hljs-title">foo</span></span>, <span class="hljs-symbol">do:</span> <span class="hljs-symbol">:ok</span>

<span class="hljs-function"><span class="hljs-keyword">defmacrop</span> <span class="hljs-title">do_foo</span></span>, <span class="hljs-symbol">do:</span> <span class="hljs-symbol">:ok</span>

x = <span class="hljs-number">5</span>
6 changes: 6 additions & 0 deletions test/markup/elixir/function-title.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ end

def f!, do: IO.puts "hello world"

defp f?, do: true

defmacro foo, do: :ok

defmacrop do_foo, do: :ok

x = 5
12 changes: 12 additions & 0 deletions test/markup/elixir/modules.expect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">User</span></span> <span class="hljs-keyword">do</span>
<span class="hljs-class"><span class="hljs-keyword">defstruct</span></span> [<span class="hljs-symbol">:name</span>, <span class="hljs-symbol">:email</span>, <span class="hljs-symbol">age:</span> <span class="hljs-number">18</span>]
<span class="hljs-keyword">end</span>

<span class="hljs-class"><span class="hljs-keyword">defprotocol</span> <span class="hljs-title">Size</span></span> <span class="hljs-keyword">do</span>
<span class="hljs-variable">@doc</span> <span class="hljs-string">&quot;Calculates the size (and not the length!) of a data structure&quot;</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">size</span></span>(data)
<span class="hljs-keyword">end</span>

<span class="hljs-class"><span class="hljs-keyword">defimpl</span> <span class="hljs-title">Size</span></span>, <span class="hljs-symbol">for:</span> Map <span class="hljs-keyword">do</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">size</span></span>(map), <span class="hljs-symbol">do:</span> map_size(map)
<span class="hljs-keyword">end</span>
12 changes: 12 additions & 0 deletions test/markup/elixir/modules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule User do
defstruct [:name, :email, age: 18]
end

defprotocol Size do
@doc "Calculates the size (and not the length!) of a data structure"
def size(data)
end

defimpl Size, for: Map do
def size(map), do: map_size(map)
end
8 changes: 6 additions & 2 deletions test/markup/elixir/strings.expect.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
a = <span class="hljs-string">&quot;&quot;&quot;test&quot;&quot;&quot;</span>
b = <span class="hljs-string">&#x27;&#x27;&#x27;test&#x27;&#x27;&#x27;</span>
a = <span class="hljs-string">&quot;&quot;&quot;
test
&quot;&quot;&quot;</span>
b = <span class="hljs-string">&#x27;&#x27;&#x27;
test
&#x27;&#x27;&#x27;</span>
c = <span class="hljs-string">&quot;test&quot;</span>
d = <span class="hljs-string">&#x27;test&#x27;</span>
8 changes: 6 additions & 2 deletions test/markup/elixir/strings.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
a = """test"""
b = '''test'''
Copy link
Member

@joshgoebel joshgoebel May 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see how these are better examples (that you added), but if the previous were valid we should also leave them to serve as additional regression tests... one can still use a multi-line string for a single line - that is valid grammar, yes?

Copy link
Contributor Author

@angelikatyborska angelikatyborska May 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is valid grammar, yes?

No, those were syntax errors in Elixir. The only allowed characters after the opening '''/""" is optional whitespace, and then a newline is required.

My assumption is that it's not a big deal if the syntax highlighting colors something that doesn't compile so I didn't feel the need to change the regexes for multiline strings, but the test examples should be valid Elixir code, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, those were syntax errors in Elixir.

Whoa. I stand corrected. ;-)

My assumption is that it's not a big deal if the syntax highlighting colors something that doesn't compile

Right, it's not our job to detect invalid code.

but the test examples should be valid Elixir code, right?

For the most part, yes. In this particular case this indeed makes sense. I just see people "swap" test cases often when they should be adding new cases instead, [not removing old ones]. Thought this was perhaps yet another case of that. :)

a = """
test
"""
b = '''
test
'''
c = "test"
d = 'test'