packages feed

brick 0.46 → 0.47

raw patch · 10 files changed

+135/−76 lines, 10 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Brick.Main: customMainWithVty :: Ord n => Vty -> IO Vty -> Maybe (BChan e) -> App s e n -> s -> IO (s, Vty)
- Brick.BorderMap: eBottomL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.BorderMap: eBottomL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.BorderMap: eLeftL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.BorderMap: eLeftL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.BorderMap: eRightL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.BorderMap: eRightL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.BorderMap: eTopL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.BorderMap: eTopL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.Main: customMain :: Ord n => IO Vty -> Maybe (BChan e) -> App s e n -> s -> IO s
+ Brick.Main: customMain :: Ord n => Vty -> IO Vty -> Maybe (BChan e) -> App s e n -> s -> IO s
- Brick.Types: bordersL :: forall n_aGj7. Lens' (Result n_aGj7) (BorderMap DynBorder)
+ Brick.Types: bordersL :: forall n_aGdW. Lens' (Result n_aGdW) (BorderMap DynBorder)
- Brick.Types: cursorLocationL :: forall n_aEXI. Lens' (CursorLocation n_aEXI) Location
+ Brick.Types: cursorLocationL :: forall n_aESx. Lens' (CursorLocation n_aESx) Location
- Brick.Types: cursorLocationNameL :: forall n_aEXI n_aGWj. Lens (CursorLocation n_aEXI) (CursorLocation n_aGWj) (Maybe n_aEXI) (Maybe n_aGWj)
+ Brick.Types: cursorLocationNameL :: forall n_aESx n_aGR8. Lens (CursorLocation n_aESx) (CursorLocation n_aGR8) (Maybe n_aESx) (Maybe n_aGR8)
- Brick.Types: cursorsL :: forall n_aGj7. Lens' (Result n_aGj7) [CursorLocation n_aGj7]
+ Brick.Types: cursorsL :: forall n_aGdW. Lens' (Result n_aGdW) [CursorLocation n_aGdW]
- Brick.Types: eBottomL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.Types: eBottomL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.Types: eLeftL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.Types: eLeftL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.Types: eRightL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.Types: eRightL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.Types: eTopL :: forall a_ajaQ. Lens' (Edges a_ajaQ) a_ajaQ
+ Brick.Types: eTopL :: forall a_aj62. Lens' (Edges a_aj62) a_aj62
- Brick.Types: extentsL :: forall n_aGj7. Lens' (Result n_aGj7) [Extent n_aGj7]
+ Brick.Types: extentsL :: forall n_aGdW. Lens' (Result n_aGdW) [Extent n_aGdW]
- Brick.Types: imageL :: forall n_aGj7. Lens' (Result n_aGj7) Image
+ Brick.Types: imageL :: forall n_aGdW. Lens' (Result n_aGdW) Image
- Brick.Types: visibilityRequestsL :: forall n_aGj7. Lens' (Result n_aGj7) [VisibilityRequest]
+ Brick.Types: visibilityRequestsL :: forall n_aGdW. Lens' (Result n_aGdW) [VisibilityRequest]
- Brick.Widgets.Dialog: dialogButtonsL :: forall a_a1gjJ a_a1gkq. Lens (Dialog a_a1gjJ) (Dialog a_a1gkq) [(String, a_a1gjJ)] [(String, a_a1gkq)]
+ Brick.Widgets.Dialog: dialogButtonsL :: forall a_a1gez a_a1gfg. Lens (Dialog a_a1gez) (Dialog a_a1gfg) [(String, a_a1gez)] [(String, a_a1gfg)]
- Brick.Widgets.Dialog: dialogSelectedIndexL :: forall a_a1gjJ. Lens' (Dialog a_a1gjJ) (Maybe Int)
+ Brick.Widgets.Dialog: dialogSelectedIndexL :: forall a_a1gez. Lens' (Dialog a_a1gez) (Maybe Int)
- Brick.Widgets.Dialog: dialogTitleL :: forall a_a1gjJ. Lens' (Dialog a_a1gjJ) (Maybe String)
+ Brick.Widgets.Dialog: dialogTitleL :: forall a_a1gez. Lens' (Dialog a_a1gez) (Maybe String)
- Brick.Widgets.Dialog: dialogWidthL :: forall a_a1gjJ. Lens' (Dialog a_a1gjJ) Int
+ Brick.Widgets.Dialog: dialogWidthL :: forall a_a1gez. Lens' (Dialog a_a1gez) Int
- Brick.Widgets.Edit: editContentsL :: forall t_a1bmS n_a1bmT t_a1bnC. Lens (Editor t_a1bmS n_a1bmT) (Editor t_a1bnC n_a1bmT) (TextZipper t_a1bmS) (TextZipper t_a1bnC)
+ Brick.Widgets.Edit: editContentsL :: forall t_a1bhI n_a1bhJ t_a1bis. Lens (Editor t_a1bhI n_a1bhJ) (Editor t_a1bis n_a1bhJ) (TextZipper t_a1bhI) (TextZipper t_a1bis)
- Brick.Widgets.FileBrowser: fileBrowserEntryFilterL :: forall n_a1qKW. Lens' (FileBrowser n_a1qKW) (Maybe (FileInfo -> Bool))
+ Brick.Widgets.FileBrowser: fileBrowserEntryFilterL :: forall n_a1qKE. Lens' (FileBrowser n_a1qKE) (Maybe (FileInfo -> Bool))
- Brick.Widgets.FileBrowser: fileBrowserSelectableL :: forall n_a1qKW. Lens' (FileBrowser n_a1qKW) (FileInfo -> Bool)
+ Brick.Widgets.FileBrowser: fileBrowserSelectableL :: forall n_a1qKE. Lens' (FileBrowser n_a1qKE) (FileInfo -> Bool)
- Brick.Widgets.List: listElementsL :: forall n_a1ll0 t_a1ll1 e_a1ll2 t_a1lzY e_a1lzZ. Lens (GenericList n_a1ll0 t_a1ll1 e_a1ll2) (GenericList n_a1ll0 t_a1lzY e_a1lzZ) (t_a1ll1 e_a1ll2) (t_a1lzY e_a1lzZ)
+ Brick.Widgets.List: listElementsL :: forall n_a1ll8 t_a1ll9 e_a1lla t_a1lzI e_a1lzJ. Lens (GenericList n_a1ll8 t_a1ll9 e_a1lla) (GenericList n_a1ll8 t_a1lzI e_a1lzJ) (t_a1ll9 e_a1lla) (t_a1lzI e_a1lzJ)
- Brick.Widgets.List: listItemHeightL :: forall n_a1ll0 t_a1ll1 e_a1ll2. Lens' (GenericList n_a1ll0 t_a1ll1 e_a1ll2) Int
+ Brick.Widgets.List: listItemHeightL :: forall n_a1ll8 t_a1ll9 e_a1lla. Lens' (GenericList n_a1ll8 t_a1ll9 e_a1lla) Int
- Brick.Widgets.List: listNameL :: forall n_a1ll0 t_a1ll1 e_a1ll2 n_a1lA0. Lens (GenericList n_a1ll0 t_a1ll1 e_a1ll2) (GenericList n_a1lA0 t_a1ll1 e_a1ll2) n_a1ll0 n_a1lA0
+ Brick.Widgets.List: listNameL :: forall n_a1ll8 t_a1ll9 e_a1lla n_a1lzK. Lens (GenericList n_a1ll8 t_a1ll9 e_a1lla) (GenericList n_a1lzK t_a1ll9 e_a1lla) n_a1ll8 n_a1lzK
- Brick.Widgets.List: listSelectedL :: forall n_a1ll0 t_a1ll1 e_a1ll2. Lens' (GenericList n_a1ll0 t_a1ll1 e_a1ll2) (Maybe Int)
+ Brick.Widgets.List: listSelectedL :: forall n_a1ll8 t_a1ll9 e_a1lla. Lens' (GenericList n_a1ll8 t_a1ll9 e_a1lla) (Maybe Int)

