1module FillInTheGaps where
5import Data.Array (foldMap, intercalate)
7import Data.Either (Either(..))
8import Data.Foldable (foldl)
9import Data.Function.Uncurried (mkFn2)
10import Data.Lens ((%~))
11import Data.Lens.Index (ix)
12import Data.Maybe (Maybe(..), fromMaybe', isJust)
13import Data.Monoid (guard)
14import Data.String (Pattern(..), split)
15import Data.String as S
16import Data.String.Regex (Regex)
17import Data.String.Regex as Regex
18import Data.String.Regex.Flags as RegexFlags
19import Data.String.Regex.Unsafe (unsafeRegex)
20import Data.Tuple.Nested ((/\))
21import Debug.Trace (spy)
23import Effect.Aff (launchAff_)
24import Effect.Class (liftEffect)
25import Justifill (justifill)
27import Milkis.Impl (FetchImpl)
28import Partial.Unsafe (unsafeCrashWith)
29import React.Basic (JSX, ReactComponent, element, fragment)
30import React.Basic.DOM (css)
31import React.Basic.DOM as R
32import React.Basic.Events (handler_)
33import React.Basic.Helpers (jsx)
34import React.Basic.Hooks (component, useState)
35import React.Basic.Hooks as React
36import React.Basic.Hooks.Spring (animatedDiv, useTransition)
37import Shared.Models.Body (CompileResult, RunResult)
38import Yoga.Button.Component (ButtonType(..), mkButton)
39import Yoga.ClickAway.Component as ClickAway
40import Yoga.CloseIcon.Component as CloseIcon
41import Yoga.Cluster.Component as Cluster
42import Yoga.CompileEditor.Component (compileAndRun)
43import Yoga.Helpers ((?||))
44import Yoga.InlineCode.Component as InlineCode
45import Yoga.Modal.Component as Modal
48 = ExpectedResult String
54derive instance eqSegment ∷ Eq Segment
55getResult ∷ Segment -> Maybe String
57 ExpectedResult r -> Just r
60findResult ∷ Array Segment -> String
61findResult = fromMaybe' (\_ -> unsafeCrashWith "Even teachers make mistakes") <<< A.findMap getResult
63toCode ∷ (Array (Array Segment)) -> String
64toCode lines = intercalate "\n" mapped
66 mapped = lines <#> (intercalate "" <<< map segmentToCode)
67 segmentToCode = case _ of
72complete ∷ (Array (Array Segment)) -> Boolean
73complete arr = foldl f true (join arr)
81visibleRange ∷ Array (Array Segment) -> { end ∷ Int, start ∷ Int }
82visibleRange arr = { start, end }
84 start = A.findIndex (_ == [ Start ]) arr ?|| 0
85 end = A.findIndex (_ == [ End ]) arr ?|| A.length arr
87renderSegments ∷ ReactComponent InlineCode.Props -> ((Array (Array Segment) -> Array (Array Segment)) -> Effect Unit) -> Array (Array Segment) -> JSX
88renderSegments ic update arrs = R.div_ (A.mapWithIndex renderLine arrs)
90 { start, end } = visibleRange arrs
91 renderLine i l = R.div_ (A.mapWithIndex (renderSegment i) l)
93 if between start end i then case s of
94 Filler s' -> R.code_ [ R.text s' ]
99 , onSubmit: update <<< updateSegments i j
105updateSegments ∷ Int -> Int -> String -> Array (Array Segment) -> Array (Array Segment)
106updateSegments i j v = (ix i <<< ix j) %~ f
110 _ -> unsafeCrashWith "Updated a non-hole"
113holeRegex = unsafeRegex "({-.*?-})" RegexFlags.global
116resultRegex = unsafeRegex "--result" RegexFlags.global
119startRegex = unsafeRegex "--start here" RegexFlags.global
122endRegex = unsafeRegex "--end here" RegexFlags.global
124rawSegments ∷ String -> Array String
125rawSegments = Regex.split holeRegex
127toSegment ∷ String -> Segment
130 | Regex.test holeRegex x -> Hole (S.length x - 4) ""
132 | S.indexOf (Pattern "--result ") x == Just 0 -> ExpectedResult ((S.stripPrefix (Pattern "--result ") x) ?|| "")
134 | Regex.test startRegex x -> Start
136 | Regex.test endRegex x -> End
137 other -> Filler other
139mkFillInTheGaps ∷ FetchImpl -> Effect (ReactComponent { code ∷ String })
140mkFillInTheGaps fetch = do
141 ic <- InlineCode.makeComponent
142 modal <- Modal.makeComponent
143 closeIcon <- CloseIcon.makeComponent
144 cluster <- Cluster.makeComponent
145 clickAway <- ClickAway.makeComponent
147 component "FillInTheGaps" \{ code } -> React.do
149 lines = split (Pattern "\n") code
151 initialSegments = lines <#> \line -> rawSegments line <#> toSegment
152 segments /\ modifySegments <- useState initialSegments
153 result /\ modifyResult <- useState Nothing
155 useTransition [ result ] (Just show)
157 { from: { opacity: 0.0, transform: "translate3d(-50%, -50%, 0) scale3d(0.3, 0.3, 1.0)" }
158 , enter: { opacity: 1.0, transform: "translate3d(-50%, -50%, 0) scale3d(1.0, 1.0, 1.0)" }
159 , leave: { opacity: 0.0, transform: "translate3d(-50%, -50%, 0) scale3d(0.3, 0.3, 1.0)" }
160 , config: mkFn2 \_ state ->
161 case spy "state" state of
162 "leave" -> { mass: 1.0, tension: 140, friction: 15 }
163 _ -> { mass: 1.0, tension: 170, friction: 20 }
165 clickAwayTransitions <-
166 useTransition [ result ] (Just show)
168 { from: { opacity: 0.0 }
169 , enter: { opacity: 1.0 }
170 , leave: { opacity: 0.0 }
171 , config: mkFn2 \_ state ->
172 case spy "state" state of
173 "leave" -> { mass: 1.0, tension: 140, friction: 15 }
174 _ -> { mass: 1.0, tension: 170, friction: 20 }
177 expectedResult = findResult (join segments)
182 res <- compileAndRun (M.fetch fetch) { code: toCode segments }
183 modifyResult (const (Just $ res)) # liftEffect
186 $ [ renderSegments ic (modifySegments) segments
190 { onClick: handler_ onClick
192 if complete segments then
201 $ clickAwayTransitions
202 >>= \{ item, key, props } ->
206 [element clickAway (justifill { style: props, onClick: modifyResult (const Nothing) })]
209 >>= \{ item, key, props } ->
217 | S.stripSuffix (S.Pattern "\n") stdout == Just expectedResult -> "Hooray!"
218 (Left l) -> "Does not compile"
219 (Right _) -> "Not " <> (findResult $ join segments)
220 , icon: element closeIcon { onClick: modifyResult (const Nothing), style: Nothing }
223 [ R.text $ compileResultToString result ]
227compileResultToString ∷ Maybe (Either CompileResult RunResult) -> String
228compileResultToString = case _ of
230 Just (Left cr) -> cr.result <#> _.message # intercalate "/n"
231 Just (Right r) -> r.stdout
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