Skip to content
This repository was archived by the owner on Apr 22, 2020. It is now read-only.

Commit 760e6e7

Browse files
nietakimikesamuel
authored andcommitted
Add Elixir language support (#478)
* First, crude version of the elixir language handler. * multiple elixir plugin improvements - attributes, atoms, strings, ... * elixir-lang - added support for number literals with underscores * elixir-lang: added support for atoms as keys in keyword lists * Elixir: added support for sigils, simplified the keywords regex * Elixir: added more keywords from Kernel.SpecialForms * Elixir: adding missing keywords and more permissive atom/variable names * Elixir: better support for binaries/bitstrings * Elixir: added support for the `iex` prompt for interactive examples * added a failing test for elixir * Elixir: fixed the failing test for elixir syntax highlighting * Elixir: Highlighting constructs like `%{"THIS": :foo}` as atoms * Elixir: fixed false-positive highlighting for 0XFF and 0O77 * Elixir: fixing the license text. * Elixir: fixing multiline charlists * Elixir: more robust multiline strings and charlists * Elixir: making string recognition simpler and more correct
1 parent e9fae9a commit 760e6e7

File tree

3 files changed

+192
-1
lines changed

3 files changed

+192
-1
lines changed

src/lang-ex.js

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* @license
3+
* Copyright (C) 2017 Jacek Królikowski
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* @fileoverview
20+
* Registers a language handler for Elixir.
21+
*
22+
23+
*/
24+
25+
PR['registerLangHandler'](
26+
PR['createSimpleLexer'](
27+
[
28+
[PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'],
29+
// # comments
30+
[PR['PR_COMMENT'], /^#.*/, null, '#'],
31+
// a (possibly multiline) charlist
32+
[PR['PR_LITERAL'], /^'(?:[^'\\]|\\(?:.|\n|\r))*'?/, null, '\''],
33+
// @attributes
34+
[PR['PR_ATTRIB_NAME'], /^@\w+/, null, '@'],
35+
[PR['PR_PUNCTUATION'], /^[!%&()*+,\-;<=>?\[\\\]^{|}]+/, null,
36+
'!%&()*+,-;<=>?[\\]^{|}'],
37+
// Borrowed from lang-erlang.js:
38+
[PR['PR_LITERAL'],
39+
/^(?:0o[0-7](?:[0-7]|_[0-7])*|0x[\da-fA-F](?:[\da-fA-F]|_[\da-fA-F])*|\d(?:\d|_\d)*(?:\.\d(?:\d|_\d)*)?(?:[eE][+\-]?\d(?:\d|_\d)*)?)/,
40+
null, '0123456789']
41+
],
42+
[
43+
// the iex> prompt for interactive examples
44+
[PR['PR_ATTRIB_NAME'], /^iex(?:\(\d+\))?> /],
45+
// special case for binaries, so that they don't get presented like atoms
46+
[PR['PR_PUNCTUATION'], /^::/],
47+
// atoms - :__a_word or :"colon followed by a string"
48+
[PR['PR_LITERAL'], /^:(?:\w+[\!\?\@]?|"(?:[^"\\]|\\.)*"?)/],
49+
// compile-time information
50+
[PR['PR_ATTRIB_NAME'], /^(?:__(?:CALLER|ENV|MODULE|DIR)__)/],
51+
// keywords
52+
[PR['PR_KEYWORD'],
53+
/^(?:alias|case|catch|def(?:delegate|exception|impl|macrop?|module|overridable|p?|protocol|struct)|do|else|end|fn|for|if|in|import|quote|raise|require|rescue|super|throw|try|unless|unquote(?:_splicing)?|use|when|with|yield)\b/],
54+
[PR['PR_LITERAL'], /^(?:true|false|nil)\b/],
55+
// atoms as keyword list keys
56+
// NOTE: this does also handle the %{"I'm an atom": :foo} case
57+
//
58+
// Contains negative lookahead to handle <<foo::binary>>
59+
[PR['PR_LITERAL'], /^(?:\w+[\!\?\@]?|"(?:[^"\\]|\\.)*"):(?!:)/],
60+
// heredoc: triple double-quoted multi-line string.
61+
//
62+
// NOTE: the opening """ needs to be followed by a newline
63+
[PR['PR_STRING'],
64+
/^"""\s*(\r|\n)+(?:""?(?!")|[^\\"]|\\(?:.|\n|\r))*"{0,3}/],
65+
// A double-quoted multi-line string
66+
[PR['PR_STRING'],
67+
/^"(?:[^"\\]|\\(?:.|\n|\r))*"?(?!")/],
68+
// types
69+
[PR['PR_TYPE'], /^[A-Z]\w*/],
70+
// variables not meant to be used or private functions
71+
[PR['PR_COMMENT'], /^_\w*/],
72+
// plain: variables, functions, ...
73+
[PR['PR_PLAIN'], /^[$a-z]\w*[\!\?]?/],
74+
// sigils with the same starting and ending character.
75+
// Key part: X(?:[^X\r\n\\]|\\.)+X where X is the sigil character
76+
[PR['PR_ATTRIB_VALUE'], /^~[A-Z](?:\/(?:[^\/\r\n\\]|\\.)+\/|\|(?:[^\|\r\n\\]|\\.)+\||"(?:[^"\r\n\\]|\\.)+"|'(?:[^'\r\n\\]|\\.)+')[A-Z]*/i],
77+
// sigils with a different starting and ending character.
78+
// Key part: X(?:[^Y\r\n\\]|\\.)+Y where X and Y are the starting and ending characters
79+
[PR['PR_ATTRIB_VALUE'], /^~[A-Z](?:\((?:[^\)\r\n\\]|\\.)+\)|\[(?:[^\]\r\n\\]|\\.)+\]|\{(?:[^\}\r\n\\]|\\.)+\}|\<(?:[^\>\r\n\\]|\\.)+\>)[A-Z]*/i],
80+
[PR['PR_PUNCTUATION'], /^(?:\.+|\/|[:~])/]
81+
]),
82+
['ex','exs']);

tests/prettify_test_2.html

+57
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
'lang-clj.js',
2626
'lang-css.js',
2727
'lang-dart.js',
28+
'lang-ex.js',
2829
'lang-lisp.js',
2930
'lang-llvm.js',
3031
'lang-matlab.js',
@@ -1083,5 +1084,61 @@ <h1>MATLAB</h1>
10831084
%}
10841085
</pre>
10851086

1087+
<h1>Elixir</h1>
1088+
<pre class="prettyprint lang-ex" id="elixir">
1089+
defmodule Foo.Bar do
1090+
@moduledoc """
1091+
Tests syntax highlighting for Elixir
1092+
"""
1093+
1094+
use Bitwise
1095+
require Logger
1096+
alias __MODULE__, as: This
1097+
1098+
@default_token_length 10_000
1099+
1100+
1101+
@spec token(length :: integer) :: String.t
1102+
1103+
def token(length \\ @default_token_length), do: String.duplicate("x", length)
1104+
1105+
1106+
defp _not_exported(), do: 0xFF + 0xF_F - 0xff
1107+
1108+
1109+
def other(foo, bar) do
1110+
fun = fn{_a, b} -&gt; b + 1_3.1_4 end
1111+
fun.(1.0e+20)
1112+
_str = "string without #{inspect(42)} interpolation" &lt;&gt; " some more
1113+
with newlines \
1114+
and newlines"
1115+
charlist = 'some\'chars
1116+
with newlines \
1117+
and newlines'
1118+
&lt;&lt;x::utf8, _y::size(8), data::binary&gt;&gt; = "fooo"
1119+
ls = [1 | [2, 3]]
1120+
map = %{"baz" =&gt; "ban"}
1121+
map = %{foo: :bar, "yes, this compiles": :"also an atom"}
1122+
:erlang.time()
1123+
case {foo, bar} do
1124+
{1, 2} -&gt; 3
1125+
_something_else -&gt; :error
1126+
_ -&gt; :"this won't match"
1127+
end
1128+
r = 2
1129+
_bitwise_not = ~~~r
1130+
1131+
~r/foo/iu # regex sigils are treated as normal ones
1132+
~S|we have "quotes" and 'quotes' and| &lt;&gt; " more string"
1133+
~c"custom sigil char \"is\" fine too"
1134+
~r'hello'
1135+
~w[hell\] #o] #sigil does not expand to the comment
1136+
~w{hello}
1137+
~C&lt;hello&gt;
1138+
end
1139+
1140+
end
1141+
</pre>
1142+
10861143
</body>
10871144
</html>

tests/prettify_test_2.js

+53-1
Original file line numberDiff line numberDiff line change
@@ -956,5 +956,57 @@ var goldens = {
956956
'%%}`END`PLN\n' +
957957
'`END<span class="ident">y`END`PUN=`END`LIT20`END`PUN;`END`PLN\n' +
958958
'`END`COM%}`END'
959-
)
959+
),
960+
elixir: ('`KWDdefmodule`END`PLN `END`TYPFoo`END`PUN.`END`TYPBar`END`PLN `END`KWDdo`END`PLN\n' +
961+
' `END`ATN@moduledoc`END`PLN `END`STR"""\n' +
962+
' Tests syntax highlighting for Elixir\n' +
963+
' """`END`PLN\n' +
964+
'\n' +
965+
' `END`KWDuse`END`PLN `END`TYPBitwise`END`PLN\n' +
966+
' `END`KWDrequire`END`PLN `END`TYPLogger`END`PLN\n' +
967+
' `END`KWDalias`END`PLN `END`ATN__MODULE__`END`PUN,`END`PLN `END`LITas:`END`PLN `END`TYPThis`END`PLN\n' +
968+
'\n' +
969+
' `END`ATN@default_token_length`END`PLN `END`LIT10_000`END`PLN\n' +
970+
'\n' +
971+
'\n' +
972+
' `END`ATN@spec`END`PLN token`END`PUN(`END`PLNlength `END`PUN::`END`PLN integer`END`PUN)`END`PLN `END`PUN::`END`PLN `END`TYPString`END`PUN.`END`PLNt\n' +
973+
'\n' +
974+
' `END`KWDdef`END`PLN token`END`PUN(`END`PLNlength `END`PUN\\\\`END`PLN `END`ATN@default_token_length`END`PUN),`END`PLN `END`KWDdo`END`PUN:`END`PLN `END`TYPString`END`PUN.`END`PLNduplicate`END`PUN(`END`STR"x"`END`PUN,`END`PLN length`END`PUN)`END`PLN\n' +
975+
'\n' +
976+
'\n' +
977+
' `END`KWDdefp`END`PLN `END`COM_not_exported`END`PUN(),`END`PLN `END`KWDdo`END`PUN:`END`PLN `END`LIT0xFF`END`PLN `END`PUN+`END`PLN `END`LIT0xF_F`END`PLN `END`PUN-`END`PLN `END`LIT0xff`END`PLN\n' +
978+
'\n' +
979+
'\n' +
980+
' `END`KWDdef`END`PLN other`END`PUN(`END`PLNfoo`END`PUN,`END`PLN bar`END`PUN)`END`PLN `END`KWDdo`END`PLN\n' +
981+
' fun `END`PUN=`END`PLN `END`KWDfn`END`PUN{`END`COM_a`END`PUN,`END`PLN b`END`PUN}`END`PLN `END`PUN-&gt;`END`PLN b `END`PUN+`END`PLN `END`LIT1_3.1_4`END`PLN `END`KWDend`END`PLN\n' +
982+
' fun`END`PUN.(`END`LIT1.0e+20`END`PUN)`END`PLN\n' +
983+
' `END`COM_str`END`PLN `END`PUN=`END`PLN `END`STR"string without #{inspect(42)} interpolation"`END`PLN `END`PUN&lt;&gt;`END`PLN `END`STR" some more\n' +
984+
' with newlines \\\n' +
985+
' and newlines"`END`PLN\n' +
986+
' charlist `END`PUN=`END`PLN `END`LIT\'some\\\'chars\n' +
987+
' with newlines \\\n' +
988+
' and newlines\'`END`PLN\n' +
989+
' `END`PUN&lt;&lt;`END`PLNx`END`PUN::`END`PLNutf8`END`PUN,`END`PLN `END`COM_y`END`PUN::`END`PLNsize`END`PUN(`END`LIT8`END`PUN),`END`PLN data`END`PUN::`END`PLNbinary`END`PUN&gt;&gt;`END`PLN `END`PUN=`END`PLN `END`STR"fooo"`END`PLN\n' +
990+
' ls `END`PUN=`END`PLN `END`PUN[`END`LIT1`END`PLN `END`PUN|`END`PLN `END`PUN[`END`LIT2`END`PUN,`END`PLN `END`LIT3`END`PUN]]`END`PLN\n' +
991+
' map `END`PUN=`END`PLN `END`PUN%{`END`STR"baz"`END`PLN `END`PUN=&gt;`END`PLN `END`STR"ban"`END`PUN}`END`PLN\n' +
992+
' map `END`PUN=`END`PLN `END`PUN%{`END`LITfoo:`END`PLN `END`LIT:bar`END`PUN,`END`PLN `END`LIT"yes, this compiles":`END`PLN `END`LIT:"also an atom"`END`PUN}`END`PLN\n' +
993+
' `END`LIT:erlang`END`PUN.`END`PLNtime`END`PUN()`END`PLN\n' +
994+
' `END`KWDcase`END`PLN `END`PUN{`END`PLNfoo`END`PUN,`END`PLN bar`END`PUN}`END`PLN `END`KWDdo`END`PLN\n' +
995+
' `END`PUN{`END`LIT1`END`PUN,`END`PLN `END`LIT2`END`PUN}`END`PLN `END`PUN-&gt;`END`PLN `END`LIT3`END`PLN\n' +
996+
' `END`COM_something_else`END`PLN `END`PUN-&gt;`END`PLN `END`LIT:error`END`PLN\n' +
997+
' `END`COM_`END`PLN `END`PUN-&gt;`END`PLN `END`LIT:"this won\'t match"`END`PLN\n' +
998+
' `END`KWDend`END`PLN\n' +
999+
' r `END`PUN=`END`PLN `END`LIT2`END`PLN\n' +
1000+
' `END`COM_bitwise_not`END`PLN `END`PUN=`END`PLN `END`PUN~~~`END`PLNr\n' +
1001+
'\n' +
1002+
' `END`ATV~r/foo/iu`END`PLN `END`COM# regex sigils are treated as normal ones`END`PLN\n' +
1003+
' `END`ATV~S|we have "quotes" and \'quotes\' and|`END`PLN `END`PUN&lt;&gt;`END`PLN `END`STR" more string"`END`PLN\n' +
1004+
' `END`ATV~c"custom sigil char \\"is\\" fine too"`END`PLN\n' +
1005+
' `END`ATV~r\'hello\'`END`PLN\n' +
1006+
' `END`ATV~w[hell\\] #o]`END`PLN `END`COM#sigil does not expand to the comment`END`PLN\n' +
1007+
' `END`ATV~w{hello}`END`PLN\n' +
1008+
' `END`ATV~C&lt;hello&gt;`END`PLN\n' +
1009+
' `END`KWDend`END`PLN\n' +
1010+
'\n' +
1011+
'`END`KWDend`END')
9601012
};

0 commit comments

Comments
 (0)