1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Develop (run) where
5import Control.Applicative ((<|>))
6import Control.Concurrent (threadDelay)
7import Control.Monad (guard)
8import Control.Monad.Trans (MonadIO(liftIO))
9import qualified Data.HashMap.Strict as HashMap
10import qualified Data.ByteString.Char8 as BSC
11import System.Directory
14import Snap.Http.Server
15import Snap.Util.FileServe
16import qualified Text.Blaze.Html5 as H
17import qualified Text.Blaze.Html.Renderer.Utf8 as Blaze
19import qualified CommandLine.Args as Args
20import qualified Develop.Compile as Compile
21import qualified Develop.Generate.Help as Generate
22import qualified Develop.Generate.Index as Index
23import qualified Develop.Generate.NotFound as NotFound
24import qualified Develop.StaticFiles as StaticFiles
31run :: Args.DevFlags -> IO ()
32run (Args.DevFlags maybePort) =
33 -- TODO get `elm reactor` running again
36 "The reactor is not available in the ALPHA period.\n\
38 \The goal is for package authors to get code updated and give early feedback.\n\
39 \Professionals and hobbyists should NOT be ugrading at this time!\n"
43 maybe 8000 id maybePort
45 do putStrLn (startupMessage port)
47 httpServe (config port) $
49 <|> route [ ("_compile", compile) ]
50 <|> route [ ("_elm/move-to-root", moveToRoot)]
51 <|> route [ ("_elm/create-new-project", createNewProject)]
52 <|> serveDirectoryWith directoryConfig "."
57config :: Int -> Config Snap a
62 # setAccessLog ConfigNoLog
63 # setErrorLog ConfigNoLog
66(#) :: a -> (a -> b) -> b
75startupMessage :: Int -> String
77 "Go to <http://localhost:" ++ show port ++ "> to see your project dashboard."
80directoryConfig :: MonadSnap m => DirectoryConfig m
83 customGenerator directory =
84 do project <- liftIO (Index.getProject directory)
85 modifyResponse $ setContentType "text/html; charset=utf-8"
86 writeBuilder (Blaze.renderHtmlBuilder (Index.toHtml project))
90 , indexGenerator = customGenerator
96 do file <- getSafePath
97 guard =<< liftIO (doesFileExist file)
98 modifyResponse (setContentType "text/javascript")
99 writeBS =<< liftIO (Compile.toJavaScript file)
104 do modifyResponse $ setResponseStatus 404 "Not Found"
105 modifyResponse $ setContentType "text/html; charset=utf-8"
106 writeBuilder (Blaze.renderHtmlBuilder NotFound.html)
113createNewProject :: Snap ()
115 do liftIO $ threadDelay (2 * 1000 * 1000)
121 liftIO Index.moveToRoot
130 do file <- getSafePath
131 guard =<< liftIO (doesFileExist file)
132 serveElm file <|> serveFilePretty file
135serveHtml :: MonadSnap m => H.Html -> m ()
137 do modifyResponse (setContentType "text/html")
138 writeBuilder (Blaze.renderHtmlBuilder html)
142-- SERVE FILES + CODE HIGHLIGHTING
145serveFilePretty :: FilePath -> Snap ()
146serveFilePretty file =
149 getSubExts (takeExtensions file)
151 case mconcat (map lookupMimeType possibleExtensions) of
156 serveFileAs mimeType file
159getSubExts :: String -> [String]
160getSubExts fullExtension =
161 if null fullExtension then
165 fullExtension : getSubExts (takeExtensions (drop 1 fullExtension))
168serveCode :: String -> Snap ()
170 do code <- liftIO (readFile file)
171 serveHtml $ Generate.makeCodeHtml ('~' : '/' : file) code
178serveElm :: FilePath -> Snap ()
180 do guard (takeExtension file == ".elm")
181 serveHtml (Generate.makeElmHtml file)
185-- SERVE STATIC ASSETS
188serveAssets :: Snap ()
190 do file <- getSafePath
191 case StaticFiles.lookup file of
195 Just (content, mimeType) ->
196 do modifyResponse (setContentType $ BSC.pack (mimeType ++ ";charset=utf-8"))
204lookupMimeType :: FilePath -> Maybe BSC.ByteString
206 HashMap.lookup ext mimeTypeDict
209(==>) :: a -> b -> (a,b)
214mimeTypeDict :: HashMap.HashMap FilePath BSC.ByteString
217 [ ".asc" ==> "text/plain"
218 , ".asf" ==> "video/x-ms-asf"
219 , ".asx" ==> "video/x-ms-asf"
220 , ".avi" ==> "video/x-msvideo"
221 , ".bz2" ==> "application/x-bzip"
222 , ".css" ==> "text/css"
223 , ".dtd" ==> "text/xml"
224 , ".dvi" ==> "application/x-dvi"
225 , ".gif" ==> "image/gif"
226 , ".gz" ==> "application/x-gzip"
227 , ".htm" ==> "text/html"
228 , ".html" ==> "text/html"
229 , ".ico" ==> "image/x-icon"
230 , ".jpeg" ==> "image/jpeg"
231 , ".jpg" ==> "image/jpeg"
232 , ".js" ==> "text/javascript"
233 , ".json" ==> "application/json"
234 , ".m3u" ==> "audio/x-mpegurl"
235 , ".mov" ==> "video/quicktime"
236 , ".mp3" ==> "audio/mpeg"
237 , ".mpeg" ==> "video/mpeg"
238 , ".mpg" ==> "video/mpeg"
239 , ".ogg" ==> "application/ogg"
240 , ".pac" ==> "application/x-ns-proxy-autoconfig"
241 , ".pdf" ==> "application/pdf"
242 , ".png" ==> "image/png"
243 , ".qt" ==> "video/quicktime"
244 , ".sig" ==> "application/pgp-signature"
245 , ".spl" ==> "application/futuresplash"
246 , ".svg" ==> "image/svg+xml"
247 , ".swf" ==> "application/x-shockwave-flash"
248 , ".tar" ==> "application/x-tar"
249 , ".tar.bz2" ==> "application/x-bzip-compressed-tar"
250 , ".tar.gz" ==> "application/x-tgz"
251 , ".tbz" ==> "application/x-bzip-compressed-tar"
252 , ".text" ==> "text/plain"
253 , ".tgz" ==> "application/x-tgz"
254 , ".ttf" ==> "application/x-font-truetype"
255 , ".txt" ==> "text/plain"
256 , ".wav" ==> "audio/x-wav"
257 , ".wax" ==> "audio/x-ms-wax"
258 , ".wma" ==> "audio/x-ms-wma"
259 , ".wmv" ==> "video/x-ms-wmv"
260 , ".xbm" ==> "image/x-xbitmap"
261 , ".xml" ==> "text/xml"
262 , ".xpm" ==> "image/x-xpixmap"
263 , ".xwd" ==> "image/x-xwindowdump"
264 , ".zip" ==> "application/zip"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list