1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE OverloadedStrings #-}
7{-# LANGUAGE RankNTypes #-}
8{-# LANGUAGE RecursiveDo #-}
9{-# LANGUAGE ScopedTypeVariables #-}
10{-# LANGUAGE TupleSections #-}
11{-# OPTIONS_GHC -threaded #-}
13import Control.Applicative
14import Control.Monad.Fix
16import qualified Data.Map as Map
17import Data.Text (Text)
18import qualified Data.Text as T
19import qualified Data.Text.Zipper as TZ
20import qualified Graphics.Vty as V
22import Reflex.Class.Switchable
23import Reflex.NotReady.Class
29 tellShutdown . fforMaybe inp $ \case
30 V.EvKey (V.KChar 'c') [V.MCtrl] -> Just ()
32 let btn = button $ pure "Add another task"
33 rec let todos' = todos [Todo "First" True, Todo "Second" False, Todo "Third" False] $ leftmost
35 , fforMaybe inp $ \case
36 V.EvKey V.KEnter [] -> Just ()
39 (m, (e, _)) <- splitV (pure (subtract 6)) (pure (True, True)) todos' $ do
40 splitV (pure (subtract 3)) (pure (True, True)) btn (display $ current m)
43testBoxes :: (Reflex t, MonadHold t m, MonadFix m) => VtyWidget t m ()
46 let region1 = fmap (\(w,h) -> Region (w `div` 6) (h `div` 6) (w `div` 2) (h `div` 2)) size
47 region2 = fmap (\(w,h) -> Region (w `div` 4) (h `div` 4) (2 * (w `div` 3)) (2*(h `div` 3))) size
48 pane region1 (constDyn False) . box singleBoxStyle $ debugInput
49 _ <- pane region2 (constDyn True) . box singleBoxStyle $
50 splitVDrag (hRule doubleBoxStyle) (box roundedBoxStyle $ multilineTextInput def) (box roundedBoxStyle dragTest)
53debugFocus :: (Reflex t, Monad m) => VtyWidget t m ()
56 text $ T.pack . show <$> current f
58debugInput :: (Reflex t, MonadHold t m) => VtyWidget t m ()
60 lastEvent <- hold "No event yet" . fmap show =<< input
61 text $ T.pack <$> lastEvent
63dragTest :: (Reflex t, MonadHold t m, MonadFix m) => VtyWidget t m ()
65 lastEvent <- hold "No event yet" . fmap show =<< drag V.BLeft
66 text $ T.pack <$> lastEvent
68testStringBox :: (Reflex t, Monad m) => VtyWidget t m ()
69testStringBox = box singleBoxStyle .
70 text . pure . T.pack . take 500 $ cycle ('\n' : ['a'..'z'])
76 deriving (Show, Read, Eq, Ord)
79 :: (MonadHold t m, MonadFix m, Reflex t)
81 -> VtyWidget t m (Dynamic t Bool)
84 v <- toggle v0 $ fforMaybe i $ \case
85 V.EvMouseUp _ _ _ -> Just ()
87 text $ current $ ffor v $ \v' -> if v' then "[x]" else "[ ]"
90button :: (Reflex t, Monad m) => Behavior t Text -> VtyWidget t m (Event t ())
92 box roundedBoxStyle $ text t
95data TodoOutput t = TodoOutput
96 { _todoOutput_todo :: Dynamic t Todo
97 , _todoOutput_delete :: Event t ()
100instance Reflex t => Switchable t (TodoOutput t) where
101 switching t0 e = TodoOutput
102 <$> switching (_todoOutput_todo t0) (_todoOutput_todo <$> e)
103 <*> switching (_todoOutput_delete t0) (_todoOutput_delete <$> e)
106 :: (MonadHold t m, MonadFix m, Reflex t)
108 -> VtyWidget t m (TodoOutput t)
111 let checkboxWidth = 3
112 checkboxRegion = pure $ Region 0 0 checkboxWidth 1
113 labelRegion = ffor w $ \w' -> Region (checkboxWidth + 1) 0 (w' - 1 - checkboxWidth) 1
114 value <- pane checkboxRegion (pure True) $ checkbox $ _todo_done t0
115 (label, d) <- pane labelRegion (pure True) $ do
117 v <- textInput $ def { _textInputConfig_initialValue = TZ.fromText $ _todo_label t0 }
118 let deleteSelf = attachWithMaybe backspaceOnEmpty (current v) i
119 return (v, deleteSelf)
121 { _todoOutput_todo = Todo <$> label <*> value
122 , _todoOutput_delete = d
125 backspaceOnEmpty v = \case
126 V.EvKey V.KBS _ | T.null v -> Just ()
130 :: forall t m. (MonadHold t m, MonadFix m, Reflex t, Adjustable t m, NotReady t m, PostBuild t m)
133 -> VtyWidget t m (Dynamic t (Map Int Todo))
134todos todos0 newTodo = do
135 let todosMap0 = Map.fromList $ zip [0..] todos0
137 rec listOut <- listHoldWithKey todosMap0 updates $ \row t -> do
138 let reg = zipDynWith (\w' ts ->
139 let l = Map.size $ Map.takeWhileAntitone (<row) ts
140 in Region 0 l w' 1) w todosMap
141 pane reg (fmap (==row) selected) $ do
145 let selectionClick = switch . current $ fmap (leftmost . Map.elems . fmap fst) listOut
146 selected <- holdDyn 0 $ leftmost
148 , fmapMaybe (fmap fst . Map.lookupMax) insert
151 let todosMap = joinDynThroughMap $ fmap (fmap (_todoOutput_todo . snd)) listOut
152 todoDelete = switch . current $
153 leftmost . Map.elems . Map.mapWithKey (\k -> (k <$) . _todoOutput_delete . snd) <$> listOut
154 selectOnDelete = attachWithMaybe
155 (\m k -> let (before, after) = Map.split k m
156 in fmap fst $ Map.lookupMax before <|> Map.lookupMin after)
159 insert = ffor (tag (current todosMap) newTodo) $ \m -> case Map.lookupMax m of
160 Nothing -> Map.singleton 0 $ Just $ Todo "" False
161 Just (k, _) -> Map.union (Just <$> m) $ Map.singleton (k+1) $ Just $ Todo "" False
162 delete = ffor (attach (current todosMap) todoDelete) $ \(m, k) ->
163 Map.union (Map.singleton k Nothing) $ Just <$> m
164 updates = leftmost [insert, delete]
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