packages feed

termbox-banana 0.3.1 → 0.4.0

raw patch · 3 files changed

+112/−142 lines, 3 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

- Termbox.Banana: type TermboxEvent = Event
+ Termbox.Banana: EventUser :: a -> Event a
+ Termbox.Banana: instance GHC.Classes.Eq a => GHC.Classes.Eq (Termbox.Banana.Event a)
+ Termbox.Banana: instance GHC.Classes.Ord a => GHC.Classes.Ord (Termbox.Banana.Event a)
+ Termbox.Banana: instance GHC.Show.Show a => GHC.Show.Show (Termbox.Banana.Event a)
+ Termbox.Banana: type Program a b = (a -> IO ()) " Callback that produces a user event." -> Event (Event a) " Event stream." -> Behavior (Int, Int) " Time-varying terminal size (width, then height)." -> MomentIO (Behavior (Cells, Cursor), Event b) " The time-varying scene to render, and an event stream of arbitrary values, only the first of which is relevant, which ends the @termbox@ program and returns from 'run'."
- Termbox.Banana: EventKey :: !Key -> Event
+ Termbox.Banana: EventKey :: !Key -> Event a
- Termbox.Banana: EventMouse :: !Mouse -> !Int -> !Int -> Event
+ Termbox.Banana: EventMouse :: !Mouse -> !Int -> !Int -> Event a
- Termbox.Banana: EventResize :: !Int -> !Int -> Event
+ Termbox.Banana: EventResize :: !Int -> !Int -> Event a
- Termbox.Banana: data Event
+ Termbox.Banana: data Event a
- Termbox.Banana: run :: (Event TermboxEvent -> Behavior (Int, Int) -> MomentIO (Behavior (Cells, Cursor), Event a)) -> IO a
+ Termbox.Banana: run :: Program a b -> IO b

Files

