Skip to content

Commit bd8e789

Browse files
committed
Add Haskell
Definitely the hardest language to add to date, the UI now looks a bit crap and the Haskell container is massive but it works so I'm taking a break :-P Fixes #37
1 parent 88e1fc0 commit bd8e789

File tree

18 files changed

+345
-25
lines changed

18 files changed

+345
-25
lines changed

assets/common.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ tr.me { background: #5cf }
203203
}
204204

205205
.bash { background: svg(bash#000) center right 7px / 26px no-repeat }
206+
.haskell { background: svg(haskell#000) center right 7px / 26px no-repeat }
206207
.javascript { background: svg(javascript#000) center right 7px / 26px no-repeat }
207208
.lisp { background: svg(lisp#000) center right 7px / 26px no-repeat }
208209
.lua { background: svg(lua#000) center right 7px / 26px no-repeat }

assets/hole.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ button:hover {
8989
#tabs {
9090
clear: both;
9191
display: grid;
92-
grid-template-columns: repeat(9, 1fr);
92+
grid-template-columns: repeat(10, 1fr);
9393
position: relative;
9494
-moz-user-select: none;
9595
-ms-user-select: none;
@@ -125,6 +125,7 @@ button:hover {
125125
}
126126

127127
#tabs a[href="#bash"] { background-image: svg(bash#fff) }
128+
#tabs a[href="#haskell"] { background-image: svg(haskell#fff) }
128129
#tabs a[href="#javascript"] { background-image: svg(javascript#fff) }
129130
#tabs a[href="#lisp"] { background-image: svg(lisp#fff) }
130131
#tabs a[href="#lua"] { background-image: svg(lua#fff) }

assets/hole.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* include codemirror.js */
22
/* include codemirror-bash.js */
33
/* include codemirror-clike.js */
4+
/* include codemirror-haskell.js */
45
/* include codemirror-javascript.js */
56
/* include codemirror-perl6.js */
67
/* include codemirror-perl.js */
@@ -18,7 +19,7 @@ onload = function() {
1819
let activeEditor;
1920
let editors = [];
2021

21-
for (let lang of ['bash', 'javascript', 'lisp', 'lua', 'perl', 'perl6', 'php', 'python', 'ruby']) {
22+
for (let lang of ['bash', 'haskell', 'javascript', 'lisp', 'lua', 'perl', 'perl6', 'php', 'python', 'ruby']) {
2223
let editor = CodeMirror(main, {
2324
lineNumbers: true,
2425
lineWrapping: true,
@@ -48,7 +49,7 @@ onload = function() {
4849

4950
( onhashchange = function() {
5051
// Kick 'em to Perl 6 if we don't know the chosen language.
51-
if (!/^#(?:bash|javascript|lisp|lua|perl6?|php|python|ruby)$/.exec(location.hash))
52+
if (!/^#(?:bash|haskell|javascript|lisp|lua|perl6?|php|python|ruby)$/.exec(location.hash))
5253
location.hash = 'perl6';
5354

5455
let lang = location.hash.slice(1);

assets/holeNg.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ button:hover {
5757
#tabs {
5858
clear: both;
5959
display: grid;
60-
grid-template-columns: repeat(9, 1fr);
60+
grid-template-columns: repeat(10, 1fr);
6161
position: relative;
6262
-moz-user-select: none;
6363
-ms-user-select: none;
@@ -93,6 +93,7 @@ button:hover {
9393
}
9494

9595
#tabs a[href="#bash"] { background-image: svg(bash#fff) }
96+
#tabs a[href="#haskell"] { background-image: svg(haskell#fff) }
9697
#tabs a[href="#javascript"] { background-image: svg(javascript#fff) }
9798
#tabs a[href="#lisp"] { background-image: svg(lisp#fff) }
9899
#tabs a[href="#lua"] { background-image: svg(lua#fff) }

assets/holeNg.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ onload = function() {
8181

8282
( onhashchange = function() {
8383
// Kick 'em to Perl 6 if we don't know the chosen language.
84-
if (!/^#(?:bash|javascript|lisp|lua|perl6?|php|python|ruby)$/.exec(location.hash))
84+
if (!/^#(?:bash|haskell|javascript|lisp|lua|perl6?|php|python|ruby)$/.exec(location.hash))
8585
location.hash = 'perl6';
8686

8787
let lang = location.hash.slice(1);
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2+
// Distributed under an MIT license: http://codemirror.net/LICENSE
3+
4+
(function(mod) {
5+
mod(CodeMirror);
6+
})(function(CodeMirror) {
7+
"use strict";
8+
9+
CodeMirror.defineMode("haskell", function(_config, modeConfig) {
10+
11+
function switchState(source, setState, f) {
12+
setState(f);
13+
return f(source, setState);
14+
}
15+
16+
// These should all be Unicode extended, as per the Haskell 2010 report
17+
var smallRE = /[a-z_]/;
18+
var largeRE = /[A-Z]/;
19+
var digitRE = /\d/;
20+
var hexitRE = /[0-9A-Fa-f]/;
21+
var octitRE = /[0-7]/;
22+
var idRE = /[a-z_A-Z0-9'\xa1-\uffff]/;
23+
var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
24+
var specialRE = /[(),;[\]`{}]/;
25+
var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
26+
27+
function normal(source, setState) {
28+
if (source.eatWhile(whiteCharRE)) {
29+
return null;
30+
}
31+
32+
var ch = source.next();
33+
if (specialRE.test(ch)) {
34+
if (ch == '{' && source.eat('-')) {
35+
var t = "comment";
36+
if (source.eat('#')) {
37+
t = "meta";
38+
}
39+
return switchState(source, setState, ncomment(t, 1));
40+
}
41+
return null;
42+
}
43+
44+
if (ch == '\'') {
45+
if (source.eat('\\')) {
46+
source.next(); // should handle other escapes here
47+
}
48+
else {
49+
source.next();
50+
}
51+
if (source.eat('\'')) {
52+
return "string";
53+
}
54+
return "string error";
55+
}
56+
57+
if (ch == '"') {
58+
return switchState(source, setState, stringLiteral);
59+
}
60+
61+
if (largeRE.test(ch)) {
62+
source.eatWhile(idRE);
63+
if (source.eat('.')) {
64+
return "qualifier";
65+
}
66+
return "variable-2";
67+
}
68+
69+
if (smallRE.test(ch)) {
70+
source.eatWhile(idRE);
71+
return "variable";
72+
}
73+
74+
if (digitRE.test(ch)) {
75+
if (ch == '0') {
76+
if (source.eat(/[xX]/)) {
77+
source.eatWhile(hexitRE); // should require at least 1
78+
return "integer";
79+
}
80+
if (source.eat(/[oO]/)) {
81+
source.eatWhile(octitRE); // should require at least 1
82+
return "number";
83+
}
84+
}
85+
source.eatWhile(digitRE);
86+
var t = "number";
87+
if (source.match(/^\.\d+/)) {
88+
t = "number";
89+
}
90+
if (source.eat(/[eE]/)) {
91+
t = "number";
92+
source.eat(/[-+]/);
93+
source.eatWhile(digitRE); // should require at least 1
94+
}
95+
return t;
96+
}
97+
98+
if (ch == "." && source.eat("."))
99+
return "keyword";
100+
101+
if (symbolRE.test(ch)) {
102+
if (ch == '-' && source.eat(/-/)) {
103+
source.eatWhile(/-/);
104+
if (!source.eat(symbolRE)) {
105+
source.skipToEnd();
106+
return "comment";
107+
}
108+
}
109+
var t = "variable";
110+
if (ch == ':') {
111+
t = "variable-2";
112+
}
113+
source.eatWhile(symbolRE);
114+
return t;
115+
}
116+
117+
return "error";
118+
}
119+
120+
function ncomment(type, nest) {
121+
if (nest == 0) {
122+
return normal;
123+
}
124+
return function(source, setState) {
125+
var currNest = nest;
126+
while (!source.eol()) {
127+
var ch = source.next();
128+
if (ch == '{' && source.eat('-')) {
129+
++currNest;
130+
}
131+
else if (ch == '-' && source.eat('}')) {
132+
--currNest;
133+
if (currNest == 0) {
134+
setState(normal);
135+
return type;
136+
}
137+
}
138+
}
139+
setState(ncomment(type, currNest));
140+
return type;
141+
};
142+
}
143+
144+
function stringLiteral(source, setState) {
145+
while (!source.eol()) {
146+
var ch = source.next();
147+
if (ch == '"') {
148+
setState(normal);
149+
return "string";
150+
}
151+
if (ch == '\\') {
152+
if (source.eol() || source.eat(whiteCharRE)) {
153+
setState(stringGap);
154+
return "string";
155+
}
156+
if (source.eat('&')) {
157+
}
158+
else {
159+
source.next(); // should handle other escapes here
160+
}
161+
}
162+
}
163+
setState(normal);
164+
return "string error";
165+
}
166+
167+
function stringGap(source, setState) {
168+
if (source.eat('\\')) {
169+
return switchState(source, setState, stringLiteral);
170+
}
171+
source.next();
172+
setState(normal);
173+
return "error";
174+
}
175+
176+
177+
var wellKnownWords = (function() {
178+
var wkw = {};
179+
function setType(t) {
180+
return function () {
181+
for (var i = 0; i < arguments.length; i++)
182+
wkw[arguments[i]] = t;
183+
};
184+
}
185+
186+
setType("keyword")(
187+
"case", "class", "data", "default", "deriving", "do", "else", "foreign",
188+
"if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
189+
"module", "newtype", "of", "then", "type", "where", "_");
190+
191+
setType("keyword")(
192+
"\.\.", ":", "::", "=", "\\", "<-", "->", "@", "~", "=>");
193+
194+
setType("builtin")(
195+
"!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<*", "<=",
196+
"<$>", "<*>", "=<<", "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*",
197+
"*>", "**");
198+
199+
setType("builtin")(
200+
"Applicative", "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum",
201+
"Eq", "False", "FilePath", "Float", "Floating", "Fractional", "Functor",
202+
"GT", "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
203+
"Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
204+
"ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
205+
"String", "True");
206+
207+
setType("builtin")(
208+
"abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
209+
"asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
210+
"compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
211+
"cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
212+
"elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
213+
"enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
214+
"flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
215+
"foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
216+
"fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
217+
"getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
218+
"isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
219+
"lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
220+
"mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
221+
"minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
222+
"otherwise", "pi", "pred", "print", "product", "properFraction", "pure",
223+
"putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
224+
"readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
225+
"realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
226+
"round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
227+
"sequence", "sequence_", "show", "showChar", "showList", "showParen",
228+
"showString", "shows", "showsPrec", "significand", "signum", "sin",
229+
"sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
230+
"tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
231+
"toRational", "truncate", "uncurry", "undefined", "unlines", "until",
232+
"unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
233+
"zip3", "zipWith", "zipWith3");
234+
235+
var override = modeConfig.overrideKeywords;
236+
if (override) for (var word in override) if (override.hasOwnProperty(word))
237+
wkw[word] = override[word];
238+
239+
return wkw;
240+
})();
241+
242+
243+
244+
return {
245+
startState: function () { return { f: normal }; },
246+
copyState: function (s) { return { f: s.f }; },
247+
248+
token: function(stream, state) {
249+
var t = state.f(stream, function(s) { state.f = s; });
250+
var w = stream.current();
251+
return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t;
252+
},
253+
254+
blockCommentStart: "{-",
255+
blockCommentEnd: "-}",
256+
lineComment: "--"
257+
};
258+
259+
});
260+
261+
CodeMirror.defineMIME("text/x-haskell", "haskell");
262+
263+
});

assets/includes/haskell.svg

Lines changed: 1 addition & 0 deletions
Loading

assets/user.css

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,12 @@ tr {
101101
}
102102

103103
#matrix tr:first-child th:nth-child(2) { background-image: svg(bash#222) }
104-
#matrix tr:first-child th:nth-child(3) { background-image: svg(javascript#222) }
105-
#matrix tr:first-child th:nth-child(4) { background-image: svg(lisp#222) }
106-
#matrix tr:first-child th:nth-child(5) { background-image: svg(lua#222) }
107-
#matrix tr:first-child th:nth-child(6) { background-image: svg(perl#222) }
108-
#matrix tr:first-child th:nth-child(7) { background-image: svg(perl6#222) }
109-
#matrix tr:first-child th:nth-child(8) { background-image: svg(php#222) }
110-
#matrix tr:first-child th:nth-child(9) { background-image: svg(python#222) }
111-
#matrix tr:first-child th:nth-child(10) { background-image: svg(ruby#222) }
104+
#matrix tr:first-child th:nth-child(3) { background-image: svg(haskell#222) }
105+
#matrix tr:first-child th:nth-child(4) { background-image: svg(javascript#222) }
106+
#matrix tr:first-child th:nth-child(5) { background-image: svg(lisp#222) }
107+
#matrix tr:first-child th:nth-child(6) { background-image: svg(lua#222) }
108+
#matrix tr:first-child th:nth-child(7) { background-image: svg(perl#222) }
109+
#matrix tr:first-child th:nth-child(8) { background-image: svg(perl6#222) }
110+
#matrix tr:first-child th:nth-child(9) { background-image: svg(php#222) }
111+
#matrix tr:first-child th:nth-child(10) { background-image: svg(python#222) }
112+
#matrix tr:first-child th:nth-child(11) { background-image: svg(ruby#222) }

build-langs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ docker pull alpine:edge
44

55
cd containers
66

7-
for name in Bash JavaScript Lisp Lua Perl Perl\ 6 PHP Python Ruby; do
7+
for name in Bash Haskell JavaScript Lisp Lua Perl Perl\ 6 PHP Python Ruby; do
88
lang=${name,,} # lowercase
99
lang=${lang// /} # trim space
1010

@@ -33,10 +33,11 @@ for name in Bash JavaScript Lisp Lua Perl Perl\ 6 PHP Python Ruby; do
3333
docker rm -f $id
3434

3535
# Remove the crap we gained from running the container, this is hacky.
36-
rm -r $lang/rootfs/{.dockerenv,dev,etc,proc,sys}
36+
rm -fr $lang/rootfs/{.dockerenv,dev,etc,proc,sys}
37+
38+
mkdir -p $lang/rootfs/{etc,proc,tmp}
3739

3840
# Python needs UIDs to actually resolve, madness!
39-
mkdir $lang/rootfs/etc
4041
echo nobody:x:99:99:nobody:/:/bin/false > $lang/rootfs/etc/passwd
4142
done
4243

containers/haskell/.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*

0 commit comments

Comments
 (0)