Files

CHANGELOG.md view
@@ -2,6 +2,21 @@ Brick changelog --------------- +0.47+----++API changes:+ * Changed `Brick.Main.customMain` so that it now takes an additional+   (first) argument: the initial `Vty` handle to use. This lets the+   caller have more control over the terminal state when, for example,+   they have previously set up Vty to do other work before calling+   `customMain`.+ * Added `Brick.Main.customMainWithVty`. This function is the same as+   `customMain` except that it also returns the final `Vty` handle that+   it used internally *without* shutting that Vty handle down. This+   allows the caller to continue using the terminal without resetting it+   after `customMainWithVty` finishes executing.+ 0.46 ---- 
README.md view
@@ -1,29 +1,19 @@ ![](logo/brick-final-clearbg-with-text.svg) -`brick` is a Haskell terminal user interface programming library in the-style of [gloss](http://hackage.haskell.org/package/gloss). This means-you write a function that describes how your user interface should look,-but the library takes care of a lot of the book-keeping that so commonly-goes into writing such programs.+`brick` is a Haskell terminal user interface (TUI) programming toolkit.+To use it, you write a pure function that describes how your user+interface should look based on your current application state and you+provide a state transformation function to handle events.  `brick` exposes a declarative API. Unlike most GUI toolkits which require you to write a long and tedious sequence of "create a widget, now bind an event handler", `brick` just requires you to describe your-interface using a set of declarative combinators. Then you provide a-function to transform your application state when input or other kinds-of events arrive.+interface using a set of declarative layout combinators.  Under the hood, this library builds upon [vty](http://hackage.haskell.org/package/vty), so some knowledge of Vty will be helpful in using this library. -Release Announcements / News-------------------------------Find out about `brick` releases and other news on Twitter:--https://twitter.com/brick_haskell/- Example ------- @@ -71,6 +61,17 @@  * `solitaire`, the card game: https://github.com/ambuc/solitaire  * `sudoku-tui`, a Sudoku implementation: https://github.com/evanrelf/sudoku-tui +These third-party packages also extend `brick`:++ * [`brick-filetree`](https://github.com/ChrisPenner/brick-filetree) [[Hackage]](http://hackage.haskell.org/package/brick-filetree) - A widget for exploring a directory tree and selecting or flagging files and directories++Release Announcements / News+----------------------------++Find out about `brick` releases and other news on Twitter:++https://twitter.com/brick_haskell/+ Getting Started --------------- @@ -113,7 +114,7 @@  * Type-safe, validated input form API (see the `Brick.Forms` module)  * A filesystem browser for file and directory selection  * Borders can be configured to automatically connect!-+  Brick-Users Discussion ---------------------- 
brick.cabal view
@@ -1,5 +1,5 @@ name:                brick-version:             0.46+version:             0.47 synopsis:            A declarative terminal user interface library description:   Write terminal applications painlessly with 'brick'! You write an
docs/guide.rst view
@@ -348,8 +348,9 @@    main :: IO ()    main = do        eventChan <- Brick.BChan.newBChan 10-       finalState <- customMain-                       (Graphics.Vty.mkVty Graphics.Vty.defaultConfig)+       let buildVty = Graphics.Vty.mkVty Graphics.Vty.defaultConfig+       initialVty <- buildVty+       finalState <- customMain initialVty buildVty                        (Just eventChan) app initialState        -- Use finalState and exit 
docs/samtay-tutorial.md view
@@ -290,7 +290,9 @@     writeBChan chan Tick     threadDelay 100000 -- decides how fast your game moves   g <- initGame-  void $ customMain (V.mkVty V.defaultConfig) (Just chan) app g+  let buildVty = V.mkVty V.defaultConfig+  initialVty <- buildVty+  void $ customMain initialVty buildVty (Just chan) app g ```  We do need to import `Vty.Graphics` since `customMain` allows us@@ -482,7 +484,9 @@     writeBChan chan Tick     int <- atomically $ readTVar tv     threadDelay int-  customMain (V.mkVty V.defaultConfig) (Just chan) app (initialGame tv)+  let buildVty = V.mkVty V.defaultConfig+  initialVty <- buildVty+  customMain initialVty buildVty (Just chan) app (initialGame tv)     >>= printResult ``` 
programs/CustomEventDemo.hs view
@@ -82,4 +82,6 @@         writeBChan chan Counter         threadDelay 1000000 -    void $ customMain (V.mkVty V.defaultConfig) (Just chan) theApp initialState+    let buildVty = V.mkVty V.defaultConfig+    initialVty <- buildVty+    void $ customMain initialVty buildVty (Just chan) theApp initialState
programs/FormDemo.hs view
@@ -145,7 +145,8 @@         f = setFieldValid False AgeField $             mkForm initialUserInfo -    f' <- customMain buildVty Nothing app f+    initialVty <- buildVty+    f' <- customMain initialVty buildVty Nothing app f      putStrLn "The starting form state was:"     print initialUserInfo
programs/MouseDemo.hs view
@@ -123,7 +123,8 @@           V.setMode (V.outputIface v) V.Mouse True           return v -    void $ M.customMain buildVty Nothing app $ St [] Nothing+    initialVty <- buildVty+    void $ M.customMain initialVty buildVty Nothing app $ St [] Nothing            "Try clicking on various UI elements.\n\            \Observe that the click coordinates identify the\n\            \underlying widget coordinates.\n\
src/Brick/Main.hs view
@@ -1,7 +1,9 @@+{-# LANGUAGE ScopedTypeVariables #-} module Brick.Main   ( App(..)   , defaultMain   , customMain+  , customMainWithVty   , simpleMain   , resizeOrQuit   , simpleApp@@ -46,7 +48,7 @@   ) where -import Control.Exception (finally)+import qualified Control.Exception as E import Lens.Micro ((^.), (&), (.~), (%~), _1, _2) import Control.Monad (forever) import Control.Monad.Trans.Class (lift)@@ -127,7 +129,9 @@             -- ^ The initial application state.             -> IO s defaultMain app st = do-    customMain (mkVty defaultConfig) Nothing app st+    let builder = mkVty defaultConfig+    initialVty <- builder+    customMain initialVty builder Nothing app st  -- | A simple main entry point which takes a widget and renders it. This -- event loop terminates when the user presses any key, but terminal@@ -170,39 +174,42 @@ readBrickEvent :: BChan (BrickEvent n e) -> BChan e -> IO (BrickEvent n e) readBrickEvent brickChan userChan = either id AppEvent <$> readBChan2 brickChan userChan -runWithNewVty :: (Ord n)-              => Vty-              -> BChan (BrickEvent n e)-              -> Maybe (BChan e)-              -> App s e n-              -> RenderState n-              -> s-              -> IO (InternalNext n s)-runWithNewVty buildVty brickChan mUserChan app initialRS initialSt =-    withVty buildVty $ \vty -> do-        pid <- forkIO $ supplyVtyEvents vty brickChan-        let readEvent = case mUserChan of-              Nothing -> readBChan brickChan-              Just uc -> readBrickEvent brickChan uc-            runInner rs st = do-              (result, newRS) <- runVty vty readEvent app st (resetRenderState rs)-              case result of-                  SuspendAndResume act -> do-                      killThread pid-                      return $ InternalSuspendAndResume newRS act-                  Halt s -> do-                      killThread pid-                      return $ InternalHalt s-                  Continue s -> runInner newRS s-        runInner initialRS initialSt+runWithVty :: (Ord n)+           => Vty+           -> BChan (BrickEvent n e)+           -> Maybe (BChan e)+           -> App s e n+           -> RenderState n+           -> s+           -> IO (InternalNext n s)+runWithVty vty brickChan mUserChan app initialRS initialSt = do+    pid <- forkIO $ supplyVtyEvents vty brickChan+    let readEvent = case mUserChan of+          Nothing -> readBChan brickChan+          Just uc -> readBrickEvent brickChan uc+        runInner rs st = do+          (result, newRS) <- runVty vty readEvent app st (resetRenderState rs)+          case result of+              SuspendAndResume act -> do+                  killThread pid+                  return $ InternalSuspendAndResume newRS act+              Halt s -> do+                  killThread pid+                  return $ InternalHalt s+              Continue s -> runInner newRS s+    runInner initialRS initialSt  -- | The custom event loop entry point to use when the simpler ones--- don't permit enough control.+-- don't permit enough control. Returns the final application state+-- after the application halts. customMain :: (Ord n)-           => IO Vty-           -- ^ An IO action to build a Vty handle. This is used to-           -- build a Vty handle whenever the event loop begins or is-           -- resumed after suspension.+           => Vty+           -- ^ The initial Vty handle to use.+           -> IO Vty+           -- ^ An IO action to build a Vty handle. This is used+           -- to build a Vty handle whenever the event loop needs+           -- to reinitialize the terminal, e.g. on resume after+           -- suspension.            -> Maybe (BChan e)            -- ^ An event channel for sending custom events to the event            -- loop (you write to this channel, the event loop reads from@@ -213,20 +220,49 @@            -> s            -- ^ The initial application state.            -> IO s-customMain buildVty mUserChan app initialAppState = do-    initialVty <- buildVty+customMain initialVty buildVty mUserChan app initialAppState = do+    (s, vty) <- customMainWithVty initialVty buildVty mUserChan app initialAppState+    shutdown vty+    return s++-- | Like 'customMain', except the last 'Vty' handle used by the+-- application is returned without being shut down with 'shutdown'. This+-- allows the caller to re-use the 'Vty' handle for something else, such+-- as another Brick application.+customMainWithVty :: (Ord n)+                  => Vty+                  -- ^ The initial Vty handle to use.+                  -> IO Vty+                  -- ^ An IO action to build a Vty handle. This is used+                  -- to build a Vty handle whenever the event loop needs+                  -- to reinitialize the terminal, e.g. on resume after+                  -- suspension.+                  -> Maybe (BChan e)+                  -- ^ An event channel for sending custom events to the event+                  -- loop (you write to this channel, the event loop reads from+                  -- it). Provide 'Nothing' if you don't plan on sending custom+                  -- events.+                  -> App s e n+                  -- ^ The application.+                  -> s+                  -- ^ The initial application state.+                  -> IO (s, Vty)+customMainWithVty initialVty buildVty mUserChan app initialAppState = do     let run vty rs st brickChan = do-            result <- runWithNewVty vty brickChan mUserChan app rs st+            result <- runWithVty vty brickChan mUserChan app rs st+                `E.catch` (\(e::E.SomeException) -> shutdown vty >> E.throw e)             case result of-                InternalHalt s -> return s+                InternalHalt s -> return (s, vty)                 InternalSuspendAndResume newRS action -> do+                    shutdown vty                     newAppState <- action                     newVty <- buildVty                     run newVty (newRS { renderCache = mempty }) newAppState brickChan -        emptyES = ES [] mempty+    let emptyES = ES [] mempty         emptyRS = RS M.empty mempty S.empty mempty mempty         eventRO = EventRO M.empty initialVty mempty emptyRS+     (st, eState) <- runStateT (runReaderT (runEventM (appStartEvent app initialAppState)) eventRO) emptyES     let initialRS = RS M.empty (esScrollRequests eState) S.empty mempty []     brickChan <- newBChan 20@@ -373,10 +409,6 @@ invalidateCache :: (Ord n) => EventM n () invalidateCache = EventM $ do     lift $ modify (\s -> s { cacheInvalidateRequests = S.insert InvalidateEntire $ cacheInvalidateRequests s })--withVty :: Vty -> (Vty -> IO a) -> IO a-withVty vty useVty = do-    useVty vty `finally` shutdown vty  getRenderState :: EventM n (RenderState n) getRenderState = EventM $ asks oldState
src/Brick/Widgets/Core.hs view
@@ -995,13 +995,8 @@          -> Widget n viewport vpname typ p =     clickable vpname $ Widget Greedy Greedy $ do-      -- First, update the viewport size.-      c <- getContext-      let newVp = VP 0 0 newSize-          newSize = (c^.availWidthL, c^.availHeightL)-          doInsert (Just vp) = Just $ vp & vpSize .~ newSize-          doInsert Nothing = Just newVp-+      -- Observe the viewport name so we can detect multiple uses of the+      -- name.       let observeName :: (Ord n, Show n) => n -> RenderM n ()           observeName n = do               observed <- use observedNamesL@@ -1017,12 +1012,19 @@        observeName vpname +      -- Update the viewport size.+      c <- getContext+      let newVp = VP 0 0 newSize+          newSize = (c^.availWidthL, c^.availHeightL)+          doInsert (Just vp) = Just $ vp & vpSize .~ newSize+          doInsert Nothing = Just newVp+       lift $ modify (& viewportMapL %~ (M.alter doInsert vpname)) -      -- Then render the sub-rendering with the rendering layout-      -- constraint released (but raise an exception if we are asked to-      -- render an infinitely-sized widget in the viewport's scrolling-      -- dimension)+      -- Then render the viewport content widget with the rendering+      -- layout constraint released (but raise an exception if we are+      -- asked to render an infinitely-sized widget in the viewport's+      -- scrolling dimension)       let release = case typ of             Vertical -> vRelease             Horizontal -> hRelease