CHANGELOG.md view
@@ -1,30 +1,30 @@-# Changelog--All notable changes to this project will be documented in this file.+## [0.4.0] - 2022-07-16 -The format is based on [Keep a Changelog](http://keepachangelog.com/)-and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).+- Parameterize `TermboxEvent` (now `Event`) by user event+- Add `Program` type alias for readability+- Remove `TermboxEvent` alias+- Drop GHC 8.2 support  ## [0.3.1] - 2022-04-02 -- Removed example executables+- Remove example executables  ## [0.3.0] - 2020-09-20  - Support GHC 8.8, GHC 8.10 - Depend on `termbox ==0.3`-- Removed `Scene`+- Remove `Scene`  ## [0.2.0] - 2019-06-28 -- Added `run`-- Renamed `main` to `run_`-- Bumped `termbox` lower bound+- Add `run`+- Rename `main` to `run_`+- Bump `termbox` lower bound  ## [0.1.1] - 2019-04-19 -- Removed unnecessary `stm` dependency-- Bumped `base` upper bound+- Remov unnecessary `stm` dependency+- Bump `base` upper bound  ## [0.1.0] - 2018-07-22 
src/Termbox/Banana.hs view
@@ -2,11 +2,15 @@ {-# LANGUAGE ScopedTypeVariables #-}  module Termbox.Banana-  ( -- $intro-    TermboxEvent,+  ( -- * Introduction+    -- $intro++    -- * Core API+    Event (..),+    Program,     run, -    -- * Re-exports+    -- * Re-exports from @termbox@     Termbox.black,     Termbox.blue,     Termbox.bold,@@ -23,7 +27,6 @@     Termbox.Cell (..),     Termbox.Cells,     Termbox.Cursor (..),-    Termbox.Event (..),     Termbox.InitError (..),     Termbox.Key (..),     pattern Termbox.KeyCtrl2,@@ -38,125 +41,36 @@     pattern Termbox.KeyCtrlUnderscore,     Termbox.Mouse (..),     Termbox.PollError (..),--    -- * Example-    -- $example   ) where  import Control.Concurrent.MVar+import Control.Monad.IO.Class (liftIO) import Data.Function (fix)-import Reactive.Banana-import Reactive.Banana.Frameworks+import qualified Reactive.Banana as Banana+import qualified Reactive.Banana.Frameworks as Banana import qualified Termbox  -- $intro--- See the bottom of this module for a simple, runnable example to get started. ----- This module is intended to be imported qualified.+-- This module is intended to be imported qualified: -- -- @ -- import qualified Termbox.Banana as Termbox -- @---- | A @termbox@ event. This type alias exists only for Haddock readability;--- in code, you are encouraged to use ----- * @Event@ for @reactive-banana@ events--- * @Termbox.Event@ for @termbox@ events-type TermboxEvent =-  Termbox.Event--type EventSource a =-  (AddHandler a, a -> IO ())---- | Run a @termbox@ program with the specified input and output modes.------ Given------ * the terminal event stream--- * the time-varying terminal size (width, then height)------ return------ * a time-varying scene to render--- * an event stream of arbitrary values, only the first of which is relevant,---   which ends the @termbox@ program and returns from the @main@ action.-run ::-  ( Event TermboxEvent ->-    Behavior (Int, Int) ->-    MomentIO (Behavior (Termbox.Cells, Termbox.Cursor), Event a)-  ) ->-  IO a-run program =-  Termbox.run $ \width height render poll -> do-    doneVar :: MVar a <--      newEmptyMVar--    (eventAddHandler, fireEvent) :: EventSource TermboxEvent <--      newAddHandler--    network :: EventNetwork <--      compile $ do-        eEvent :: Event TermboxEvent <--          fromAddHandler eventAddHandler--        let eResize :: Event (Int, Int)-            eResize =-              filterJust-                ( ( \case-                      Termbox.EventResize w h -> Just (w, h)-                      _ -> Nothing-                  )-                    <$> eEvent-                )--        bSize :: Behavior (Int, Int) <--          flip stepper eResize (width, height)--        moment (uncurry render) program eEvent bSize (putMVar doneVar)--    actuate network--    fix $ \loop -> do-      poll >>= fireEvent-      tryReadMVar doneVar >>= maybe loop pure--moment ::-  ((Termbox.Cells, Termbox.Cursor) -> IO ()) ->-  ( Event TermboxEvent ->-    Behavior (Int, Int) ->-    MomentIO (Behavior (Termbox.Cells, Termbox.Cursor), Event a)-  ) ->-  Event TermboxEvent ->-  Behavior (Int, Int) ->-  (a -> IO ()) ->-  MomentIO ()-moment render program eEvent bSize abort = do-  (bScene, eDone) :: (Behavior (Termbox.Cells, Termbox.Cursor), Event a) <--    program eEvent bSize--  eScene :: Event (Future (Termbox.Cells, Termbox.Cursor)) <--    changes bScene--  liftIO . render =<< valueB bScene-  reactimate (abort <$> eDone)-  reactimate' ((fmap . fmap) render eScene)---- $example+-- ==== __👉 Quick start example__ ----- Below is a sample program that simply displays the last key pressed, and--- quits on @Esc@:+-- This is a program that displays the last key pressed, and quits on @Esc@: -- -- @--- {-\# LANGUAGE LambdaCase          \#-}--- {-\# LANGUAGE ScopedTypeVariables \#-}+-- {-\# LANGUAGE LambdaCase \#-} -- -- module Main where --+-- import Data.Void (Void) -- import Reactive.Banana -- import Reactive.Banana.Frameworks--- -- import qualified Termbox.Banana as Termbox -- -- main :: IO ()@@ -164,42 +78,94 @@ --   Termbox.'run' moment -- -- moment---   :: Event Termbox.'Termbox.Event'+--   :: (Void -> IO ())+--   -> Event (Termbox.'Event' Void) --   -> Behavior (Int, Int) --   -> MomentIO (Behavior (Termbox.'Termbox.Cells', Termbox.'Termbox.Cursor'), Event ())--- moment eEvent _bSize = do---   let---     eQuit :: Event ()---     eQuit =---       () <$ filterE isKeyEsc eEvent------   bLatestEvent :: Behavior (Maybe Termbox.'Termbox.Event') <----     stepper---       Nothing---       (Just \<$\> eEvent)------   let---     bCells :: Behavior Termbox.'Termbox.Cells'---     bCells =---       maybe mempty renderEvent \<$\> bLatestEvent------   let---     bScene :: Behavior (Termbox.'Termbox.Cells', Termbox.'Termbox.Cursor')---     bScene =---       (,)---         \<$\> bCells---         \<*\> pure Termbox.'Termbox.NoCursor'---+-- moment _fireUserEvent eEvent _bSize = do+--   let eQuit = () <$ filterE isKeyEsc eEvent+--   bLatestEvent <- stepper Nothing (Just \<$\> eEvent)+--   let bCells = maybe mempty renderEvent \<$\> bLatestEvent+--   let bScene = (,) \<$\> bCells \<*\> pure Termbox.'Termbox.NoCursor' --   pure (bScene, eQuit) ----- renderEvent :: Termbox.'Termbox.Event' -> Termbox.'Termbox.Cells'+-- renderEvent :: Show a => Termbox.'Event' a -> Termbox.'Termbox.Cells' -- renderEvent = --   foldMap (\\(i, c) -> Termbox.set i 0 (Termbox.'Termbox.Cell' c mempty mempty)) --     . zip [0..] --     . show ----- isKeyEsc :: Termbox.'Termbox.Event' -> Bool+-- isKeyEsc :: Termbox.'Event' a -> Bool -- isKeyEsc = \\case---   Termbox.'Termbox.EventKey' Termbox.'Termbox.KeyEsc' _ -> True+--   Termbox.'EventKey' Termbox.'Termbox.KeyEsc' -> True --   _ -> False -- @++-- | A key press, terminal resize, mouse click, or a user event.+data Event a+  = EventKey !Termbox.Key+  | EventResize !Int !Int+  | EventMouse !Termbox.Mouse !Int !Int+  | EventUser a+  deriving stock (Eq, Ord, Show)++type Program a b =+  -- | Callback that produces a user event.+  (a -> IO ()) ->+  -- | Event stream.+  Banana.Event (Event a) ->+  -- | Time-varying terminal size (width, then height).+  Banana.Behavior (Int, Int) ->+  -- | The time-varying scene to render, and an event stream of arbitrary values, only the first of which is relevant,+  -- which ends the @termbox@ program and returns from 'run'.+  Banana.MomentIO (Banana.Behavior (Termbox.Cells, Termbox.Cursor), Banana.Event b)++-- | Run a @termbox@ program.+run :: Program a b -> IO b+run program =+  Termbox.run $ \initialWidth initialHeight render poll -> do+    doneVar <- newEmptyMVar+    (eventAddHandler, fireEvent) <- Banana.newAddHandler+    (userEventAddHandler, fireUserEvent) <- Banana.newAddHandler++    network <-+      Banana.compile $ do+        eEvent <- Banana.fromAddHandler eventAddHandler+        eUserEvent <- Banana.fromAddHandler userEventAddHandler+        let eTermboxEvent =+              Banana.unionWith+                const+                ( ( \case+                      Termbox.EventKey key -> EventKey key+                      Termbox.EventResize width height -> EventResize width height+                      Termbox.EventMouse mouse col row -> EventMouse mouse col row+                  )+                    <$> eEvent+                )+                (EventUser <$> eUserEvent)++        let eResize :: Banana.Event (Int, Int)+            eResize =+              Banana.filterJust+                ( ( \case+                      Termbox.EventResize w h -> Just (w, h)+                      _ -> Nothing+                  )+                    <$> eEvent+                )++        bSize <- Banana.stepper (initialWidth, initialHeight) eResize+        (bScene, eDone) <- program fireUserEvent eTermboxEvent bSize+        let bRender = (\(cells, cursor) -> render cells cursor) <$> bScene+        eRender <- Banana.changes bRender+        do+          action <- Banana.valueB bRender+          liftIO action+        Banana.reactimate (putMVar doneVar <$> eDone)+        Banana.reactimate' eRender++    Banana.actuate network++    fix $ \loop -> do+      poll >>= fireEvent+      tryReadMVar doneVar >>= maybe loop pure
termbox-banana.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4  name: termbox-banana-version: 0.3.1+version: 0.4.0 category: User Interfaces description:   A @reactive-banana@-based interface to writing @termbox@ programs.@@ -29,10 +29,11 @@  library   build-depends:-    base ^>= 4.10 || ^>= 4.11 || ^>= 4.12 || ^>= 4.13 || ^>= 4.14 || ^>= 4.15 || ^>= 4.16,+    base ^>= 4.11 || ^>= 4.12 || ^>= 4.13 || ^>= 4.14 || ^>= 4.15 || ^>= 4.16,     reactive-banana ^>= 1.2 || ^>= 1.3,     termbox ^>= 0.3,   default-extensions:+    DerivingStrategies     GeneralizedNewtypeDeriving     InstanceSigs     LambdaCase@@ -50,4 +51,7 @@     ghc-options:       -Wno-missing-safe-haskell-mode       -Wno-prepositive-qualified-module+  if impl(ghc >= 9.2)+    ghc-options:+      -Wno-missing-kind-signatures   hs-source-dirs: src