Skip to content

Commit 391f0d7

Browse files
committed
Use file-embed to avoid reading files from disk
1 parent 7e2d8d8 commit 391f0d7

19 files changed

+267
-264
lines changed

Main.hs

Lines changed: 31 additions & 258 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
--
1313
-----------------------------------------------------------------------------
1414

15-
{-# LANGUAGE OverloadedStrings #-}
15+
{-# LANGUAGE OverloadedStrings, TemplateHaskell #-}
1616

1717
module Main (
1818
main
@@ -40,8 +40,13 @@ import qualified System.IO.UTF8 as U
4040

4141
import qualified Paths_trypurescript as Paths
4242

43-
preludeFilename :: IO FilePath
44-
preludeFilename = Paths.getDataFileName "prelude/prelude.purs"
43+
import qualified Data.ByteString as B
44+
import qualified Data.ByteString.UTF8 as BU
45+
46+
import Data.FileEmbed
47+
48+
prelude :: String
49+
prelude = BU.toString $(embedFile "prelude/prelude.purs")
4550

4651
data Compiled = Compiled { js :: String
4752
, externs :: String
@@ -72,257 +77,34 @@ mono :: H.Html -> H.Html
7277
mono h = h ! A.class_ "mono"
7378

7479
examplesJs :: String
75-
examplesJs = unlines
76-
[ "$('#examples').change(function() {"
77-
, " var name = $('#examples').val();"
78-
, " if (name) {"
79-
, " window.location = '/example/' + name;"
80-
, " }"
81-
, "});"
82-
]
80+
examplesJs = BU.toString $(embedFile "assets/examples.js")
8381

8482
css :: String
85-
css = unlines
86-
[ "body { font-family: 'Lato', sans-serif; color: #404040; margin: 0; }"
87-
, ".mono { font-family: 'Ubuntu Mono', monospace; white-space: pre; word-break: break-all; word-wrap: break-word; }"
88-
, ".header { margin: 0; background: #202028; box-shadow: 0 0 10px #808080; color: #E0E0E0; }"
89-
, ".splitter { margin: 0; height: 5px; background: #606068; }"
90-
, ".center { margin: 0 auto; padding: 20px; }"
91-
, "a { color: #808080; }"
92-
, "button { background: #d0d0d0; color: #606060; padding-top: 3px; padding-bottom: 3px; font-weight: bold; border-radius: 1px; border: 1px solid #c0c0c0; box-shadow: 1px 1px 0 0 #ffffff inset; padding-left: 15px; padding-right: 15px; cursor: pointer; }"
93-
, "button:hover { background: #e0e0e0; }"
94-
, "#code, #js { margin: 10px; }"]
83+
css = BU.toString $(embedFile "assets/style.css")
9584

9685
gaq :: String
97-
gaq = unlines
98-
[ "var _gaq = _gaq || [];"
99-
, "_gaq.push(['_setAccount', 'UA-33896432-1']);"
100-
, "_gaq.push(['_trackPageview']);"
101-
, "(function() {"
102-
, " var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;"
103-
, " ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';"
104-
, " var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);"
105-
, "})();" ]
86+
gaq = BU.toString $(embedFile "assets/gaq.js")
10687

107-
ace :: Bool -> String
108-
ace js = unlines $
109-
[ "var editor = ace.edit('code');"
110-
, "editor.setTheme('ace/theme/dawn');"
111-
, "editor.renderer.setShowGutter(false);"
112-
, "var session = editor.getSession();"
113-
, "session.setMode('ace/mode/haskell');"
114-
, "session.setValue($('#textarea').val());"
115-
, "session.setUseWrapMode(true);"
116-
, "session.on('change', function(){"
117-
, " $('#textarea').val(editor.getSession().getValue());"
118-
, "});"
119-
, "if ($('#js')[0]) {"
120-
, " var js = ace.edit('js');"
121-
, " js.setTheme('ace/theme/dawn');"
122-
, " js.renderer.setShowGutter(false);"
123-
, " js.setReadOnly(true);"
124-
, " var session = js.getSession();"
125-
, " session.setUseWrapMode(true);"
126-
]
127-
++ (if js then
128-
[ " session.setMode('ace/mode/javascript');" ]
129-
else
130-
[]) ++
131-
[ "}"
132-
, "function setHeight() {"
133-
, " var top = $('#code').offset().top;"
134-
, " var tot = $(window).height();"
135-
, " var height = Math.max(tot - top - 50, 200);"
136-
, " $('#code').height(height + 'px');"
137-
, " $('#js').height(height + 'px');"
138-
, "}"
139-
, "$(setHeight);"
140-
, "$(window).on('resize', setHeight);" ]
88+
ace :: String
89+
ace = BU.toString $(embedFile "assets/ace.js")
90+
91+
defaultCode :: String
92+
defaultCode = BU.toString $(embedFile "examples/default.purs")
14193

14294
examples :: [(String, (String, String))]
14395
examples =
144-
[ ("adt",
145-
("Algebraic Data Types",
146-
unlines [ "module Main where"
147-
, ""
148-
, "import Prelude"
149-
, ""
150-
, "data Person = Person { name :: String, age :: Number }"
151-
, ""
152-
, "foreign import numberToString :: Number -> String"
153-
, ""
154-
, "showPerson (Person { name = name, age = age }) ="
155-
, " name ++ \", aged \" ++ numberToString age"
156-
]))
157-
, ("ops",
158-
("Operators",
159-
unlines [ "module Main where"
160-
, ""
161-
, "import Prelude ()"
162-
, ""
163-
, "infixl 5 >>>"
164-
, ""
165-
, "(>>>) :: forall a b c. (a -> b) -> (b -> c) -> a -> c"
166-
, "(>>>) f g a = g (f a)"
167-
, ""
168-
, "foreign import foo :: String -> Number"
169-
, "foreign import bar :: Number -> Boolean"
170-
, ""
171-
, "test = foo >>> bar"
172-
]))
173-
, ("arrays",
174-
("Arrays",
175-
unlines [ "module Main where"
176-
, ""
177-
, "import Prelude"
178-
, ""
179-
, "sum (x:xs) = x + sum xs"
180-
, "sum _ = 0"
181-
, ""
182-
, "sumOfProducts (x : y : xs) = x * y + sumOfProducts xs"
183-
, "sumOfProducts _ = 0"
184-
]))
185-
, ("rows",
186-
("Row Polymorphism",
187-
unlines [ "module Main where"
188-
, ""
189-
, "import Prelude"
190-
, ""
191-
, "showPerson o = o.lastName ++ \", \" ++ o.firstName"
192-
]))
193-
, ("ffi",
194-
("FFI",
195-
unlines [ "module Main where"
196-
, ""
197-
, "foreign import data IO :: * -> *"
198-
, ""
199-
, "foreign import log \"function log(s) { return function() { console.log(s) }; }\" :: String -> IO { }"
200-
, ""
201-
, "main = log \"Hello World!\""
202-
]))
203-
, ("blocks",
204-
("Mutable Variables",
205-
unlines [ "module Main where"
206-
, ""
207-
, "import Prelude"
208-
, "import Control.Monad.Eff"
209-
, "import Control.Monad.ST"
210-
, ""
211-
, "collatz :: Number -> Number"
212-
, "collatz n = runPure (runST (do"
213-
, " r <- newSTRef n"
214-
, " count <- newSTRef 0"
215-
, " untilE $ do"
216-
, " modifySTRef count $ (+) 1"
217-
, " m <- readSTRef r"
218-
, " writeSTRef r $ if m % 2 == 0 then m / 2 else 3 * m + 1"
219-
, " return $ m == 1"
220-
, " readSTRef count))"
221-
]))
222-
, ("modules",
223-
("Modules",
224-
unlines [ "module M1 where"
225-
, ""
226-
, "import Prelude"
227-
, ""
228-
, "incr :: Number -> Number"
229-
, "incr x = x + 1"
230-
, ""
231-
, "module Main where"
232-
, ""
233-
, "test = M1.incr 10"
234-
]))
235-
, ("rank2",
236-
("Rank N Types",
237-
unlines [ "module Main where"
238-
, ""
239-
, "type Nat = forall a. a -> (a -> a) -> a"
240-
, ""
241-
, "zero :: Nat"
242-
, "zero a _ = a"
243-
, ""
244-
, "succ :: Nat -> Nat"
245-
, "succ n a f = f (n a f)"
246-
, ""
247-
, "type Lens a b = forall f. (a -> f a) -> b -> f b"
248-
, ""
249-
, "compose :: forall a b c. Lens a b -> Lens b c -> Lens a c"
250-
, "compose l1 l2 f = l2 (l1 f)"
251-
]))
252-
, ("recursion",
253-
("Recursion",
254-
unlines [ "module Main where"
255-
, ""
256-
, "import Prelude"
257-
, ""
258-
, "isOdd :: Number -> Boolean"
259-
, "isOdd 0 = false"
260-
, "isOdd n = isEven (n - 1)"
261-
, ""
262-
, "isEven :: Number -> Boolean"
263-
, "isEven 0 = true"
264-
, "isEven n = isOdd (n - 1)"
265-
]))
266-
, ("do",
267-
("Do Notation",
268-
unlines [ "module Main where"
269-
, ""
270-
, "import Prelude"
271-
, ""
272-
, "data Maybe a = Nothing | Just a"
273-
, ""
274-
, "instance monadMaybe :: Prelude.Monad Maybe where"
275-
, " return = Just"
276-
, " (>>=) Nothing _ = Nothing"
277-
, " (>>=) (Just a) f = f a"
278-
, ""
279-
, "isEven n | n % 2 == 0 = Just {}"
280-
, "isEven _ = Nothing"
281-
, ""
282-
, "evenSum a b = do"
283-
, " n <- a"
284-
, " m <- b"
285-
, " let sum = n + m"
286-
, " isEven sum"
287-
, " return sum"
288-
]))
289-
, ("tco",
290-
("Tail-Call Elimination",
291-
unlines [ "module Main where"
292-
, ""
293-
, "import Prelude"
294-
, ""
295-
, "factHelper prod 0 = prod"
296-
, "factHelper prod n = factHelper (prod * n) (n - 1)"
297-
, ""
298-
, "fact = factHelper 1"
299-
]))
300-
, ("typeclasses",
301-
("Type Classes",
302-
unlines [ "module Main where"
303-
, ""
304-
, "import Prelude ((++))"
305-
, ""
306-
, "class Show a where"
307-
, " show :: a -> String"
308-
, ""
309-
, "instance showString :: Show String where"
310-
, " show s = s"
311-
, ""
312-
, "instance showBoolean :: Show Boolean where"
313-
, " show true = \"true\""
314-
, " show false = \"false\""
315-
, ""
316-
, "instance showArray :: (Show a) => Show [a] where"
317-
, " show arr = \"[\" ++ go arr ++ \"]\""
318-
, " where"
319-
, " go :: forall a. (Show a) => [a] -> String"
320-
, " go [] = \"\""
321-
, " go [x] = show x"
322-
, " go (x:xs) = show x ++ \", \" ++ go xs"
323-
, ""
324-
, "test = show [true, false]"
325-
]))
96+
[ ("adt", ("Algebraic Data Types", BU.toString $(embedFile "examples/adt.purs")))
97+
, ("ops", ("Operators", BU.toString $(embedFile "examples/operators.purs")))
98+
, ("arrays", ("Arrays", BU.toString $(embedFile "examples/arrays.purs")))
99+
, ("rows", ("Row Polymorphism", BU.toString $(embedFile "examples/rows.purs")))
100+
, ("ffi", ("FFI", BU.toString $(embedFile "examples/ffi.purs")))
101+
, ("mutable", ("Mutable Variables", BU.toString $(embedFile "examples/mutable.purs")))
102+
, ("modules", ("Modules", BU.toString $(embedFile "examples/modules.purs")))
103+
, ("rank2", ("Rank N Types", BU.toString $(embedFile "examples/rankn.purs")))
104+
, ("recursion", ("Recursion", BU.toString $(embedFile "examples/recursion.purs")))
105+
, ("do", ("Do Notation", BU.toString $(embedFile "examples/do.purs")))
106+
, ("tco", ("Tail-Call Elimination", BU.toString $(embedFile "examples/tco.purs")))
107+
, ("typeclasses", ("Type Classes", BU.toString $(embedFile "examples/typeclasses.purs")))
326108
]
327109

328110
page :: Maybe String -> Maybe String -> Maybe Response -> ActionM ()
@@ -373,7 +155,8 @@ page ex input res = html $ renderHtml $ do
373155
H.div ! A.style "position: absolute; width: 50%; left: 50%;" $ do
374156
H.h2 $ H.toHtml $ str "Generated Javascript"
375157
H.div ! A.id "js" $ H.toHtml . str $ text
376-
H.script ! A.type_ "text/javascript" $ preEscapedToHtml (ace success)
158+
H.script ! A.type_ "text/javascript" $ preEscapedToHtml $ str $ "var compiledSuccessfully = " ++ if success then "true;" else "false;"
159+
H.script ! A.type_ "text/javascript" $ preEscapedToHtml ace
377160

378161
responseToJs :: Maybe Response -> (Bool, String)
379162
responseToJs Nothing = (False, "")
@@ -383,20 +166,10 @@ responseToJs (Just (Response (Right (Compiled js _)))) = (True, js)
383166

384167
server :: Int -> IO ()
385168
server port = do
386-
prelude <- preludeFilename >>= U.readFile
387169
let preludeModules = either (error . show) id $ P.runIndentParser "" P.parseModules prelude
388170
scotty port $ do
389171
get "/" $ do
390-
page Nothing (Just (unlines [ "-- Type PureScript code here and click 'Compile' ..."
391-
, "-- "
392-
, "-- Or select an example from the list at the top right of the page"
393-
, ""
394-
, "module Main where"
395-
, ""
396-
, "import Debug.Trace"
397-
, ""
398-
, "main = trace \"Hello, World!\""
399-
])) Nothing
172+
page Nothing (Just defaultCode) Nothing
400173
get "/example/:name" $ do
401174
name <- param "name"
402175
case lookup name examples of

assets/ace.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
var editor = ace.edit('code');
2+
editor.setTheme('ace/theme/dawn');
3+
editor.renderer.setShowGutter(false);
4+
var session = editor.getSession();
5+
session.setMode('ace/mode/haskell');
6+
session.setValue($('#textarea').val());
7+
session.setUseWrapMode(true);
8+
session.on('change', function(){
9+
$('#textarea').val(editor.getSession().getValue());
10+
});
11+
if ($('#js')[0]) {
12+
var js = ace.edit('js');
13+
js.setTheme('ace/theme/dawn');
14+
js.renderer.setShowGutter(false);
15+
js.setReadOnly(true);
16+
var session = js.getSession();
17+
session.setUseWrapMode(true);
18+
if (compiledSuccessfully) {
19+
session.setMode('ace/mode/javascript');
20+
}
21+
}
22+
function setHeight() {
23+
var top = $('#code').offset().top;
24+
var tot = $(window).height();
25+
var height = Math.max(tot - top - 50, 200);
26+
$('#code').height(height + 'px');
27+
$('#js').height(height + 'px');
28+
}
29+
$(setHeight);
30+
$(window).on('resize', setHeight);

assets/examples.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
$('#examples').change(function() {
2+
var name = $('#examples').val();
3+
if (name) {
4+
window.location = '/example/' + name;
5+
}
6+
});

assets/gaq.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
var _gaq = _gaq || [];
2+
_gaq.push(['_setAccount', 'UA-33896432-1']);
3+
_gaq.push(['_trackPageview']);
4+
(function() {
5+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
6+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
7+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
8+
})();

assets/style.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
body { font-family: 'Lato', sans-serif; color: #404040; margin: 0; }
2+
.mono { font-family: 'Ubuntu Mono', monospace; white-space: pre; word-break: break-all; word-wrap: break-word; }
3+
.header { margin: 0; background: #202028; box-shadow: 0 0 10px #808080; color: #E0E0E0; }
4+
.splitter { margin: 0; height: 5px; background: #606068; }
5+
.center { margin: 0 auto; padding: 20px; }
6+
a { color: #808080; }
7+
button { background: #d0d0d0; color: #606060; padding-top: 3px; padding-bottom: 3px; font-weight: bold; border-radius: 1px; border: 1px solid #c0c0c0; box-shadow: 1px 1px 0 0 #ffffff inset; padding-left: 15px; padding-right: 15px; cursor: pointer; }
8+
button:hover { background: #e0e0e0; }
9+
#code, #js { margin: 10px; }

0 commit comments

Comments
 (0)