Have terminal/ and browser/ for CLI and reactor

This commit is contained in:
Evan Czaplicki 2018-02-21 18:26:29 -08:00
parent 089b07740c
commit 6dbf13b4d2
36 changed files with 1873 additions and 0 deletions

BIN
browser/assets/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Binary file not shown.

246
browser/assets/styles.css Normal file
View File

@ -0,0 +1,246 @@
@charset "UTF-8";
/* FONTS */
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 400;
src: local('Source Code Pro'), local('SourceCodePro-Regular'), url(/_elm/source-code-pro.ttf) format('truetype');
}
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url(/_elm/source-sans-pro.ttf) format('truetype');
}
/* GENERIC STUFF */
html, head, body {
margin: 0;
height: 100%;
}
body {
font-family: 'Source Sans Pro', 'Trebuchet MS', 'Lucida Grande', 'Bitstream Vera Sans', 'Helvetica Neue', sans-serif;
color: #293c4b;
}
a {
color: #60B5CC;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* INDEX */
.header {
width: 100%;
background-color: #60B5CC;
height: 8px;
}
.content {
width: 960px;
margin-left: auto;
margin-right: auto;
}
/* COLUMNS */
.left-column {
float: left;
width: 600px;
padding-bottom: 80px;
}
.right-column {
float: right;
width: 300px;
padding-bottom: 80px;
}
/* BOXES */
.box {
border: 1px solid #c7c7c7;
border-radius: 5px;
margin-bottom: 40px;
}
.box-header {
display: block;
overflow: hidden;
padding: 7px 12px;
background-color: #fafafa;
text-align: center;
}
.box-item {
display: block;
overflow: hidden;
padding: 7px 12px;
border-top: 1px solid #e1e1e1;
}
.box-footer {
display: block;
overflow: hidden;
padding: 2px 12px;
border-top: 1px solid #e1e1e1;
text-align: center;
background-color: #fafafa;
height: 16px;
}
/* ICONS */
.icon {
display: inline-block;
vertical-align: middle;
padding-right: 0.5em;
}
/* PAGES */
.page-name {
float: left;
}
.page-size {
float: right;
color: #293c4b;
}
.page-size:hover {
color: #60B5CC;
}
/* START */
.start {
width: 500px;
margin-left: auto;
margin-right: auto;
}
.start code {
font-family: 'Source Code Pro', monospace;
padding: 0;
padding-top: 0.2em;
padding-bottom: 0.2em;
margin: 0;
font-size: 85%;
background-color: rgba(0,0,0,0.04);
border-radius: 3px;
}
.start code::before, .start code::after {
letter-spacing: -0.2em;
content: "\00a0";
}
/* START HELLO */
.start-hello {
text-align: center;
padding: calc(50vh - 180px) 0;
}
.start-hello h1 {
font-size: 5em;
margin: 0;
}
/* START DETAILS */
.start-details {
background: rgb(233, 235, 235);
border-top-left-radius: 10px;
border-top-right-radius: 10px;
padding: 1em 2em;
}
.start-details h2 {
text-align: center;
}
.start-details li {
padding-bottom: 0.5em;
}
/* WAITING */
.waiting {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #9A9A9A;
}
/* NOT FOUND */
.not-found {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #F5F5F5;
color: #9A9A9A;
}
/* BUTTONS */
.button {
text-align: center;
}
.button a {
background-color: #7FD13B;
border-radius: 6px;
min-width: 120px;
padding: 12px 24px;
margin: 12px;
display: inline-block;
color: white;
font-size: 1.5em;
cursor: pointer;
}
.button a:hover {
color: white;
background-color: #62BC17;
text-decoration: none;
}
/* POTENTIAL */
.potential h1 {
padding-top: 1em;
font-size: 3em;
}

BIN
browser/assets/waiting.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

48
browser/check.py Executable file
View File

@ -0,0 +1,48 @@
#!/usr/bin/env python
import os
import sys
## FIGURE OUT NEW MODIFICATION TIME
def mostRecentModification(directory):
mostRecent = 0
for dirpath, dirs, files in os.walk(directory):
for f in files:
lastModified = os.path.getmtime(dirpath + '/' + f)
mostRecent = max(int(lastModified), mostRecent)
return mostRecent
srcTime = mostRecentModification('ui/src')
assetTime = mostRecentModification('ui/assets')
mostRecent = max(srcTime, assetTime)
## FIGURE OUT OLD MODIFICATION TIME
with open('ui/last-modified', 'a') as handle:
pass
prevMostRecent = 0
with open('ui/last-modified', 'r+') as handle:
line = handle.read()
prevMostRecent = int(line) if line else 0
## TOUCH FILES IF NECESSARY
if mostRecent > prevMostRecent:
print "+------------------------------------------------------------+"
print "| Some ui/ code changed. Touching src/Reactor/StaticFiles.hs |"
print "| to trigger a recompilation of the Template Haskell stuff. |"
print "+------------------------------------------------------------+"
os.utime('src/Reactor/StaticFiles.hs', None)
with open('ui/last-modified', 'w') as handle:
handle.write(str(mostRecent))

22
browser/elm.json Normal file
View File

@ -0,0 +1,22 @@
{
"type": "browser",
"source-directories": [
"src"
],
"elm-version": "0.19.0",
"dependencies": {
"elm-explorations/markdown": "1.0.0",
"elm-lang/core": "6.0.0",
"elm-lang/html": "3.0.0",
"elm-lang/http": "2.0.0",
"elm-lang/json": "1.0.0",
"elm-lang/project-metadata-utils": "1.0.0",
"elm-lang/svg": "3.0.0"
},
"test-dependencies": {},
"do-not-edit-this-by-hand": {
"transitive-dependencies": {
"elm-lang/virtual-dom": "3.0.0"
}
}
}

145
browser/src/Errors.elm Normal file
View File

@ -0,0 +1,145 @@
module Errors exposing (main)
import Char
import Html exposing (..)
import Html.Attributes exposing (..)
import String
main =
Html.programWithFlags
{ init = init
, update = update
, view = view
, subscriptions = always Sub.none
}
-- MODEL
type alias Model =
String
init : String -> (Model, Cmd msg)
init errorMessage =
(errorMessage, Cmd.none)
-- UPDATE
update : msg -> Model -> (Model, Cmd msg)
update _ model =
(model, Cmd.none)
-- VIEW
view : Model -> Html msg
view model =
div
[ style "width" "100%"
, style "min-height" "100%"
, style "display" "flex"
, style "flex-direction" "column"
, style "align-items" "center"
, style "background-color" "black"
, style "color" "rgb(233, 235, 235)"
, style "font-family" "monospace"
]
[ div
[ style "display" "block"
, style "white-space" "pre"
, style "background-color" "rgb(39, 40, 34)"
, style "padding" "2em"
]
(addColors model)
]
addColors : String -> List (Html msg)
addColors message =
message
|> String.lines
|> List.concatMap addColorToLine
addColorToLine : String -> List (Html msg)
addColorToLine line =
flip (++) [ text "\n" ] <|
if isBreaker line then
[ colorful "rgb(51, 187, 200)" ("\n\n" ++ line) ]
else if isBigBreaker line then
[ colorful "rgb(211, 56, 211)" line ]
else if isUnderline line then
[ colorful "#D5200C" line ]
else if String.startsWith " " line then
[ colorful "#9A9A9A" line ]
else
processLine line
colorful : String -> String -> Html msg
colorful color msg =
span [ style "color" color ] [ text msg ]
isBreaker : String -> Bool
isBreaker line =
String.startsWith "-- " line
&&
String.contains "----------" line
isBigBreaker : String -> Bool
isBigBreaker line =
String.startsWith "===============" line
isUnderline : String -> Bool
isUnderline line =
String.all (\c -> c == ' ' || c == '^') line
isLineNumber : String -> Bool
isLineNumber string =
String.all (\c -> c == ' ' || Char.isDigit c) string
processLine : String -> List (Html msg)
processLine line =
case String.split "|" line of
[] ->
[ text line ]
starter :: rest ->
if not (isLineNumber starter) then
[ text line ]
else
let
restOfLine =
String.join "|" rest
marker =
if String.left 1 restOfLine == ">" then
colorful "#D5200C" ">"
else
text " "
in
[ colorful "#9A9A9A" (starter ++ "|")
, marker
, colorful "#9A9A9A" (String.dropLeft 1 restOfLine)
]

69
browser/src/Index.elm Normal file
View File

@ -0,0 +1,69 @@
module Index exposing (main)
import Html exposing (Html)
import Json.Decode as Decode
import Index.Dashboard as Dashboard
import Index.Project as Project exposing (Project)
-- MAIN
main =
Html.programWithFlags
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
Project
-- INIT
init : Decode.Value -> (Model, Cmd msg)
init flags =
case Project.decode flags of
Err _ ->
Debug.crash "TODO"
Ok project ->
(project, Cmd.none)
-- UPDATE
update : msg -> Model -> (Model, Cmd msg)
update _ model =
(model, Cmd.none)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Html msg
view =
Dashboard.view

View File

@ -0,0 +1,228 @@
module Index.Dashboard exposing
( view
)
import Html exposing (..)
import Html.Attributes exposing (class, href, style, title)
import Elm.Config as Config exposing (Config)
import Elm.License as License
import Elm.Repo as Repo exposing (Repo)
import Elm.Version as Version exposing (Version)
import Index.Icon as Icon
import Index.Navigator as Navigator exposing ((</>))
import Index.Project as Project exposing (Project, File(..))
import Index.Skeleton as Skeleton
-- VIEW
view : Project -> Html msg
view { root, pwd, dirs, files, readme, config } =
Skeleton.view
[ Navigator.view root pwd
, viewLeftColumn dirs files readme
, viewRightColumn config
, clearfix
]
clearfix : Html msg
clearfix =
div [ style "clear" "both" ] []
-- VIEW LEFT COLUMN
viewLeftColumn : List String -> List File -> Maybe String -> Html msg
viewLeftColumn dirs files readme =
section [ class "left-column" ]
[ viewFiles dirs files
, viewReadme readme
]
-- VIEW README
viewReadme : Maybe String -> Html msg
viewReadme readme =
case readme of
Nothing ->
text ""
Just markdown ->
Skeleton.readmeBox markdown
-- VIEW FILES
viewFiles : List String -> List File -> Html msg
viewFiles dirs files =
Skeleton.box
{ title = "File Navigation"
, items = List.map viewDir dirs ++ List.map viewFile files
, footer = Nothing
}
viewDir : String -> List (Html msg)
viewDir dir =
[ a [ href dir ] [ Icon.folder, text dir ]
]
viewFile : File -> List (Html msg)
viewFile file =
case file of
HasMain name ->
[ a [ href name ] [ Icon.lookup name, text name ]
]
NoMain name ->
[ a [ href name ] [ Icon.lookup name, text name ]
]
Other name ->
[ a [ href name ] [ Icon.lookup name, text name ]
]
-- VIEW RIGHT COLUMN
viewRightColumn : Config -> Html msg
viewRightColumn config =
div [ class "right-column" ] <|
case config of
Config.App info ->
[ viewPageSummary info.pages
, viewDeps info.dependencies
, viewTestDeps info.testDependencies
]
Config.Pkg info ->
[ viewPackageSummary info
, viewDeps (exactify info.dependencies)
, viewTestDeps (exactify info.testDependencies)
]
-- VIEW PAGE SUMMARY
viewPageSummary : List String -> Html msg
viewPageSummary pages =
Skeleton.box
{ title = "Pages"
, items = List.map viewPage pages
, footer = Nothing
}
viewPage : String -> List (Html msg)
viewPage name =
[ div
[ style "float" "left"
]
[ Icon.gift
, text name
]
, div
[ style "float" "right"
]
[ text "7kb"
, bundleSize 10
]
]
bundleSize : Int -> Html msg
bundleSize size =
span
[ style "color" "#e1e1e1"
]
[ text (" + " ++ String.fromInt size ++ "kb")
]
-- VIEW PACKAGE SUMMARY
viewPackageSummary : Config.PkgInfo -> Html msg
viewPackageSummary { summary, license, version } =
Skeleton.box
{ title = "Package Information"
, items =
[ [ text ("Version: " ++ Version.toString version) ]
, [ text ("License: " ++ license.code) ]
]
, footer = Nothing
}
-- VIEW DEPENDENCIES
viewDeps : Config.Deps Version -> Html msg
viewDeps deps =
Skeleton.box
{ title = "Dependencies"
, items = List.map viewDep deps
, footer =
Just
( "/_elm/dependencies"
, "Add more dependencies?"
)
}
viewTestDeps : Config.Deps Version -> Html msg
viewTestDeps deps =
Skeleton.box
{ title = "Test Dependencies"
, items = List.map viewDep deps
, footer =
Just
( "/_elm/test-dependencies"
, "Add more test dependencies?"
)
}
viewDep : (Repo, Version) -> List (Html msg)
viewDep (repo, version) =
[ div
[ style "float" "left" ]
[ Icon.package
, a [ href (toPackageUrl repo version) ] [ text (Repo.toString repo) ]
]
, div
[ style "float" "right" ]
[ text (Version.toString version) ]
]
toPackageUrl : Repo -> Version -> String
toPackageUrl name version =
"http://package.elm-lang.org/packages"
</> Repo.toString name
</> Version.toString version
-- TODO - make this actually work!
exactify : Config.Deps a -> Config.Deps Version
exactify deps =
List.map (\(name, _) -> (name, Version 0 0 0)) deps

112
browser/src/Index/Icon.elm Normal file
View File

@ -0,0 +1,112 @@
module Index.Icon exposing
( home
, image
, file
, gift
, folder
, package
, plus
, lookup
)
import Dict
import Html exposing (Html)
import Html.Attributes exposing (class)
import Svg exposing (..)
import Svg.Attributes exposing (width, height, viewBox, d, fill)
-- ICON
icon : String -> String -> String -> Html msg
icon color size path =
svg
[ class "icon"
, width size
, height size
, viewBox "0 0 1792 1792"
]
[ path [ fill color, d path ] []
]
-- NECESSARY ICONS
home : Html msg
home =
icon "#babdb6" "36px" "M1472 992v480q0 26-19 45t-45 19h-384v-384h-256v384h-384q-26 0-45-19t-19-45v-480q0-1 .5-3t.5-3l575-474 575 474q1 2 1 6zm223-69l-62 74q-8 9-21 11h-3q-13 0-21-7l-692-577-692 577q-12 8-24 7-13-2-21-11l-62-74q-8-10-7-23.5t11-21.5l719-599q32-26 76-26t76 26l244 204v-195q0-14 9-23t23-9h192q14 0 23 9t9 23v408l219 182q10 8 11 21.5t-7 23.5z"
image : Html msg
image =
icon "#babdb6" "16px" "M1596 380q28 28 48 76t20 88v1152q0 40-28 68t-68 28h-1344q-40 0-68-28t-28-68v-1600q0-40 28-68t68-28h896q40 0 88 20t76 48zm-444-244v376h376q-10-29-22-41l-313-313q-12-12-41-22zm384 1528v-1024h-416q-40 0-68-28t-28-68v-416h-768v1536h1280zm-128-448v320h-1024v-192l192-192 128 128 384-384zm-832-192q-80 0-136-56t-56-136 56-136 136-56 136 56 56 136-56 136-136 56z"
file : Html msg
file =
icon "#babdb6" "16px" "M1596 380q28 28 48 76t20 88v1152q0 40-28 68t-68 28h-1344q-40 0-68-28t-28-68v-1600q0-40 28-68t68-28h896q40 0 88 20t76 48zm-444-244v376h376q-10-29-22-41l-313-313q-12-12-41-22zm384 1528v-1024h-416q-40 0-68-28t-28-68v-416h-768v1536h1280zm-1024-864q0-14 9-23t23-9h704q14 0 23 9t9 23v64q0 14-9 23t-23 9h-704q-14 0-23-9t-9-23v-64zm736 224q14 0 23 9t9 23v64q0 14-9 23t-23 9h-704q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h704zm0 256q14 0 23 9t9 23v64q0 14-9 23t-23 9h-704q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h704z"
gift : Html msg
gift =
icon "#babdb6" "16px" "M1056 1356v-716h-320v716q0 25 18 38.5t46 13.5h192q28 0 46-13.5t18-38.5zm-456-844h195l-126-161q-26-31-69-31-40 0-68 28t-28 68 28 68 68 28zm688-96q0-40-28-68t-68-28q-43 0-69 31l-125 161h194q40 0 68-28t28-68zm376 256v320q0 14-9 23t-23 9h-96v416q0 40-28 68t-68 28h-1088q-40 0-68-28t-28-68v-416h-96q-14 0-23-9t-9-23v-320q0-14 9-23t23-9h440q-93 0-158.5-65.5t-65.5-158.5 65.5-158.5 158.5-65.5q107 0 168 77l128 165 128-165q61-77 168-77 93 0 158.5 65.5t65.5 158.5-65.5 158.5-158.5 65.5h440q14 0 23 9t9 23z"
folder : Html msg
folder =
icon "#babdb6" "16px" "M1728 608v704q0 92-66 158t-158 66h-1216q-92 0-158-66t-66-158v-960q0-92 66-158t158-66h320q92 0 158 66t66 158v32h672q92 0 158 66t66 158z"
package : Html msg
package =
icon "#babdb6" "16px" "M1088 832q0-26-19-45t-45-19h-256q-26 0-45 19t-19 45 19 45 45 19h256q26 0 45-19t19-45zm576-192v960q0 26-19 45t-45 19h-1408q-26 0-45-19t-19-45v-960q0-26 19-45t45-19h1408q26 0 45 19t19 45zm64-448v256q0 26-19 45t-45 19h-1536q-26 0-45-19t-19-45v-256q0-26 19-45t45-19h1536q26 0 45 19t19 45z"
plus : Html msg
plus =
icon "#babdb6" "16px" "M1600 736v192q0 40-28 68t-68 28h-416v416q0 40-28 68t-68 28h-192q-40 0-68-28t-28-68v-416h-416q-40 0-68-28t-28-68v-192q0-40 28-68t68-28h416v-416q0-40 28-68t68-28h192q40 0 68 28t28 68v416h416q40 0 68 28t28 68z"
-- LOOKUP
lookup : String -> Html msg
lookup fileName =
let
extension =
getExtension fileName
in
Maybe.withDefault file (Dict.get extension extensionIcons)
extensionIcons : Dict.Dict String (Html msg)
extensionIcons =
Dict.fromList
[ ("jpg" , image)
, ("jpeg", image)
, ("png" , image)
, ("gif" , image)
]
getExtension : String -> String
getExtension str =
getExtensionHelp (String.split "." str)
getExtensionHelp : List String -> String
getExtensionHelp segments =
case segments of
[] ->
""
[ext] ->
String.toLower ext
_ :: rest ->
getExtensionHelp rest

View File

@ -0,0 +1,78 @@
module Index.Navigator exposing (view, (</>))
import Color
import Html exposing (..)
import Html.Attributes exposing (..)
import TempFontAwesome as FA
-- ADD SLASHES
(</>) : String -> String -> String
(</>) directory file =
if String.endsWith "/" directory then
directory ++ file
else
directory ++ "/" ++ file
-- VIEW
view : String -> List String -> Html msg
view root dirs =
div
[ style "font-size" "2em"
, style "padding" "20px 0"
, style "display" "flex"
, style "align-items" "center"
, style "height" "40px"
]
(makeLinks root dirs "/" [])
makeLinks : String -> List String -> String -> List (Html msg) -> List (Html msg)
makeLinks root dirs oldPath revAnchors =
case dirs of
dir :: otherDirs ->
let
newPath =
oldPath </> dir
anchor =
a [ href newPath ] [ text dir ]
in
makeLinks root otherDirs newPath (anchor :: revAnchors)
[] ->
let
home =
a [ href "/"
, title root
, style "display" "inherit"
]
[ FA.home Color.darkGrey 36
]
in
case revAnchors of
[] ->
[home]
lastAnchor :: otherRevAnchors ->
home :: slash :: List.foldl addSlash [lastAnchor] otherRevAnchors
addSlash : Html msg -> List (Html msg) -> List (Html msg)
addSlash front back =
front :: slash :: back
slash : Html msg
slash =
span [ style "padding" "0 8px" ] [ text "/" ]

View File

@ -0,0 +1,75 @@
module Index.Skeleton exposing
( view
, box
, readmeBox
)
import Color exposing (Color, darkGrey)
import Html exposing (..)
import Html.Attributes exposing (..)
import Markdown
import TempFontAwesome as FA
-- VIEW
view : List (Html msg) -> Html msg
view content =
div []
[ header [ class "header" ] []
, div [class "content"] content
]
-- VIEW BOXES
type alias BoxArgs msg =
{ title : String
, items : List (List (Html msg))
, footer : Maybe (String, String)
}
box : BoxArgs msg -> Html msg
box { title, items, footer } =
let
realItems =
List.map (div [ class "box-item" ]) items
in
boxHelp title realItems footer
readmeBox : String -> Html msg
readmeBox markdown =
let
readme =
Markdown.toHtml [ class "box-item" ] markdown
in
boxHelp "README" [readme] Nothing
boxHelp : String -> List (Html msg) -> Maybe (String, String) -> Html msg
boxHelp boxTitle items footer =
div [ class "box" ] <|
div [ class "box-header" ] [ text boxTitle ]
:: items
++ [ boxFooter footer ]
boxFooter : Maybe (String, String) -> Html msg
boxFooter maybeFooter =
case maybeFooter of
Nothing ->
text ""
Just (path, description) ->
a [ href path
, title description
]
[ div [ class "box-footer" ] [ FA.plus darkGrey 14 ]
]

256
browser/src/Main.elm Normal file
View File

@ -0,0 +1,256 @@
module Index.Dashboard exposing
( view
)
import Html exposing (..)
import Html.Attributes exposing (class, href, style, title)
import Elm.Config as Config exposing (Config)
import Elm.License as License
import Elm.Repo as Repo exposing (Repo)
import Elm.Version as Version exposing (Version)
import Index.Icon as Icon
import Index.Navigator as Navigator exposing ((</>))
import Index.Project as Project exposing (Project, File(..))
import Index.Skeleton as Skeleton
-- MODEL
type alias Model =
{ path : String
, status : ProjectStatus
, directory : Status Directory
}
type ProjectStatus
= ProjectIsNew
| ProjectIsInvalid
| ProjectIsValid
{ root : String
, project : Project.Project
, exactDeps : List (Package.Name, Version.Version)
}
type DirectoryStatus
= NotFound
| Waiting
| Found Directory
-- DIRECTORY
type alias Directory =
{ dirs : List String
, files : List File
, readme : Maybe String
}
type alias File =
{ name : String
, runnable : Bool
}
-- DECODER
decoder : D.Decoder Directory
decoder =
D.map4 Directory
(D.field "path" (D.list D.string))
(D.field "dirs" (D.list D.string))
(D.field "files" (D.list fileDecoder))
(D.field "readme" (D.nullable D.string))
fileDecoder : D.Decoder File
fileDecoder =
D.map2 File
(D.field "name" D.string)
(D.field "runnable" D.bool)
-- NOT FOUND
notFound : Html msg
notFound =
div [ class "not-found" ]
[ div [ style "font-size" "12em" ] [ text "404" ]
, div [ style "font-size" "3em" ] [ text "Page not found" ]
]
-- WAITING
waiting : Html msg
waiting =
div [ class "waiting" ]
[ img [ src "/_elm/waiting.gif" ] []
]
-- VIEW DIRECTORY
viewDirectory : Project -> Directory -> Html msg
viewDirectory project directory =
Skeleton.view
[ Navigator.view pwd
, section [ class "left-column" ]
[ viewFiles directory.dirs directory.files
, viewReadme directory.readme
]
, section [ class "right-column" ]
[ viewProjectSummary project
, viewDeps project
, viewTestDeps project
]
, div [ style "clear" "both" ] []
]
-- VIEW README
viewReadme : Maybe String -> Html msg
viewReadme readme =
case readme of
Nothing ->
text ""
Just markdown ->
Skeleton.readmeBox markdown
-- VIEW FILES
viewFiles : List String -> List File -> Html msg
viewFiles dirs files =
Skeleton.box
{ title = "File Navigation"
, items = List.map viewDir dirs ++ List.map viewFile files
, footer = Nothing
}
viewDir : String -> List (Html msg)
viewDir dir =
[ a [ href dir ] [ Icon.folder, text dir ]
]
viewFile : File -> List (Html msg)
viewFile {name} =
[ a [ href name ] [ Icon.lookup name, text name ]
]
-- VIEW PAGE SUMMARY
viewProjectSummary : Project.Project -> Html msg
viewProjectSummary project =
case project of
Project.Browser info ->
Skeleton.box
{ title = "Source Directories"
, items = List.map (\dir -> [text dir]) info.dirs
, footer = Nothing
}
-- TODO show estimated bundle size here
Project.Package info ->
Skeleton.box
{ title = "Package Info"
, items =
[ [ text ("Name: " ++ info.name) ]
, [ text ("Version: " ++ Version.toString info.version) ]
, [ text ("License: " ++ License.toString info.license) ]
]
, footer = Nothing
}
-- VIEW DEPENDENCIES
viewDeps : ExactDeps -> Project.Project -> Html msg
viewDeps exactDeps project =
let
dependencies =
case project of
Project.Browser info ->
List.map (viewDependency exactDeps) info.deps
Project.Package info ->
List.map (viewDependency exactDeps) info.deps
in
Skeleton.box
{ title = "Dependencies"
, items = dependencies
, footer = Nothing -- TODO Just ("/_elm/dependencies", "Add more dependencies?")
}
viewTestDeps : ExactDeps -> Project.Project -> Html msg
viewTestDeps exactDeps project =
let
dependencies =
case project of
Project.Browser info ->
List.map (viewDependency exactDeps) info.testDeps
Project.Package info ->
List.map (viewDependency exactDeps) info.testDeps
in
Skeleton.box
{ title = "Test Dependencies"
, items = dependencies
, footer = Nothing -- TODO Just ("/_elm/test-dependencies", "Add more test dependencies?")
}
viewDependency : ExactDeps -> (Package.Name, vsn) -> List (Html msg)
viewDependency exactDeps (pkg, _) =
case Dict.get (Package.toString pkg) exactDeps of
Nothing ->
[ div [ style "float" "left" ]
[ Icon.package
, text (Package.toString pkg)
]
, div [ style "float" "right" ] [ text "???" ]
]
Just version ->
[ div [ style "float" "left" ]
[ Icon.package
, a [ href (toPackageUrl pkg version) ] [ text (Package.toString pkg) ]
]
, div [ style "float" "right" ] [ text (Version.toString version) ]
]
toPackageUrl : Package.Name -> Version.Version -> String
toPackageUrl name version =
"http://package.elm-lang.org/packages/"
++ Package.toString name ++ "/" ++ Version.toString version

0
browser/src/NotFound.elm Normal file
View File

View File

@ -0,0 +1,202 @@
module Page.Directory exposing
( Info
, File(..)
, decoder
)
import Json.Decode as D
import Elm.Project as Project
-- DIRECTORY
type alias Directory =
{ path : List String
, dirs : List String
, files : List File
, readme : Maybe String
}
type alias File =
{ name : String
, runnable : Bool
}
-- DECODER
decoder : D.Decoder Directory
decoder =
D.map4 Directory
(D.field "path" (D.list D.string))
(D.field "dirs" (D.list D.string))
(D.field "files" (D.list fileDecoder))
(D.field "readme" (D.nullable D.string))
fileDecoder : D.Decoder File
fileDecoder =
D.map2 File
(D.field "name" D.string)
(D.field "runnable" D.bool)
-- VIEW
view : Project -> Directory -> Html msg
view project directory =
Skeleton.view
[ Navigator.view pwd
, section [ class "left-column" ]
[ viewFiles directory.dirs directory.files
, viewReadme directory.readme
]
, section [ class "right-column" ]
[ viewProjectSummary project
, viewDeps project
, viewTestDeps project
]
, div [ style "clear" "both" ] []
]
-- VIEW README
viewReadme : Maybe String -> Html msg
viewReadme readme =
case readme of
Nothing ->
text ""
Just markdown ->
Skeleton.readmeBox markdown
-- VIEW FILES
viewFiles : List String -> List File -> Html msg
viewFiles dirs files =
Skeleton.box
{ title = "File Navigation"
, items = List.map viewDir dirs ++ List.map viewFile files
, footer = Nothing
}
viewDir : String -> List (Html msg)
viewDir dir =
[ a [ href dir ] [ Icon.folder, text dir ]
]
viewFile : File -> List (Html msg)
viewFile {name} =
[ a [ href name ] [ Icon.lookup name, text name ]
]
-- VIEW PAGE SUMMARY
viewProjectSummary : Project.Project -> Html msg
viewProjectSummary project =
case project of
Project.Browser info ->
Skeleton.box
{ title = "Source Directories"
, items = List.map (\dir -> [text dir]) info.dirs
, footer = Nothing
}
-- TODO show estimated bundle size here
Project.Package info ->
Skeleton.box
{ title = "Package Info"
, items =
[ [ text ("Name: " ++ info.name) ]
, [ text ("Version: " ++ Version.toString info.version) ]
, [ text ("License: " ++ License.toString info.license) ]
]
, footer = Nothing
}
-- VIEW DEPENDENCIES
viewDeps : ExactDeps -> Project.Project -> Html msg
viewDeps exactDeps project =
let
dependencies =
case project of
Project.Browser info ->
List.map (viewDependency exactDeps) info.deps
Project.Package info ->
List.map (viewDependency exactDeps) info.deps
in
Skeleton.box
{ title = "Dependencies"
, items = dependencies
, footer = Nothing -- TODO Just ("/_elm/dependencies", "Add more dependencies?")
}
viewTestDeps : ExactDeps -> Project.Project -> Html msg
viewTestDeps exactDeps project =
let
dependencies =
case project of
Project.Browser info ->
List.map (viewDependency exactDeps) info.testDeps
Project.Package info ->
List.map (viewDependency exactDeps) info.testDeps
in
Skeleton.box
{ title = "Test Dependencies"
, items = dependencies
, footer = Nothing -- TODO Just ("/_elm/test-dependencies", "Add more test dependencies?")
}
viewDependency : ExactDeps -> (Package.Name, vsn) -> List (Html msg)
viewDependency exactDeps (pkg, _) =
case Dict.get (Package.toString pkg) exactDeps of
Nothing ->
[ div [ style "float" "left" ]
[ Icon.package
, text (Package.toString pkg)
]
, div [ style "float" "right" ] [ text "???" ]
]
Just version ->
[ div [ style "float" "left" ]
[ Icon.package
, a [ href (toPackageUrl pkg version) ] [ text (Package.toString pkg) ]
]
, div [ style "float" "right" ] [ text (Version.toString version) ]
]
toPackageUrl : Package.Name -> Version.Version -> String
toPackageUrl name version =
"http://package.elm-lang.org/packages/"
++ Package.toString name ++ "/" ++ Version.toString version

203
browser/src/Start.elm Normal file
View File

@ -0,0 +1,203 @@
module Start exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Html.Lazy exposing (lazy)
import Http
import Navigation
import String
main =
Html.programWithFlags
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
-- MODEL
type Model
= NoProject String
| PotentialProject String String
| Waiting
-- INIT
type alias Flags =
{ root : String
, suggestion : Maybe String
}
init : Flags -> ( Model, Cmd Msg )
init flags =
case flags.suggestion of
Nothing ->
( NoProject flags.root, Cmd.none )
Just suggestion ->
( PotentialProject flags.root suggestion, Cmd.none )
-- UPDATE
type Msg
= RequestNewProject
| NewProjectReady
| IgnoreSuggestion String
| MoveReactor
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
RequestNewProject ->
( Waiting, createNewProject )
NewProjectReady ->
( Waiting, Navigation.reload )
IgnoreSuggestion root ->
( NoProject root, Cmd.none )
MoveReactor ->
( Waiting, moveReactor )
createNewProject : Cmd Msg
createNewProject =
Http.send (\_ -> NewProjectReady) <|
Http.getString "/_elm/create-new-project"
moveReactor : Cmd Msg
moveReactor =
Http.send (\_ -> NewProjectReady) <|
Http.getString "/_elm/move-to-root"
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
-- VIEW
view : Model -> Html Msg
view model =
case model of
NoProject root ->
viewNoProject root
PotentialProject root suggestion ->
viewPotentialProject root suggestion
Waiting ->
viewWaiting
-- VIEW NO PROJECT
viewNoProject : String -> Html Msg
viewNoProject root =
div [ class "start" ]
[ div [ class "start-hello" ]
[ h1 [] [ text "Hello!" ]
, para "Looks like you are starting a new Elm project. Exciting!"
, para "I will help you get set up. Just press this button!"
, div [ class "button" ]
[ a [ onClick RequestNewProject ] [ text "Create New Project" ]
]
]
, div [ class "start-details" ]
[ h2 [] [ text "What does this button do exactly?" ]
, p []
[ text "In the "
, code [] [ text root ]
, text " directory, I will create:"
]
, ul []
[ file "elm.json" "describes which packages you need."
, file "src/" "a directory for all your Elm code."
, file "src/Main.elm" "an example Elm program."
, file "tests/" "a directory for any tests you write."
]
, para "I will share more details on all this after you press the button!"
]
]
para : String -> Html msg
para str =
p [] [ text str ]
file : String -> String -> Html msg
file fileName description =
li []
[ code [] [ text fileName ]
, text " "
, text description
]
-- VIEW WAITING
viewWaiting : Html msg
viewWaiting =
div [ class "waiting" ]
[ img [ src "/_elm/waiting.gif" ] []
]
-- VIEW POTENTIAL PROJECT
viewPotentialProject : String -> String -> Html Msg
viewPotentialProject root suggestion =
div [ class "start potential" ]
[ h1 [] [ text "Existing Project?" ]
, p []
[ text "You ran "
, code [] [ text "elm-reactor" ]
, text " from "
, code [] [ text root ]
, text " which is not the root of an Elm project."
]
, p []
[ text "I found an Elm project at "
, code [] [ text suggestion ]
, text " though. Would you like to continue developing that one?"
]
, div [ class "button" ]
[ a [ onClick MoveReactor ] [ text "Continue Existing Project" ]
]
, h1 [] [ text "Or New Project?" ]
, para "Or maybe you want some weird nested Elm project, where you have Elm projects within other Elm projects. It is probably better to have them separated, but I can get you set up if that is what you really want!"
, div [ class "button" ]
[ a [ onClick (IgnoreSuggestion root) ] [ text "New Project" ]
]
]

189
elm.cabal Normal file
View File

@ -0,0 +1,189 @@
Name: elm
Version: 0.19.0
Synopsis:
The `elm` command line interface.
Description:
This includes commands like `elm make`, `elm repl`, and many others
for helping make Elm developers happy and productive.
Homepage: http://elm-lang.org
License: BSD3
License-file: LICENSE
Author: Evan Czaplicki
Maintainer: info@elm-lang.org
Copyright: Copyright (c) 2011-present, Evan Czaplicki
Category: Compiler, Language
Cabal-version: >=1.9
Build-type: Simple
source-repository head
type: git
location: git://github.com/elm-lang/elm-compiler.git
Flag dev {
Description: Turn off optimization and make warnings errors
Default: False
}
Executable elm
if flag(dev)
ghc-options: -O0 -Wall -Werror
else
ghc-options: -O2 -fsimpl-tick-factor=200
Hs-Source-Dirs:
compiler/src
builder/src
cli/src
Main-Is:
Main.hs
exposed-modules:
Elm.Compiler,
Elm.Compiler.Module,
Elm.Compiler.Objects,
Elm.Compiler.Type,
Elm.Docs,
Elm.Kernel,
Elm.Header,
Elm.Name,
Elm.Package,
Elm.Utils,
Json.Decode,
Json.Encode
other-modules:
AST.Canonical,
AST.Optimized,
AST.Source,
AST.Module.Name,
AST.Utils.Binop,
AST.Utils.Shader,
AST.Utils.Type,
AST.Valid,
Canonicalize.Effects,
Canonicalize.Environment,
Canonicalize.Environment.Dups,
Canonicalize.Environment.Foreign,
Canonicalize.Environment.Local,
Canonicalize.Expression,
Canonicalize.Module,
Canonicalize.Pattern,
Canonicalize.Type,
Compile,
Data.Bag,
Data.Index,
Data.OneOrMore,
Elm.Compiler.Imports,
Elm.Compiler.Type.Extract,
Elm.Compiler.Version,
Elm.Interface,
Generate.JavaScript,
Generate.JavaScript.Builder,
Generate.JavaScript.Expression,
Generate.JavaScript.Name,
Json.Decode.Internals,
Nitpick.PatternMatches,
Optimize.Case,
Optimize.DecisionTree,
Optimize.Expression,
Optimize.Module,
Optimize.Names,
Optimize.Port,
Parse.Declaration,
Parse.Expression,
Parse.Module,
Parse.Parse,
Parse.Pattern,
Parse.Primitives,
Parse.Primitives.Internals,
Parse.Primitives.Kernel,
Parse.Primitives.Keyword,
Parse.Primitives.Number,
Parse.Primitives.Shader,
Parse.Primitives.Symbol,
Parse.Primitives.Utf8,
Parse.Primitives.Variable,
Parse.Primitives.Whitespace,
Parse.Repl,
Parse.Shader,
Parse.Type,
Reporting.Annotation,
Reporting.Error,
Reporting.Error.Canonicalize,
Reporting.Error.Docs,
Reporting.Error.Json,
Reporting.Error.Main,
Reporting.Error.Pattern,
Reporting.Error.Syntax,
Reporting.Error.Type,
Reporting.Helpers,
Reporting.Region,
Reporting.Render.Code,
Reporting.Render.Type,
Reporting.Report,
Reporting.Result,
Reporting.Warning,
Type.Constrain.Expression,
Type.Constrain.Module,
Type.Constrain.Pattern,
Type.Error,
Type.Instantiate,
Type.Occurs,
Type.Solve,
Type.Type,
Type.Unify,
Type.UnionFind,
Validate,
Paths_elm_compiler
Build-depends:
ansi-terminal >= 0.7 && < 0.8,
ansi-wl-pprint >= 0.6.7 && < 0.7,
base >=4.8 && <5,
binary >= 0.8 && < 0.9,
blaze-html,
blaze-markup,
bytestring >= 0.9 && < 0.11,
containers >= 0.5.8.2 && < 0.6,
directory >= 1.2.3.0 && < 2.0,
edit-distance >= 0.2 && < 0.3,
filepath >= 1 && < 2.0,
ghc-prim,
haskeline,
HTTP >= 4000.2.5 && < 4000.4,
http-client >= 0.5 && < 0.6,
http-client-tls >= 0.3 && < 0.4,
http-types >= 0.9 && < 1.0,
language-glsl >= 0.0.2 && < 0.3,
logict,
mtl >= 2.2.1 && < 3,
network >= 2.4 && < 2.7,
parsec,
pretty >= 1.0 && < 2.0,
process,
raw-strings-qq,
scientific,
semigroups,
SHA,
snap-core,
snap-server,
template-haskell,
text >= 1 && < 2,
time,
unordered-containers,
utf8-string,
vector,
websockets,
websockets-snap,
zip-archive