git.iko.soy/rowtype-yoga/psfp
on master help sign in
Ch-ch-changes
commit21162af38fc6b367f981a7e405414880e5221a12 authorMark Eibes <mark.eibes@gmail.com> dateMon 13 Apr 2020, 22:19 (7 years ago) parent64d8094
12 files changed+56−270
blog/src/components/FillInTheGaps.purs−232 blog/src/components/PSLayout.purs+30−19 blog/src/pages/optional.mdx+6−4 components/src/Yoga/CompileEditor/Component.purs+1−1 components/src/Yoga/Compiler/Api.purs+4−2 components/src/Yoga/FillInTheGaps/Component.purs+1−1 components/src/Yoga/FillInTheGaps/Stories.purs+2−2 playground/run.js+1−1 playground/src/Batteries.purs → playground/src/Grimoire.purs+8−3 playground/src/Main.purs+3−3 playgrounds/.gitkeep server/src/PscIdeClient.purs−2
blog/src/components/FillInTheGaps.pursdeleted−232
@@ -1,232 +0,0 @@
1−module FillInTheGaps where
2−
3−import Prelude
4−
5−import Data.Array (foldMap, intercalate)
6−import Data.Array as A
7−import Data.Either (Either(..))
8−import Data.Foldable (foldl)
9−import Data.Function.Uncurried (mkFn2)
10−import Data.Lens ((%~))
11−import Data.Lens.Index (ix)
12−import Data.Maybe (Maybe(..), fromMaybe', isJust, isNothing)
13−import Data.Monoid (guard)
14−import Data.String (Pattern(..), split)
15−import Data.String as S
16−import Data.String.Regex (Regex)
17−import Data.String.Regex as Regex
18−import Data.String.Regex.Flags as RegexFlags
19−import Data.String.Regex.Unsafe (unsafeRegex)
20−import Data.Tuple.Nested ((/\))
21−import Debug.Trace (spy)
22−import Effect (Effect)
23−import Effect.Aff (launchAff_)
24−import Effect.Class (liftEffect)
25−import Justifill (justifill)
26−import Milkis as M
27−import Milkis.Impl (FetchImpl)
28−import Partial.Unsafe (unsafeCrashWith)
29−import React.Basic (JSX, ReactComponent, element, fragment)
30−import React.Basic.DOM (css)
31−import React.Basic.DOM as R
32−import React.Basic.DOM.Events (preventDefault)
33−import React.Basic.Events (handler, handler_)
34−import React.Basic.Helpers (jsx)
35−import React.Basic.Hooks (component, useState)
36−import React.Basic.Hooks as React
37−import React.Basic.Hooks.Spring (animatedDiv, useTransition)
38−import Shared.Models.Body (CompileResult, RunResult)
39−import Yoga.Button.Component (ButtonType(..), mkButton)
40−import Yoga.ClickAway.Component as ClickAway
41−import Yoga.CloseIcon.Component as CloseIcon
42−import Yoga.Cluster.Component as Cluster
43−import Yoga.CompileEditor.Component (compileAndRun)
44−import Yoga.Helpers ((?||))
45−import Yoga.InlineCode.Component as InlineCode
46−import Yoga.Modal.Component as Modal
47−
48−data Segment
49− = ExpectedResult String
50− | Start
51− | End
52− | Filler String
53− | Hole Int String
54−
55−derive instance eqSegment ∷ Eq Segment
56−getResult ∷ Segment -> Maybe String
57−getResult = case _ of
58− ExpectedResult r -> Just r
59− _ -> Nothing
60−
61−findResult ∷ Array Segment -> String
62−findResult = fromMaybe' (\_ -> unsafeCrashWith "Even teachers make mistakes") <<< A.findMap getResult
63−
64−toCode ∷ (Array (Array Segment)) -> String
65−toCode lines = intercalate "\n" mapped
66− where
67− mapped = lines <#> (intercalate "" <<< map segmentToCode)
68− segmentToCode = case _ of
69− Filler s -> s
70− Hole _ s -> s
71− _ -> ""
72−
73−complete ∷ (Array (Array Segment)) -> Boolean
74−complete arr = foldl f true (join arr)
75− where
76− f acc seg =
77− acc
78− && case seg of
79− Hole _ s -> s /= ""
80− _ -> true
81−
82−visibleRange ∷ Array (Array Segment) -> { end ∷ Int, start ∷ Int }
83−visibleRange arr = { start, end }
84− where
85− start = A.findIndex (_ == [ Start ]) arr ?|| 0
86− end = A.findIndex (_ == [ End ]) arr ?|| A.length arr
87−
88−renderSegments ∷ ReactComponent InlineCode.Props -> ((Array (Array Segment) -> Array (Array Segment)) -> Effect Unit) -> Array (Array Segment) -> JSX
89−renderSegments ic update arrs = R.div_ (A.mapWithIndex renderLine arrs)
90− where
91− { start, end } = visibleRange arrs
92− renderLine i l = R.div_ (A.mapWithIndex (renderSegment i) l)
93− renderSegment i j s =
94− if between start end i then case s of
95− Filler s' -> R.code_ [ R.text s' ]
96− Hole width _ ->
97− element ic
98− $ justifill
99− { width
100− , onSubmit: update <<< updateSegments i j
101− }
102− _ -> mempty
103− else
104− mempty
105−
106−updateSegments ∷ Int -> Int -> String -> Array (Array Segment) -> Array (Array Segment)
107−updateSegments i j v = (ix i <<< ix j) %~ f
108− where
109− f = case _ of
110− Hole h _ -> Hole h v
111− _ -> unsafeCrashWith "Updated a non-hole"
112−
113−holeRegex ∷ Regex
114−holeRegex = unsafeRegex "({-.*?-})" RegexFlags.global
115−
116−resultRegex ∷ Regex
117−resultRegex = unsafeRegex "--result" RegexFlags.global
118−
119−startRegex ∷ Regex
120−startRegex = unsafeRegex "--start here" RegexFlags.global
121−
122−endRegex ∷ Regex
123−endRegex = unsafeRegex "--end here" RegexFlags.global
124−
125−rawSegments ∷ String -> Array String
126−rawSegments = Regex.split holeRegex
127−
128−toSegment ∷ String -> Segment
129−toSegment = case _ of
130− x
131− | Regex.test holeRegex x -> Hole (S.length x - 4) ""
132− x
133− | S.indexOf (Pattern "--result ") x == Just 0 -> ExpectedResult ((S.stripPrefix (Pattern "--result ") x) ?|| "")
134− x
135− | Regex.test startRegex x -> Start
136− x
137− | Regex.test endRegex x -> End
138− other -> Filler other
139−
140−mkFillInTheGaps ∷ FetchImpl -> Effect (ReactComponent { code ∷ String })
141−mkFillInTheGaps fetch = do
142− ic <- InlineCode.makeComponent
143− modal <- Modal.makeComponent
144− closeIcon <- CloseIcon.makeComponent
145− cluster <- Cluster.makeComponent
146− clickAway <- ClickAway.makeComponent
147− button <- mkButton
148− component "FillInTheGaps" \{ code } -> React.do
149− let
150− lines = split (Pattern "\n") code
151−
152− initialSegments = lines <#> \line -> rawSegments line <#> toSegment
153− segments /\ modifySegments <- useState initialSegments
154− result /\ modifyResult <- useState Nothing
155− modalTransitions <-
156− useTransition [ result ] (Just show)
157− $ css
158− { from: { opacity: 0.0, transform: "translate3d(-50%, -50%, 0) scale3d(0.3, 0.3, 1.0)" }
159− , enter: { opacity: 1.0, transform: "translate3d(-50%, -50%, 0) scale3d(1.0, 1.0, 1.0)" }
160− , leave: { opacity: 0.0, transform: "translate3d(-50%, -50%, 0) scale3d(0.3, 0.3, 1.0)" }
161− , config: mkFn2 \_ state ->
162− case spy "state" state of
163− "leave" -> { mass: 1.0, tension: 140, friction: 15 }
164− _ -> { mass: 1.0, tension: 170, friction: 20 }
165− }
166− clickAwayTransitions <-
167− useTransition [ result ] (Just show)
168− $ css
169− { from: { opacity: 0.0 }
170− , enter: { opacity: 1.0 }
171− , leave: { opacity: 0.0 }
172− , config: mkFn2 \_ state ->
173− case spy "state" state of
174− "leave" -> { mass: 1.0, tension: 140, friction: 15 }
175− _ -> { mass: 1.0, tension: 170, friction: 20 }
176− }
177− let
178− expectedResult = findResult (join segments)
179−
180− onClick =
181− launchAff_ do
182− do
183− res <- compileAndRun (M.fetch fetch) { code: toCode segments }
184− modifyResult (const (Just $ res)) # liftEffect
185− pure
186− $ fragment
187− $ [ renderSegments ic (modifySegments) segments
188− , jsx cluster {}
189− [ R.div_
190− [ jsx button
191− { onClick: handler_ onClick
192− , buttonType:
193− if complete segments && isNothing result then
194− HighlightedButton
195− else
196− DisabledButton
197− }
198− [ R.text "Try it" ]
199− ]
200− ]
201− , fragment
202− $ clickAwayTransitions
203− >>= \{ item, key, props } ->
204− guard (isJust item)
205− $ join item
206− # foldMap \_ ->
207− [element clickAway (justifill { allowEscape: true, style: props, onClick: modifyResult (const Nothing) })]
208− , fragment
209− $ modalTransitions
210− >>= \{ item, key, props } ->
211− guard (isJust item)
212− $ join item
213− # foldMap \r ->
214− [ jsx modal
215− { title:
216− case r of
217− (Right { stdout })
218− | S.stripSuffix (S.Pattern "\n") stdout == Just expectedResult -> "Hooray!"
219− (Left l) -> "Does not compile"
220− (Right _) -> "Not " <> (findResult $ join segments)
221− , icon: element closeIcon { onClick: modifyResult (const Nothing), style: Nothing }
222− , style: props
223− }
224− [ R.text $ compileResultToString result ]
225− ]
226− ]
227−
228−compileResultToString ∷ Maybe (Either CompileResult RunResult) -> String
229−compileResultToString = case _ of
230− Nothing -> ""
231− Just (Left cr) -> cr.result <#> _.message # intercalate "/n"
232− Just (Right r) -> r.stdout
blog/src/components/PSLayout.purs+30−19
@@ -1,17 +1,14 @@
11module PSLayout where
22
33import Prelude
4−
5−import Color (toHexString)
64import Data.Array as Array
75import Data.Array.NonEmpty as NEA
86import Data.Maybe (Maybe(..), fromMaybe)
97import Data.Nullable (Nullable)
108import Data.Nullable as Nullable
11−import Data.Semigroup.Foldable (intercalateMap)
129import Data.String as String
1310import Effect (Effect)
14−import FillInTheGaps (mkFillInTheGaps)
11+import Effect.Unsafe (unsafePerformEffect)
1512import JSS (jss, jssClasses)
1613import Justifill (justifill)
1714import Milkis.Impl (FetchImpl)
@@ -19,10 +16,12 @@ import React.Basic (JSX, ReactComponent)
1916import React.Basic.DOM (unsafeCreateDOMComponent)
2017import React.Basic.DOM as R
2118import React.Basic.Helpers (jsx)
22−import React.Basic.Hooks (ReactChildren, component, componentWithChildren, element, reactChildrenToArray)
19+import React.Basic.Hooks (ReactChildren, component, componentWithChildren, element, reactChildrenToArray, useState)
2320import React.Basic.Hooks as React
2421import Yoga.Box.Component as Box
2522import Yoga.CompileEditor.Component (mkCompileEditor)
23+import Yoga.Compiler.Api (apiCompiler)
24+import Yoga.FillInTheGaps.Component as FillInTheGaps
2625import Yoga.Header.Component (mkHeader)
2726import Yoga.InlineCode.Component as InlineCode
2827import Yoga.Theme (fromTheme)
@@ -79,6 +78,15 @@ mkLayout fetchImpl = do
7978 ]
8079 }
8180
81+mkSecret :: Effect ( ReactComponent { kids ∷ Array JSX , visible ∷ Boolean })
82+mkSecret = do
83+ component "Secret" \{ kids, visible } -> React.do
84+ pure
85+ $ R.div
86+ { style: R.css { visibility: if visible then "visible" else "hidden" }
87+ , children: kids
88+ }
89+
8290mkMdxProviderComponent ∷
8391 FetchImpl ->
8492 Effect
@@ -90,31 +98,33 @@ mkMdxProviderComponent ∷
9098mkMdxProviderComponent fetchImpl = do
9199 cssBaseline <- mkCssBaseline
92100 editor <- mkCompileEditor fetchImpl
93− fillInTheGaps <- mkFillInTheGaps fetchImpl
101+ fillInTheGaps <- FillInTheGaps.makeComponent (apiCompiler fetchImpl)
94102 box <- Box.makeComponent
95103 sidebar <- mkSidebar
96104 header <- mkHeader
97105 yogaInlineCode <- InlineCode.makeComponent
98106 h <- mkH
99107 p <- mkP
108+ secret <- mkSecret
100109 useStyles <-
101110 makeStylesJSS
102111 $ jssClasses \(theme ∷ CSSTheme) ->
103112 { code:
104− { fontFamily: theme.codeFontFamily # NEA.head
105− , backgroundColor: theme.interfaceColour
106− , fontSize: "10pt"
107− , border: "1px solid #383c39"
108− , padding: "3px"
109− , borderRadius: "3px"
110− }
113+ { fontFamily: theme.codeFontFamily # NEA.head
114+ , backgroundColor: theme.interfaceColour
115+ , fontSize: "10pt"
116+ , border: "1px solid #383c39"
117+ , padding: "3px"
118+ , borderRadius: "3px"
119+ }
111120 , flexer:
112− { display: "flex"
113− , flexDirection: "row"
114− }
121+ { display: "flex"
122+ , flexDirection: "row"
123+ }
115124 }
116125 componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
117126 classes <- useStyles {}
127+ sections <- useState []
118128 let
119129 baseline child = element cssBaseline { kids: child }
120130
@@ -136,12 +146,14 @@ mkMdxProviderComponent fetchImpl = do
136146 element h { level: H3, text: props.children, className: Nothing }
137147 , h3:
138148 \props ->
139− element h { level: H4, text: props.children , className: Nothing}
149+ element h { level: H4, text: props.children, className: Nothing }
140150 , p:
141151 \props ->
142152 R.div
143153 { children: [ element p { text: props.children } ]
144154 }
155+ , thematicBreak:
156+ \props -> R.div_ [ R.text "HOUI" ]
145157 , inlineCode:
146158 \props -> do
147159 R.span { className: classes.code, children: props.children }
@@ -173,8 +185,7 @@ mkMdxProviderComponent fetchImpl = do
173185
174186 language = fromMaybe "" (classNameQ >>= String.stripPrefix (String.Pattern "language-"))
175187 case isCode, language of
176− true, "puregaps" ->
177− element fillInTheGaps { code: fromMaybe "" codeQ}
188+ true, "puregaps" -> element fillInTheGaps { code: fromMaybe "" codeQ }
178189 true, _ ->
179190 element editor
180191 { initialCode: fromMaybe "" codeQ
blog/src/pages/optional.mdx+6−4
@@ -6,15 +6,17 @@ import SEO from '../components/seo'
66# Optional
77
88```puregaps
9−--result Hello World
9+--result Apero
1010module Main where
11−import Batteries
11+import Grimoire
1212
13−main :: Effect Unit
14−main = log $
13+incantation :: Effect Unit
1514--start here
15+incantation = cast $
1616 "{-Hello-}" <> " " <> "{-World-}"
1717--end here
1818```
1919
20+---
21+
2022## Hans Hölzel
components/src/Yoga/CompileEditor/Component.purs+1−1
@@ -18,7 +18,7 @@ import React.Basic (ReactComponent)
1818import React.Basic.DOM as R
1919import React.Basic.Events (handler_)
2020import React.Basic.Helpers (jsx)
21−import React.Basic.Hooks (component, element, fragment, useState)
21+import React.Basic.Hooks (component, element, useState)
2222import React.Basic.Hooks as React
2323import Shared.Json (readAff)
2424import Shared.Models.Body as Body
components/src/Yoga/Compiler/Api.purs+4−2
@@ -5,16 +5,18 @@ import Data.Either (Either(..))
55import Data.Maybe (Maybe(..))
66import Effect.Aff (Aff, attempt, error, message, throwError)
77import Milkis as M
8+import Milkis.Impl (FetchImpl)
89import Shared.Json (readAff)
910import Shared.Models.Body as Body
1011import Simple.JSON (writeJSON)
1112import Yoga.Compiler.Types (Compiler)
1213
13−apiCompiler ∷ M.Fetch -> { | Compiler () }
14−apiCompiler fetch =
14+apiCompiler ∷ FetchImpl -> { | Compiler () }
15+apiCompiler fetchImpl =
1516 { compileAndRun
1617 }
1718 where
19+ fetch = M.fetch fetchImpl
1820 compileAndRun ∷ Body.CompileRequest -> Aff (Either Body.CompileResult Body.RunResult)
1921 compileAndRun body = do
2022 response <-
components/src/Yoga/FillInTheGaps/Component.purs+1−1
@@ -214,7 +214,7 @@ makeComponent { compileAndRun } = do
214214 else
215215 DisabledButton
216216 }
217− [ R.text "Try it" ]
217+ [ R.text "Incantate" ]
218218 ]
219219 ]
220220 , fragment
components/src/Yoga/FillInTheGaps/Stories.purs+2−2
@@ -31,11 +31,11 @@ codeWithHoles =
3131 """
3232--result Hello World
3333module Main where
34−import Batteries
34+import Grimoire
3535
3636main :: Effect Unit
3737--start here
38−main = log
38+main = cast
3939 "{-Hello World-}"
4040--end here
4141"""
playground/run.js+1−1
@@ -1 +1 @@
1−require ("./output/Main").main()
1+require ("./output/Main").incantation()
playground/src/Batteries.purs → playground/src/Grimoire.pursrenamed+8−3
@@ -1,5 +1,5 @@
1−module Batteries
2− ( module Batteries
1+module Grimoire
2+ ( module Grimoire
33 , module Control.Alt
44 , module Control.Alternative
55 , module Control.Apply
@@ -8,7 +8,6 @@ module Batteries
88 , module Effect.Aff
99 , module Effect
1010 , module Effect.Class
11− , module Effect.Console
1211 , module Control.Monad.Cont.Class
1312 , module Control.Monad.Cont.Trans
1413 , module Control.Monad.Error.Class
@@ -1073,3 +1072,9 @@ import Type.Proxy
10731072import Unsafe.Coerce
10741073 ( unsafeCoerce
10751074 )
1075+
1076+cast :: String -> Effect Unit
1077+cast = log
1078+
1079+summon :: forall a. Show a => a -> Effect Unit
1080+summon = logShow
playground/src/Main.purs+3−3
@@ -1,6 +1,6 @@
11module Main where
22
3−import Batteries
3+import Grimoire
44
5−main :: Effect Unit
6−main = log "Hello, World!"
5+incantation :: Effect Unit
6+incantation = cast "Abracadabra"
playgrounds/.gitkeepdeleted

No changes to the content.

server/src/PscIdeClient.purs−2
@@ -54,8 +54,6 @@ startIdeServer ∷ Folder -> Int -> Aff ChildProcess
5454startIdeServer folder port = do
5555 log $ "Spawning ide server" <> infoString
5656 cp <- spawnProcess folder "npx" [ "purs", "ide", "server", "-p", show port, "--editor-mode", "--no-watch" ]
57− -- liftEffect $ onDataString (CP.stdout cp) UTF8 \str -> do
58− -- log $ "--------" <> infoString <> "\n----------\n" <> str <> "\n----------\n"
5957 log $ "Spawned ide server" <> infoString
6058 -- building once
6159 { error, stderr, stdout } <- execCommand folder "npx spago build"