git.iko.soy/rowtype-yoga/psfp
on master help sign in
Ch-ch-changes
21162afMark Eibes
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 @@
1module PSLayout where
1module PSLayout where
2
2
3import Prelude
3import Prelude
4−
5−import Color (toHexString)
6import Data.Array as Array
4import Data.Array as Array
7import Data.Array.NonEmpty as NEA
5import Data.Array.NonEmpty as NEA
8import Data.Maybe (Maybe(..), fromMaybe)
6import Data.Maybe (Maybe(..), fromMaybe)
9import Data.Nullable (Nullable)
7import Data.Nullable (Nullable)
10import Data.Nullable as Nullable
8import Data.Nullable as Nullable
11−import Data.Semigroup.Foldable (intercalateMap)
12import Data.String as String
9import Data.String as String
13import Effect (Effect)
10import Effect (Effect)
14−import FillInTheGaps (mkFillInTheGaps)
11+import Effect.Unsafe (unsafePerformEffect)
15import JSS (jss, jssClasses)
12import JSS (jss, jssClasses)
16import Justifill (justifill)
13import Justifill (justifill)
17import Milkis.Impl (FetchImpl)
14import Milkis.Impl (FetchImpl)
@@ -19,10 +16,12 @@ import React.Basic (JSX, ReactComponent)
19import React.Basic.DOM (unsafeCreateDOMComponent)
16import React.Basic.DOM (unsafeCreateDOMComponent)
20import React.Basic.DOM as R
17import React.Basic.DOM as R
21import React.Basic.Helpers (jsx)
18import 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)
23import React.Basic.Hooks as React
20import React.Basic.Hooks as React
24import Yoga.Box.Component as Box
21import Yoga.Box.Component as Box
25import Yoga.CompileEditor.Component (mkCompileEditor)
22import Yoga.CompileEditor.Component (mkCompileEditor)
23+import Yoga.Compiler.Api (apiCompiler)
24+import Yoga.FillInTheGaps.Component as FillInTheGaps
26import Yoga.Header.Component (mkHeader)
25import Yoga.Header.Component (mkHeader)
27import Yoga.InlineCode.Component as InlineCode
26import Yoga.InlineCode.Component as InlineCode
28import Yoga.Theme (fromTheme)
27import Yoga.Theme (fromTheme)
@@ -79,6 +78,15 @@ mkLayout fetchImpl = do
79 ]
78 ]
80 }
79 }
81
80
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+
82mkMdxProviderComponent ∷
90mkMdxProviderComponent ∷
83 FetchImpl ->
91 FetchImpl ->
84 Effect
92 Effect
@@ -90,31 +98,33 @@ mkMdxProviderComponent ∷
90mkMdxProviderComponent fetchImpl = do
98mkMdxProviderComponent fetchImpl = do
91 cssBaseline <- mkCssBaseline
99 cssBaseline <- mkCssBaseline
92 editor <- mkCompileEditor fetchImpl
100 editor <- mkCompileEditor fetchImpl
93− fillInTheGaps <- mkFillInTheGaps fetchImpl
101+ fillInTheGaps <- FillInTheGaps.makeComponent (apiCompiler fetchImpl)
94 box <- Box.makeComponent
102 box <- Box.makeComponent
95 sidebar <- mkSidebar
103 sidebar <- mkSidebar
96 header <- mkHeader
104 header <- mkHeader
97 yogaInlineCode <- InlineCode.makeComponent
105 yogaInlineCode <- InlineCode.makeComponent
98 h <- mkH
106 h <- mkH
99 p <- mkP
107 p <- mkP
108+ secret <- mkSecret
100 useStyles <-
109 useStyles <-
101 makeStylesJSS
110 makeStylesJSS
102 $ jssClasses \(theme ∷ CSSTheme) ->
111 $ jssClasses \(theme ∷ CSSTheme) ->
103 { code:
112 { code:
104− { fontFamily: theme.codeFontFamily # NEA.head
113+ { fontFamily: theme.codeFontFamily # NEA.head
105− , backgroundColor: theme.interfaceColour
114+ , backgroundColor: theme.interfaceColour
106− , fontSize: "10pt"
115+ , fontSize: "10pt"
107− , border: "1px solid #383c39"
116+ , border: "1px solid #383c39"
108− , padding: "3px"
117+ , padding: "3px"
109− , borderRadius: "3px"
118+ , borderRadius: "3px"
110− }
119+ }
111 , flexer:
120 , flexer:
112− { display: "flex"
121+ { display: "flex"
113− , flexDirection: "row"
122+ , flexDirection: "row"
114− }
123+ }
115 }
124 }
116 componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
125 componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
117 classes <- useStyles {}
126 classes <- useStyles {}
127+ sections <- useState []
118 let
128 let
119 baseline child = element cssBaseline { kids: child }
129 baseline child = element cssBaseline { kids: child }
120
130
@@ -136,12 +146,14 @@ mkMdxProviderComponent fetchImpl = do
136 element h { level: H3, text: props.children, className: Nothing }
146 element h { level: H3, text: props.children, className: Nothing }
137 , h3:
147 , h3:
138 \props ->
148 \props ->
139− element h { level: H4, text: props.children , className: Nothing}
149+ element h { level: H4, text: props.children, className: Nothing }
140 , p:
150 , p:
141 \props ->
151 \props ->
142 R.div
152 R.div
143 { children: [ element p { text: props.children } ]
153 { children: [ element p { text: props.children } ]
144 }
154 }
155+ , thematicBreak:
156+ \props -> R.div_ [ R.text "HOUI" ]
145 , inlineCode:
157 , inlineCode:
146 \props -> do
158 \props -> do
147 R.span { className: classes.code, children: props.children }
159 R.span { className: classes.code, children: props.children }
@@ -173,8 +185,7 @@ mkMdxProviderComponent fetchImpl = do
173
185
174 language = fromMaybe "" (classNameQ >>= String.stripPrefix (String.Pattern "language-"))
186 language = fromMaybe "" (classNameQ >>= String.stripPrefix (String.Pattern "language-"))
175 case isCode, language of
187 case isCode, language of
176− true, "puregaps" ->
177− element fillInTheGaps { code: fromMaybe "" codeQ}
188+ true, "puregaps" -> element fillInTheGaps { code: fromMaybe "" codeQ }
178 true, _ ->
189 true, _ ->
179 element editor
190 element editor
180 { initialCode: fromMaybe "" codeQ
191 { initialCode: fromMaybe "" codeQ
blog/src/pages/optional.mdx+6−4
@@ -6,15 +6,17 @@ import SEO from '../components/seo'
6# Optional
6# Optional
7
7
8```puregaps
8```puregaps
9−--result Hello World
9+--result Apero
10module Main where
10module Main where
11−import Batteries
11+import Grimoire
12
12
13−main :: Effect Unit
13+incantation :: Effect Unit
14−main = log $
15--start here
14--start here
15+incantation = cast $
16 "{-Hello-}" <> " " <> "{-World-}"
16 "{-Hello-}" <> " " <> "{-World-}"
17--end here
17--end here
18```
18```
19
19
20+---
21+
20## Hans Hölzel
22## Hans Hölzel
components/src/Yoga/CompileEditor/Component.purs+1−1
@@ -18,7 +18,7 @@ import React.Basic (ReactComponent)
18import React.Basic.DOM as R
18import React.Basic.DOM as R
19import React.Basic.Events (handler_)
19import React.Basic.Events (handler_)
20import React.Basic.Helpers (jsx)
20import React.Basic.Helpers (jsx)
21−import React.Basic.Hooks (component, element, fragment, useState)
21+import React.Basic.Hooks (component, element, useState)
22import React.Basic.Hooks as React
22import React.Basic.Hooks as React
23import Shared.Json (readAff)
23import Shared.Json (readAff)
24import Shared.Models.Body as Body
24import Shared.Models.Body as Body
components/src/Yoga/Compiler/Api.purs+4−2
@@ -5,16 +5,18 @@ import Data.Either (Either(..))
5import Data.Maybe (Maybe(..))
5import Data.Maybe (Maybe(..))
6import Effect.Aff (Aff, attempt, error, message, throwError)
6import Effect.Aff (Aff, attempt, error, message, throwError)
7import Milkis as M
7import Milkis as M
8+import Milkis.Impl (FetchImpl)
8import Shared.Json (readAff)
9import Shared.Json (readAff)
9import Shared.Models.Body as Body
10import Shared.Models.Body as Body
10import Simple.JSON (writeJSON)
11import Simple.JSON (writeJSON)
11import Yoga.Compiler.Types (Compiler)
12import Yoga.Compiler.Types (Compiler)
12
13
13−apiCompiler ∷ M.Fetch -> { | Compiler () }
14+apiCompiler ∷ FetchImpl -> { | Compiler () }
14−apiCompiler fetch =
15+apiCompiler fetchImpl =
15 { compileAndRun
16 { compileAndRun
16 }
17 }
17 where
18 where
19+ fetch = M.fetch fetchImpl
18 compileAndRun ∷ Body.CompileRequest -> Aff (Either Body.CompileResult Body.RunResult)
20 compileAndRun ∷ Body.CompileRequest -> Aff (Either Body.CompileResult Body.RunResult)
19 compileAndRun body = do
21 compileAndRun body = do
20 response <-
22 response <-
components/src/Yoga/FillInTheGaps/Component.purs+1−1
@@ -214,7 +214,7 @@ makeComponent { compileAndRun } = do
214 else
214 else
215 DisabledButton
215 DisabledButton
216 }
216 }
217− [ R.text "Try it" ]
217+ [ R.text "Incantate" ]
218 ]
218 ]
219 ]
219 ]
220 , fragment
220 , fragment
components/src/Yoga/FillInTheGaps/Stories.purs+2−2
@@ -31,11 +31,11 @@ codeWithHoles =
31 """
31 """
32--result Hello World
32--result Hello World
33module Main where
33module Main where
34−import Batteries
34+import Grimoire
35
35
36main :: Effect Unit
36main :: Effect Unit
37--start here
37--start here
38−main = log
38+main = cast
39 "{-Hello World-}"
39 "{-Hello World-}"
40--end here
40--end here
41"""
41"""
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
1+module Grimoire
2− ( module Batteries
2+ ( module Grimoire
3 , module Control.Alt
3 , module Control.Alt
4 , module Control.Alternative
4 , module Control.Alternative
5 , module Control.Apply
5 , module Control.Apply
@@ -8,7 +8,6 @@ module Batteries
8 , module Effect.Aff
8 , module Effect.Aff
9 , module Effect
9 , module Effect
10 , module Effect.Class
10 , module Effect.Class
11− , module Effect.Console
12 , module Control.Monad.Cont.Class
11 , module Control.Monad.Cont.Class
13 , module Control.Monad.Cont.Trans
12 , module Control.Monad.Cont.Trans
14 , module Control.Monad.Error.Class
13 , module Control.Monad.Error.Class
@@ -1073,3 +1072,9 @@ import Type.Proxy
1073import Unsafe.Coerce
1072import Unsafe.Coerce
1074 ( unsafeCoerce
1073 ( unsafeCoerce
1075 )
1074 )
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 @@
1module Main where
1module Main where
2
2
3−import Batteries
3+import Grimoire
4
4
5−main :: Effect Unit
5+incantation :: Effect Unit
6−main = log "Hello, World!"
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
54startIdeServer folder port = do
54startIdeServer folder port = do
55 log $ "Spawning ide server" <> infoString
55 log $ "Spawning ide server" <> infoString
56 cp <- spawnProcess folder "npx" [ "purs", "ide", "server", "-p", show port, "--editor-mode", "--no-watch" ]
56 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"
59 log $ "Spawned ide server" <> infoString
57 log $ "Spawned ide server" <> infoString
60 -- building once
58 -- building once
61 { error, stderr, stdout } <- execCommand folder "npx spago build"
59 { error, stderr, stdout } <- execCommand folder "npx spago build"