brick 0.60.2 → 0.61
raw patch · 8 files changed
+67/−14 lines, 8 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Brick.Forms: editShowableFieldWithValidate :: (Ord n, Show n, Read a, Show a) => Lens' s a -> n -> (a -> Bool) -> s -> FormFieldState s e n
- Brick.BorderMap: eBottomL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.BorderMap: eBottomL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.BorderMap: eLeftL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.BorderMap: eLeftL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.BorderMap: eRightL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.BorderMap: eRightL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.BorderMap: eTopL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.BorderMap: eTopL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.Types: bordersL :: forall n_axZg. Lens' (Result n_axZg) (BorderMap DynBorder)
+ Brick.Types: bordersL :: forall n_axVH. Lens' (Result n_axVH) (BorderMap DynBorder)
- Brick.Types: cursorLocationL :: forall n_awLM. Lens' (CursorLocation n_awLM) Location
+ Brick.Types: cursorLocationL :: forall n_awIf. Lens' (CursorLocation n_awIf) Location
- Brick.Types: cursorLocationNameL :: forall n_awLM n_ayCO. Lens (CursorLocation n_awLM) (CursorLocation n_ayCO) (Maybe n_awLM) (Maybe n_ayCO)
+ Brick.Types: cursorLocationNameL :: forall n_awIf n_ayzf. Lens (CursorLocation n_awIf) (CursorLocation n_ayzf) (Maybe n_awIf) (Maybe n_ayzf)
- Brick.Types: cursorsL :: forall n_axZg. Lens' (Result n_axZg) [CursorLocation n_axZg]
+ Brick.Types: cursorsL :: forall n_axVH. Lens' (Result n_axVH) [CursorLocation n_axVH]
- Brick.Types: eBottomL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.Types: eBottomL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.Types: eLeftL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.Types: eLeftL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.Types: eRightL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.Types: eRightL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.Types: eTopL :: forall a_acV3. Lens' (Edges a_acV3) a_acV3
+ Brick.Types: eTopL :: forall a_acVj. Lens' (Edges a_acVj) a_acVj
- Brick.Types: extentsL :: forall n_axZg. Lens' (Result n_axZg) [Extent n_axZg]
+ Brick.Types: extentsL :: forall n_axVH. Lens' (Result n_axVH) [Extent n_axVH]
- Brick.Types: imageL :: forall n_axZg. Lens' (Result n_axZg) Image
+ Brick.Types: imageL :: forall n_axVH. Lens' (Result n_axVH) Image
- Brick.Types: visibilityRequestsL :: forall n_axZg. Lens' (Result n_axZg) [VisibilityRequest]
+ Brick.Types: visibilityRequestsL :: forall n_axVH. Lens' (Result n_axVH) [VisibilityRequest]
- Brick.Widgets.Dialog: dialogButtonsL :: forall a_a1920 a_a192E. Lens (Dialog a_a1920) (Dialog a_a192E) [(String, a_a1920)] [(String, a_a192E)]
+ Brick.Widgets.Dialog: dialogButtonsL :: forall a_a18Yy a_a18Zc. Lens (Dialog a_a18Yy) (Dialog a_a18Zc) [(String, a_a18Yy)] [(String, a_a18Zc)]
- Brick.Widgets.Dialog: dialogSelectedIndexL :: forall a_a1920. Lens' (Dialog a_a1920) (Maybe Int)
+ Brick.Widgets.Dialog: dialogSelectedIndexL :: forall a_a18Yy. Lens' (Dialog a_a18Yy) (Maybe Int)
- Brick.Widgets.Dialog: dialogTitleL :: forall a_a1920. Lens' (Dialog a_a1920) (Maybe String)
+ Brick.Widgets.Dialog: dialogTitleL :: forall a_a18Yy. Lens' (Dialog a_a18Yy) (Maybe String)
- Brick.Widgets.Dialog: dialogWidthL :: forall a_a1920. Lens' (Dialog a_a1920) Int
+ Brick.Widgets.Dialog: dialogWidthL :: forall a_a18Yy. Lens' (Dialog a_a18Yy) Int
- Brick.Widgets.Edit: editContentsL :: forall t_a13xB n_a13xC t_a13yg. Lens (Editor t_a13xB n_a13xC) (Editor t_a13yg n_a13xC) (TextZipper t_a13xB) (TextZipper t_a13yg)
+ Brick.Widgets.Edit: editContentsL :: forall t_a13u9 n_a13ua t_a13uO. Lens (Editor t_a13u9 n_a13ua) (Editor t_a13uO n_a13ua) (TextZipper t_a13u9) (TextZipper t_a13uO)
- Brick.Widgets.FileBrowser: fileBrowserEntryFilterL :: forall n_a1j8O. Lens' (FileBrowser n_a1j8O) (Maybe (FileInfo -> Bool))
+ Brick.Widgets.FileBrowser: fileBrowserEntryFilterL :: forall n_a1j5p. Lens' (FileBrowser n_a1j5p) (Maybe (FileInfo -> Bool))
- Brick.Widgets.FileBrowser: fileBrowserSelectableL :: forall n_a1j8O. Lens' (FileBrowser n_a1j8O) (FileInfo -> Bool)
+ Brick.Widgets.FileBrowser: fileBrowserSelectableL :: forall n_a1j5p. Lens' (FileBrowser n_a1j5p) (FileInfo -> Bool)
- Brick.Widgets.List: listElementsL :: forall n_a1dYe t_a1dYf e_a1dYg t_a1ecl e_a1ecm. Lens (GenericList n_a1dYe t_a1dYf e_a1dYg) (GenericList n_a1dYe t_a1ecl e_a1ecm) (t_a1dYf e_a1dYg) (t_a1ecl e_a1ecm)
+ Brick.Widgets.List: listElementsL :: forall n_a1dUP t_a1dUQ e_a1dUR t_a1e8W e_a1e8X. Lens (GenericList n_a1dUP t_a1dUQ e_a1dUR) (GenericList n_a1dUP t_a1e8W e_a1e8X) (t_a1dUQ e_a1dUR) (t_a1e8W e_a1e8X)
- Brick.Widgets.List: listItemHeightL :: forall n_a1dYe t_a1dYf e_a1dYg. Lens' (GenericList n_a1dYe t_a1dYf e_a1dYg) Int
+ Brick.Widgets.List: listItemHeightL :: forall n_a1dUP t_a1dUQ e_a1dUR. Lens' (GenericList n_a1dUP t_a1dUQ e_a1dUR) Int
- Brick.Widgets.List: listNameL :: forall n_a1dYe t_a1dYf e_a1dYg n_a1ecn. Lens (GenericList n_a1dYe t_a1dYf e_a1dYg) (GenericList n_a1ecn t_a1dYf e_a1dYg) n_a1dYe n_a1ecn
+ Brick.Widgets.List: listNameL :: forall n_a1dUP t_a1dUQ e_a1dUR n_a1e8Y. Lens (GenericList n_a1dUP t_a1dUQ e_a1dUR) (GenericList n_a1e8Y t_a1dUQ e_a1dUR) n_a1dUP n_a1e8Y
- Brick.Widgets.List: listSelectedL :: forall n_a1dYe t_a1dYf e_a1dYg. Lens' (GenericList n_a1dYe t_a1dYf e_a1dYg) (Maybe Int)
+ Brick.Widgets.List: listSelectedL :: forall n_a1dUP t_a1dUQ e_a1dUR. Lens' (GenericList n_a1dUP t_a1dUQ e_a1dUR) (Maybe Int)
Files
- CHANGELOG.md +8/−0
- README.md +1/−0
- brick.cabal +2/−2
- docs/guide.rst +5/−0
- programs/MouseDemo.hs +2/−2
- src/Brick/BorderMap.hs +2/−2
- src/Brick/Forms.hs +43/−4
- tests/Main.hs +4/−4
CHANGELOG.md view
@@ -2,6 +2,14 @@ Brick changelog --------------- +0.61+----++API changes:+ * Brick.Forms got `editShowableFieldWithValidate`, a generalization+ of `editShowableField` that allows the caller to specify an+ additional validation function (thanks Ben Selfridge)+ 0.60.2 ------
README.md view
@@ -71,6 +71,7 @@ | [`ghcup`](https://www.haskell.org/ghcup/) | A TUI for `ghcup`, the Haskell toolchain manager | | [`cbookview`](https://github.com/mlang/chessIO) | A TUI for exploring polyglot chess opening book files | | [`thock`](https://github.com/rmehri01/thock) | A modern TUI typing game featuring online racing against friends |+| [`fifteen`](https://github.com/benjaminselfridge/fifteen) | An implementation of the [15 puzzle](https://en.wikipedia.org/wiki/15_puzzle) | These third-party packages also extend `brick`:
brick.cabal view
@@ -1,5 +1,5 @@ name: brick-version: 0.60.2+version: 0.61 synopsis: A declarative terminal user interface library description: Write terminal user interfaces (TUIs) painlessly with 'brick'! You@@ -114,7 +114,7 @@ Brick.Types.Internal Brick.Widgets.Internal - build-depends: base <= 4.15,+ build-depends: base < 4.16.0.0, vty >= 5.31, transformers, data-clist >= 0.1,
docs/guide.rst view
@@ -1355,6 +1355,11 @@ later validate that state and convert it back into the approprate type for storage in ``UserInfo``. +The form value itself -- of type ``Form`` -- must be stored in your+application state. You should only ever call ``newForm`` when you need+to initialize a totally new form. Once initialized, the form needs to be+kept around and updated by event handlers in order to work.+ For example, if the initial ``UserInfo`` value's ``_age`` field has the value ``0``, the ``editShowableField`` will call ``show`` on ``0``, convert that to ``Text``, and initialize the editor for ``_age`` with
programs/MouseDemo.hs view
@@ -95,8 +95,8 @@ let T.Location pos = loc M.continue $ st & lastReportedClick .~ Just (n, loc) & edit %~ E.applyEdit (if n == TextBox then moveCursor (swap pos) else id)-appEvent st (T.MouseUp _ _ _) = M.continue $ st & lastReportedClick .~ Nothing-appEvent st (T.VtyEvent (V.EvMouseUp _ _ _)) = M.continue $ st & lastReportedClick .~ Nothing+appEvent st (T.MouseUp {}) = M.continue $ st & lastReportedClick .~ Nothing+appEvent st (T.VtyEvent (V.EvMouseUp {})) = M.continue $ st & lastReportedClick .~ Nothing appEvent st (T.VtyEvent (V.EvKey V.KUp [V.MCtrl])) = M.vScrollBy (M.viewportScroll Prose) (-1) >> M.continue st appEvent st (T.VtyEvent (V.EvKey V.KDown [V.MCtrl])) = M.vScrollBy (M.viewportScroll Prose) 1 >> M.continue st appEvent st (T.VtyEvent (V.EvKey V.KEsc [])) = M.halt st
src/Brick/BorderMap.hs view
@@ -165,8 +165,8 @@ } where bounds' = neighbors coordinates'- values' = pure gc- <*> _coordinates m+ values' = gc+ <$> _coordinates m <*> coordinates' <*> bounds' <*> _values m
src/Brick/Forms.hs view
@@ -3,9 +3,9 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE CPP #-} {-# LANGUAGE ScopedTypeVariables #-}--- | NOTE: This API is experimental and will probably change. Please try--- it out! Feedback is very much appreciated, and your patience in the--- face of breaking API changes is also appreciated! It's also worth+-- | Note - This API is experimental and will probably change. Please+-- try it out! Feedback is very much appreciated, and your patience in+-- the face of breaking API changes is also appreciated! It's also worth -- bearing in mind that this API is designed to support a narrow range -- of use cases. If you find that you need more customization than this -- offers, then you will need to consider building your own layout and@@ -32,6 +32,10 @@ -- 'FormField's combined for a single 'FormFieldState' (e.g. a radio -- button sequence). --+-- To use a 'Form', you must include it within your application state+-- type. You can use 'formState' to access the underlying s whenever you+-- need it. See @programs/FormDemo.hs@ for a complete working example.+-- -- Also note that, by default, forms and their field inputs are -- concatenated together in a 'vBox'. This can be customized on a -- per-field basis and for the entire form by using the functions@@ -65,6 +69,7 @@ -- * Simple form field constructors , editTextField , editShowableField+ , editShowableFieldWithValidate , editPasswordField , radioField , checkboxField@@ -83,6 +88,7 @@ where import Graphics.Vty hiding (showCursor)+import Control.Monad ((<=<)) #if !(MIN_VERSION_base(4,11,0)) import Data.Monoid #endif@@ -188,7 +194,8 @@ } -> FormFieldState s e n -- | A form: a sequence of input fields that manipulate the fields of an--- underlying state that you choose.+-- underlying state that you choose. This value must be stored in the+-- Brick application's state. -- -- Type variables are as follows: --@@ -557,6 +564,38 @@ editShowableField stLens n = let ini = T.pack . show val = readMaybe . T.unpack . T.intercalate "\n"+ limit = Just 1+ renderText = txt . T.unlines+ in editField stLens n limit ini val renderText id++-- | A form field using a single-line editor to edit the 'Show' representation+-- of a state field value of type @a@. This automatically uses its 'Read'+-- instance to validate the input, and also accepts an additional user-defined+-- pass for validation. This field is mostly useful in cases where the+-- user-facing representation of a value matches the 'Show' representation+-- exactly, such as with 'Int', but you don't want to accept just /any/ 'Int'.+--+-- This field responds to all events handled by 'editor', including+-- mouse events.+editShowableFieldWithValidate :: (Ord n, Show n, Read a, Show a)+ => Lens' s a+ -- ^ The state lens for this value.+ -> n+ -- ^ The resource name for the input field.+ -> (a -> Bool)+ -- ^ Additional validation step for input.+ -- 'True' indicates that the value is+ -- valid.+ -> s+ -- ^ The initial form state.+ -> FormFieldState s e n+editShowableFieldWithValidate stLens n isValid =+ let ini = T.pack . show+ val ls = do+ val <- readMaybe $ T.unpack $ T.intercalate "\n" ls+ if isValid val+ then return val+ else Nothing limit = Just 1 renderText = txt . T.unlines in editField stLens n limit ini val renderText id
tests/Main.hs view
@@ -60,16 +60,16 @@ prop_compare l r = compare l r == compare (lower l) (lower r) prop_applicativeIdentity :: I -> Bool-prop_applicativeIdentity v = (pure id <*> v) == v+prop_applicativeIdentity v = (id <$> v) == v prop_applicativeComposition :: IMap (O -> O) -> IMap (O -> O) -> IMap O -> Bool-prop_applicativeComposition u v w = (pure (.) <*> u <*> v <*> w) == (u <*> (v <*> w))+prop_applicativeComposition u v w = ((.) <$> u <*> v <*> w) == (u <*> (v <*> w)) prop_applicativeHomomorphism :: (O -> O) -> O -> Bool-prop_applicativeHomomorphism f x = (pure f <*> pure x :: I) == pure (f x)+prop_applicativeHomomorphism f x = (f <$> pure x :: I) == pure (f x) prop_applicativeInterchange :: IMap (O -> O) -> O -> Bool-prop_applicativeInterchange u y = (u <*> pure y) == (pure ($ y) <*> u)+prop_applicativeInterchange u y = (u <*> pure y) == (($ y) <$> u) prop_empty :: Bool prop_empty = lower (IMap.empty :: I) == IntMap.empty