mirror of
https://github.com/rowtype-yoga/psfp.git
synced 2024-09-11 16:25:36 +03:00
Simplified Fill In The Gaps
This commit is contained in:
parent
21162af38f
commit
d37fadc1ff
1
blog/.psc-ide-port
Normal file
1
blog/.psc-ide-port
Normal file
@ -0,0 +1 @@
|
||||
15613
|
@ -1,14 +1,17 @@
|
||||
module PSLayout where
|
||||
|
||||
import Prelude
|
||||
|
||||
import Data.Array as A
|
||||
import Data.Array as Array
|
||||
import Data.Array.NonEmpty as NEA
|
||||
import Data.Maybe (Maybe(..), fromMaybe)
|
||||
import Data.Nullable (Nullable)
|
||||
import Data.Nullable as Nullable
|
||||
import Data.String as String
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Debug.Trace (spy)
|
||||
import Effect (Effect)
|
||||
import Effect.Unsafe (unsafePerformEffect)
|
||||
import JSS (jss, jssClasses)
|
||||
import Justifill (justifill)
|
||||
import Milkis.Impl (FetchImpl)
|
||||
@ -16,13 +19,15 @@ import React.Basic (JSX, ReactComponent)
|
||||
import React.Basic.DOM (unsafeCreateDOMComponent)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Helpers (jsx)
|
||||
import React.Basic.Hooks (ReactChildren, component, componentWithChildren, element, reactChildrenToArray, useState)
|
||||
import React.Basic.Hooks (ReactChildren, component, componentWithChildren, element, reactChildrenToArray, useEffect, useState)
|
||||
import React.Basic.Hooks as React
|
||||
import Unsafe.Coerce (unsafeCoerce)
|
||||
import Yoga.Box.Component as Box
|
||||
import Yoga.CompileEditor.Component (mkCompileEditor)
|
||||
import Yoga.Compiler.Api (apiCompiler)
|
||||
import Yoga.FillInTheGaps.Component as FillInTheGaps
|
||||
import Yoga.Header.Component (mkHeader)
|
||||
import Yoga.Helpers ((?||))
|
||||
import Yoga.InlineCode.Component as InlineCode
|
||||
import Yoga.Theme (fromTheme)
|
||||
import Yoga.Theme.CSSBaseline (mkCssBaseline)
|
||||
@ -78,9 +83,12 @@ mkLayout fetchImpl = do
|
||||
]
|
||||
}
|
||||
|
||||
mkSecret :: Effect ( ReactComponent { kids ∷ Array JSX , visible ∷ Boolean })
|
||||
mkSecret :: Effect ( ReactComponent { kids ∷ Array JSX , visible ∷ Boolean, register :: Effect Unit })
|
||||
mkSecret = do
|
||||
component "Secret" \{ kids, visible } -> React.do
|
||||
component "Secret" \{ kids, visible, register } -> React.do
|
||||
useEffect visible do
|
||||
unless visible register
|
||||
pure mempty
|
||||
pure
|
||||
$ R.div
|
||||
{ style: R.css { visibility: if visible then "visible" else "hidden" }
|
||||
@ -124,16 +132,20 @@ mkMdxProviderComponent fetchImpl = do
|
||||
}
|
||||
componentWithChildren "MDXProviderComponent" \{ children, siteInfo } -> React.do
|
||||
classes <- useStyles {}
|
||||
sections <- useState []
|
||||
visibleThroughKey /\ updateVisible <- useState ""
|
||||
let
|
||||
baseline child = element cssBaseline { kids: child }
|
||||
kids = reactChildrenToArray children
|
||||
visibleKids = spy "visibleKids" $ fromMaybe kids do
|
||||
i <- kids # A.findIndex (\x -> (unsafeCoerce x).key == visibleThroughKey)
|
||||
pure $ A.take (i+1) kids
|
||||
|
||||
siteInfoJSX =
|
||||
R.div
|
||||
{ children:
|
||||
[ jsx header { className: "" } [ R.text siteInfo.site.siteMetadata.title ]
|
||||
, element sidebar { links: siteInfo.site.siteMetadata.menuLinks }
|
||||
, jsx box {} (reactChildrenToArray children)
|
||||
, jsx box {} visibleKids
|
||||
]
|
||||
}
|
||||
|
||||
@ -152,8 +164,8 @@ mkMdxProviderComponent fetchImpl = do
|
||||
R.div
|
||||
{ children: [ element p { text: props.children } ]
|
||||
}
|
||||
, thematicBreak:
|
||||
\props -> R.div_ [ R.text "HOUI" ]
|
||||
-- , thematicBreak:
|
||||
-- \props -> jsx secret { register: updateSections (Map.insert ) }
|
||||
, inlineCode:
|
||||
\props -> do
|
||||
R.span { className: classes.code, children: props.children }
|
||||
@ -194,6 +206,13 @@ mkMdxProviderComponent fetchImpl = do
|
||||
}
|
||||
false, _ -> element (unsafeCreateDOMComponent "pre") props
|
||||
}
|
||||
|
||||
useEffect (A.length kids) do
|
||||
let
|
||||
firstGaps = kids # A.find (\x -> (unsafeCoerce x).props.mdxType == "pre" && ((unsafeCoerce x).props.children.props.className == "language-puregaps")) <#> (\x -> (unsafeCoerce x).key)
|
||||
lastKey = kids # A.last # unsafeCoerce # _.key
|
||||
updateVisible (const (firstGaps ?|| lastKey))
|
||||
pure mempty
|
||||
pure
|
||||
$ baseline
|
||||
[ element mdxProvider
|
||||
|
@ -6,7 +6,7 @@ import SEO from '../components/seo'
|
||||
# Optional
|
||||
|
||||
```puregaps
|
||||
--result Apero
|
||||
--result Hello World
|
||||
module Main where
|
||||
import Grimoire
|
||||
|
||||
@ -19,4 +19,16 @@ incantation = cast $
|
||||
|
||||
---
|
||||
|
||||
```puregaps
|
||||
--result Hello World
|
||||
module Main where
|
||||
import Grimoire
|
||||
|
||||
incantation :: Effect Unit
|
||||
--start here
|
||||
incantation = cast $
|
||||
"{-Hello World-}"
|
||||
--end here
|
||||
```
|
||||
|
||||
## Hans Hölzel
|
@ -1,83 +1,24 @@
|
||||
module Yoga.FillInTheGaps.Component where
|
||||
|
||||
import Prelude
|
||||
import Data.Array (foldMap, foldr, intercalate)
|
||||
import Data.Array as A
|
||||
import Data.Either (Either(..))
|
||||
import Data.Foldable (foldl)
|
||||
import Data.Function.Uncurried (mkFn2)
|
||||
import Data.Lens ((%~))
|
||||
import Data.Lens.Index (ix)
|
||||
import Data.Maybe (Maybe(..), fromMaybe', isJust, isNothing)
|
||||
import Data.Monoid (guard)
|
||||
import Data.String (Pattern(..), split)
|
||||
import Data.String as S
|
||||
import Data.String.Regex (Regex)
|
||||
import Data.String.Regex as Regex
|
||||
import Data.String.Regex.Flags as RegexFlags
|
||||
import Data.String.Regex.Unsafe (unsafeRegex)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Debug.Trace (spy)
|
||||
import Effect (Effect)
|
||||
import Effect.Aff (launchAff_)
|
||||
import Effect.Aff (Milliseconds(..), delay)
|
||||
import Effect.Class (liftEffect)
|
||||
import Justifill (justifill)
|
||||
import Partial.Unsafe (unsafeCrashWith)
|
||||
import React.Basic (JSX, ReactComponent, element, fragment)
|
||||
import React.Basic.DOM (css)
|
||||
import React.Basic (JSX, ReactComponent, element)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Events (handler_)
|
||||
import React.Basic.Helpers (jsx)
|
||||
import React.Basic.Hooks (component, useState)
|
||||
import React.Basic.Hooks as React
|
||||
import React.Basic.Hooks.Spring (useTransition)
|
||||
import React.Basic.Hooks.Aff (useAff)
|
||||
import React.Basic.SyntaxHighlighter.Component (HighlighterTheme, syntaxHighlighterImpl)
|
||||
import Shared.Models.Body (CompileResult, RunResult)
|
||||
import Yoga.Button.Component (ButtonType(..), mkButton)
|
||||
import Yoga.ClickAway.Component as ClickAway
|
||||
import Yoga.CloseIcon.Component as CloseIcon
|
||||
import Yoga.Cluster.Component as Cluster
|
||||
import Yoga.Compiler.Types (Compiler)
|
||||
import Yoga.FillInTheGaps.Logic (Segment(..), updateSegments)
|
||||
import Yoga.Helpers ((?||))
|
||||
import Yoga.InlineCode.Component as InlineCode
|
||||
import Yoga.Modal.Component as Modal
|
||||
import Yoga.Theme.Styles (useTheme)
|
||||
import Yoga.Theme.Syntax (mkHighlighterTheme)
|
||||
|
||||
data Segment
|
||||
= ExpectedResult String
|
||||
| Start
|
||||
| End
|
||||
| Filler String
|
||||
| Hole Int String
|
||||
|
||||
derive instance eqSegment ∷ Eq Segment
|
||||
getResult ∷ Segment -> Maybe String
|
||||
getResult = case _ of
|
||||
ExpectedResult r -> Just r
|
||||
_ -> Nothing
|
||||
|
||||
findResult ∷ Array Segment -> String
|
||||
findResult = fromMaybe' (\_ -> unsafeCrashWith "Even teachers make mistakes") <<< A.findMap getResult
|
||||
|
||||
toCode ∷ Array (Array Segment) -> String
|
||||
toCode lines = intercalate "\n" mapped
|
||||
where
|
||||
mapped = lines <#> (intercalate "" <<< map segmentToCode)
|
||||
segmentToCode = case _ of
|
||||
Filler s -> s
|
||||
Hole _ s -> s
|
||||
_ -> ""
|
||||
|
||||
complete ∷ Array (Array Segment) -> Boolean
|
||||
complete arr = foldl f true (join arr)
|
||||
where
|
||||
f acc seg =
|
||||
acc
|
||||
&& case seg of
|
||||
Hole _ s -> s /= ""
|
||||
_ -> true
|
||||
|
||||
visibleRange ∷ Array (Array Segment) -> { end ∷ Int, start ∷ Int }
|
||||
visibleRange arr = { start, end }
|
||||
where
|
||||
@ -91,7 +32,7 @@ renderSegments highlighterTheme ic update arrs = R.div_ (A.mapWithIndex renderLi
|
||||
renderLine i l = R.div_ (A.mapWithIndex (renderSegment i) l)
|
||||
renderSegment i j s =
|
||||
if between start end i then case s of
|
||||
Filler s' -> element syntaxHighlighterImpl { style: highlighterTheme, language: "purescript", children: spy "ch" s' }
|
||||
Filler s' -> element syntaxHighlighterImpl { style: highlighterTheme, language: "purescript", children: s' }
|
||||
Hole width _ ->
|
||||
element ic
|
||||
$ justifill
|
||||
@ -102,150 +43,13 @@ renderSegments highlighterTheme ic update arrs = R.div_ (A.mapWithIndex renderLi
|
||||
else
|
||||
mempty
|
||||
|
||||
updateSegments ∷ Int -> Int -> String -> Array (Array Segment) -> Array (Array Segment)
|
||||
updateSegments i j v = (ix i <<< ix j) %~ f
|
||||
where
|
||||
f = case _ of
|
||||
Hole h _ -> Hole h v
|
||||
_ -> unsafeCrashWith "Updated a non-hole"
|
||||
|
||||
holeRegex ∷ Regex
|
||||
holeRegex = unsafeRegex "({-.*?-})" RegexFlags.global
|
||||
|
||||
resultRegex ∷ Regex
|
||||
resultRegex = unsafeRegex "--result" RegexFlags.global
|
||||
|
||||
startRegex ∷ Regex
|
||||
startRegex = unsafeRegex "--start here" RegexFlags.global
|
||||
|
||||
endRegex ∷ Regex
|
||||
endRegex = unsafeRegex "--end here" RegexFlags.global
|
||||
|
||||
rawSegments ∷ String -> Array String
|
||||
rawSegments = Regex.split holeRegex
|
||||
|
||||
toSegment ∷ String -> Segment
|
||||
toSegment = case _ of
|
||||
x
|
||||
| Regex.test holeRegex x -> Hole (S.length x - 4) ""
|
||||
x
|
||||
| S.indexOf (Pattern "--result ") x == Just 0 -> ExpectedResult ((S.stripPrefix (Pattern "--result ") x) ?|| "")
|
||||
x
|
||||
| Regex.test startRegex x -> Start
|
||||
x
|
||||
| Regex.test endRegex x -> End
|
||||
other -> Filler other
|
||||
|
||||
-- Glues together Filler segments
|
||||
-- [[Filler "line1"], [Filler "line2"]] --> [[Filler "line1\nline2"]]
|
||||
-- [[Filler "line1", Filler "line2"]] --> [[Filler "line1\nline2"]]
|
||||
-- [[Filler "line1", Filler "line2"], [Filler "line3"]] --> [[Filler "line1\nline2\line3"]]
|
||||
smooshFillers ∷ Array (Array Segment) -> Array (Array Segment)
|
||||
smooshFillers = foldl smooshOuter []
|
||||
where
|
||||
smooshInner segments segment = case segment, A.unsnoc segments of
|
||||
Filler f, Just { init, last: Filler prev } -> A.snoc init (Filler (prev <> "\n" <> f))
|
||||
_, _ -> A.snoc segments segment
|
||||
smooshOuter acc segs = case foldl smooshInner [] segs, A.unsnoc acc of
|
||||
[ Filler f ], Just { init, last: [ Filler prev ] } -> A.snoc init [ Filler (prev <> "\n" <> f) ]
|
||||
_, _ -> A.snoc acc segs
|
||||
|
||||
type Ctx r
|
||||
= (Compiler r)
|
||||
|
||||
makeComponent ∷ { | Ctx () } -> Effect (ReactComponent { code ∷ String })
|
||||
makeComponent { compileAndRun } = do
|
||||
makeComponent ∷ Effect (ReactComponent { initialSegments ∷ Array (Array Segment), update ∷ Array (Array Segment) -> Effect Unit })
|
||||
makeComponent = do
|
||||
ic <- InlineCode.makeComponent
|
||||
modal <- Modal.makeComponent
|
||||
closeIcon <- CloseIcon.makeComponent
|
||||
cluster <- Cluster.makeComponent
|
||||
clickAway <- ClickAway.makeComponent
|
||||
button <- mkButton
|
||||
component "FillInTheGaps" \{ code } -> React.do
|
||||
let
|
||||
lines = split (Pattern "\n") code
|
||||
|
||||
initialSegments = smooshFillers (lines <#> \line -> rawSegments line <#> toSegment)
|
||||
component "FillInTheGaps" \{ initialSegments, update } -> React.do
|
||||
segments /\ modifySegments <- useState initialSegments
|
||||
result /\ modifyResult <- useState Nothing
|
||||
cssTheme <- useTheme
|
||||
let
|
||||
highlighterTheme = mkHighlighterTheme cssTheme
|
||||
modalTransitions <-
|
||||
useTransition [ result ] (Just show)
|
||||
$ css
|
||||
{ from: { opacity: 0.0, transform: "translate3d(-50%, -50%, 0) scale3d(0.3, 0.3, 1.0)" }
|
||||
, enter: { opacity: 1.0, transform: "translate3d(-50%, -50%, 0) scale3d(1.0, 1.0, 1.0)" }
|
||||
, leave: { opacity: 0.0, transform: "translate3d(-50%, -50%, 0) scale3d(0.3, 0.3, 1.0)" }
|
||||
, config:
|
||||
mkFn2 \_ state -> case state of
|
||||
"leave" -> { mass: 1.0, tension: 140, friction: 15 }
|
||||
_ -> { mass: 1.0, tension: 170, friction: 20 }
|
||||
}
|
||||
clickAwayTransitions <-
|
||||
useTransition [ result ] (Just show)
|
||||
$ css
|
||||
{ from: { opacity: 0.0 }
|
||||
, enter: { opacity: 1.0 }
|
||||
, leave: { opacity: 0.0 }
|
||||
, config:
|
||||
mkFn2 \_ state -> case state of
|
||||
"leave" -> { mass: 1.0, tension: 140, friction: 15 }
|
||||
_ -> { mass: 1.0, tension: 170, friction: 20 }
|
||||
}
|
||||
let
|
||||
expectedResult = findResult (join segments)
|
||||
|
||||
onClick =
|
||||
launchAff_ do
|
||||
do
|
||||
res <- compileAndRun { code: toCode segments }
|
||||
modifyResult (const (Just $ res)) # liftEffect
|
||||
pure
|
||||
$ fragment
|
||||
$ [ renderSegments highlighterTheme ic (modifySegments) segments
|
||||
, jsx cluster {}
|
||||
[ R.div_
|
||||
[ jsx button
|
||||
{ onClick: handler_ onClick
|
||||
, buttonType:
|
||||
if complete segments && isNothing result then
|
||||
HighlightedButton
|
||||
else
|
||||
DisabledButton
|
||||
}
|
||||
[ R.text "Incantate" ]
|
||||
]
|
||||
]
|
||||
, fragment
|
||||
$ clickAwayTransitions
|
||||
>>= \{ item, key, props } ->
|
||||
guard (isJust item)
|
||||
$ join item
|
||||
# foldMap \_ ->
|
||||
[ element clickAway (justifill { allowEscape: true, style: props, onClick: modifyResult (const Nothing) }) ]
|
||||
, fragment
|
||||
$ modalTransitions
|
||||
>>= \{ item, key, props } ->
|
||||
guard (isJust item)
|
||||
$ join item
|
||||
# foldMap \r ->
|
||||
[ jsx modal
|
||||
{ title:
|
||||
case r of
|
||||
(Right { stdout })
|
||||
| S.stripSuffix (S.Pattern "\n") stdout == Just expectedResult -> "Hooray!"
|
||||
(Left l) -> "Does not compile"
|
||||
(Right _) -> "Not " <> (findResult $ join segments)
|
||||
, icon: element closeIcon { onClick: modifyResult (const Nothing), style: Nothing }
|
||||
, style: props
|
||||
}
|
||||
[ R.pre_ [ R.text $ compileResultToString result ] ]
|
||||
]
|
||||
]
|
||||
|
||||
compileResultToString ∷ Maybe (Either CompileResult RunResult) -> String
|
||||
compileResultToString = case _ of
|
||||
Nothing -> ""
|
||||
Just (Left cr) -> cr.result <#> _.message # intercalate "\n"
|
||||
Just (Right r) -> r.stdout
|
||||
useAff segments do
|
||||
delay (200.0 # Milliseconds)
|
||||
update segments # liftEffect
|
||||
highlighterTheme <- useTheme <#> mkHighlighterTheme
|
||||
pure $ renderSegments highlighterTheme ic (modifySegments) segments
|
||||
|
118
components/src/Yoga/FillInTheGaps/Logic.purs
Normal file
118
components/src/Yoga/FillInTheGaps/Logic.purs
Normal file
@ -0,0 +1,118 @@
|
||||
module Yoga.FillInTheGaps.Logic where
|
||||
|
||||
import Prelude
|
||||
import Data.Array (intercalate)
|
||||
import Data.Array as A
|
||||
import Data.Either (Either(..))
|
||||
import Data.Foldable (foldl)
|
||||
import Data.Lens ((%~))
|
||||
import Data.Lens.Index (ix)
|
||||
import Data.Maybe (Maybe(..), fromMaybe')
|
||||
import Data.String (Pattern(..), split)
|
||||
import Data.String as S
|
||||
import Data.String.Regex (Regex)
|
||||
import Data.String.Regex as Regex
|
||||
import Data.String.Regex.Flags as RegexFlags
|
||||
import Data.String.Regex.Unsafe (unsafeRegex)
|
||||
import Data.Tuple.Nested ((/\))
|
||||
import Debug.Trace (spy)
|
||||
import Effect (Effect)
|
||||
import Justifill (justifill)
|
||||
import Partial.Unsafe (unsafeCrashWith)
|
||||
import React.Basic (JSX, ReactComponent, element)
|
||||
import React.Basic.DOM as R
|
||||
import React.Basic.Hooks (component, useState)
|
||||
import React.Basic.Hooks as React
|
||||
import React.Basic.SyntaxHighlighter.Component (HighlighterTheme, syntaxHighlighterImpl)
|
||||
import Shared.Models.Body (CompileResult, RunResult)
|
||||
import Yoga.Helpers ((?||))
|
||||
import Yoga.InlineCode.Component as InlineCode
|
||||
import Yoga.Theme.Styles (useTheme)
|
||||
import Yoga.Theme.Syntax (mkHighlighterTheme)
|
||||
|
||||
complete ∷ Array (Array Segment) -> Boolean
|
||||
complete arr = foldl f true (join arr)
|
||||
where
|
||||
f acc seg =
|
||||
acc
|
||||
&& case seg of
|
||||
Hole _ s -> s /= ""
|
||||
_ -> true
|
||||
|
||||
data Segment
|
||||
= ExpectedResult String
|
||||
| Start
|
||||
| End
|
||||
| Filler String
|
||||
| Hole Int String
|
||||
|
||||
derive instance eqSegment ∷ Eq Segment
|
||||
getResult ∷ Segment -> Maybe String
|
||||
getResult = case _ of
|
||||
ExpectedResult r -> Just r
|
||||
_ -> Nothing
|
||||
|
||||
findResult ∷ Array Segment -> String
|
||||
findResult = fromMaybe' (\_ -> unsafeCrashWith "Even teachers make mistakes") <<< A.findMap getResult
|
||||
|
||||
toCode ∷ Array (Array Segment) -> String
|
||||
toCode lines = intercalate "\n" mapped
|
||||
where
|
||||
mapped = lines <#> (intercalate "" <<< map segmentToCode)
|
||||
segmentToCode = case _ of
|
||||
Filler s -> s
|
||||
Hole _ s -> s
|
||||
_ -> ""
|
||||
|
||||
holeRegex ∷ Regex
|
||||
holeRegex = unsafeRegex "({-.*?-})" RegexFlags.global
|
||||
|
||||
resultRegex ∷ Regex
|
||||
resultRegex = unsafeRegex "--result" RegexFlags.global
|
||||
|
||||
startRegex ∷ Regex
|
||||
startRegex = unsafeRegex "--start here" RegexFlags.global
|
||||
|
||||
endRegex ∷ Regex
|
||||
endRegex = unsafeRegex "--end here" RegexFlags.global
|
||||
|
||||
rawSegments ∷ String -> Array String
|
||||
rawSegments = Regex.split holeRegex
|
||||
|
||||
toSegment ∷ String -> Segment
|
||||
toSegment = case _ of
|
||||
x
|
||||
| Regex.test holeRegex x -> Hole (S.length x - 4) ""
|
||||
x
|
||||
| S.indexOf (Pattern "--result ") x == Just 0 -> ExpectedResult ((S.stripPrefix (Pattern "--result ") x) ?|| "")
|
||||
x
|
||||
| Regex.test startRegex x -> Start
|
||||
x
|
||||
| Regex.test endRegex x -> End
|
||||
other -> Filler other
|
||||
|
||||
updateSegments ∷ Int -> Int -> String -> Array (Array Segment) -> Array (Array Segment)
|
||||
updateSegments i j v = (ix i <<< ix j) %~ f
|
||||
where
|
||||
f = case _ of
|
||||
Hole h _ -> Hole h v
|
||||
_ -> unsafeCrashWith "Updated a non-hole"
|
||||
|
||||
-- Glues together Filler segments
|
||||
-- [[Filler "line1"], [Filler "line2"]] --> [[Filler "line1\nline2"]]
|
||||
-- [[Filler "line1", Filler "line2"]] --> [[Filler "line1\nline2"]]
|
||||
-- [[Filler "line1", Filler "line2"], [Filler "line3"]] --> [[Filler "line1\nline2\line3"]]
|
||||
smooshFillers ∷ Array (Array Segment) -> Array (Array Segment)
|
||||
smooshFillers = foldl smooshOuter []
|
||||
where
|
||||
smooshInner segments segment = case segment, A.unsnoc segments of
|
||||
Filler f, Just { init, last: Filler prev } -> A.snoc init (Filler (prev <> "\n" <> f))
|
||||
_, _ -> A.snoc segments segment
|
||||
smooshOuter acc segs = case foldl smooshInner [] segs, A.unsnoc acc of
|
||||
[ Filler f ], Just { init, last: [ Filler prev ] } -> A.snoc init [ Filler (prev <> "\n" <> f) ]
|
||||
_, _ -> A.snoc acc segs
|
||||
|
||||
parseSegments code = segments
|
||||
where
|
||||
lines = split (Pattern "\n") code
|
||||
segments = smooshFillers (lines <#> \line -> rawSegments line <#> toSegment)
|
@ -1,30 +1,19 @@
|
||||
module Yoga.FillInTheGaps.Stories where
|
||||
|
||||
import Prelude hiding (add)
|
||||
import Data.Either (Either(..))
|
||||
import Data.Maybe (Maybe(..))
|
||||
import Data.String as String
|
||||
import Effect (Effect)
|
||||
import Storybook.Decorator.FullScreen (fullScreenDecorator)
|
||||
import Storybook.React (Storybook, add, addDecorator, storiesOf)
|
||||
import Yoga.FillInTheGaps.Component as FillInTheGaps
|
||||
|
||||
ctx ∷ { | FillInTheGaps.Ctx () }
|
||||
ctx =
|
||||
{ compileAndRun
|
||||
}
|
||||
where
|
||||
compileAndRun = case _ of
|
||||
{ code }
|
||||
| code == correctCode -> pure (Right { code: Nothing, stdout: "Hello World\n", stderr: "" })
|
||||
other -> pure (Right { code: Nothing, stdout: "Not hello world", stderr: "" })
|
||||
import Yoga.FillInTheGaps.Logic (parseSegments)
|
||||
|
||||
stories ∷ Effect Storybook
|
||||
stories = do
|
||||
storiesOf "FillInTheGaps" do
|
||||
addDecorator fullScreenDecorator
|
||||
add "The FillInTheGaps" (FillInTheGaps.makeComponent ctx)
|
||||
[ { code: codeWithHoles }
|
||||
add "The FillInTheGaps" (FillInTheGaps.makeComponent)
|
||||
[ { initialSegments: parseSegments codeWithHoles, update: pure (pure unit) }
|
||||
]
|
||||
|
||||
codeWithHoles =
|
||||
@ -33,9 +22,9 @@ codeWithHoles =
|
||||
module Main where
|
||||
import Grimoire
|
||||
|
||||
main :: Effect Unit
|
||||
incantation :: Effect Unit
|
||||
--start here
|
||||
main = cast
|
||||
incantation = cast
|
||||
"{-Hello World-}"
|
||||
--end here
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user