packages feed

brick 2.12 → 2.13

raw patch · 6 files changed

+88/−19 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Brick.Widgets.List: getScrollWrap :: forall n (t :: Type -> Type) e. GenericList n t e -> Bool
+ Brick.Widgets.List: listScrollWrapL :: forall n (t :: Type -> Type) e f. Functor f => (Bool -> f Bool) -> GenericList n t e -> f (GenericList n t e)
+ Brick.Widgets.List: setScrollWrap :: forall (t :: Type -> Type) e n. (Traversable t, Splittable t, Semigroup (t e)) => Bool -> GenericList n t e -> GenericList n t e

Files

CHANGELOG.md view
@@ -2,6 +2,18 @@ Brick changelog --------------- +2.13+----++New features:++* Brick.Widgets.List: added support for wrapping (thanks Enrico Maria De+  Angelis). The List API now provides `setScrollWrap` to configure lists+  to wrap when moving their cursor, and the cursor-movement functions+  and event handlers now cause selection wrapping when a list has+  wrapping enabled. The `ListDemo` demo program was also updated to+  demonstrate the wrapping behavior.+ 2.12 ---- 
README.md view
@@ -215,7 +215,7 @@ should consider to make submitting patches easier for all concerned:   - Patches written completely or partially by AI are unlikely to be-   accepted.+   accepted. Please disclose any AI use.  - If you want to take on big things, talk to me first; let's have a    design/vision discussion before you start coding. Create a GitHub    issue and we can use that as the place to hash things out.
brick.cabal view
@@ -1,5 +1,5 @@ name:                brick-version:             2.12+version:             2.13 synopsis:            A declarative terminal user interface library description:   Write terminal user interfaces (TUIs) painlessly with 'brick'! You
programs/ListDemo.hs view
@@ -43,10 +43,16 @@               hLimit 25 $               vLimit 15 $               L.renderList listDrawElement True l+        wrapStatus = if L.getScrollWrap l+                     then "enabled"+                     else "disabled"         ui = C.vCenter $ vBox [ C.hCenter box                               , str " "                               , C.hCenter $ str "Press +/- to add/remove list elements."                               , C.hCenter $ str "Press Esc to exit."+                              , str " "+                              , C.hCenter $ str "Press 'w' to toggle selection wrapping."+                              , C.hCenter $ str $ "Selection wrapping is currently " <> wrapStatus <> "."                               ]  appEvent :: T.BrickEvent () e -> T.EventM () (L.List () Char) ()@@ -64,6 +70,9 @@                 Nothing -> return ()                 Just i -> modify $ L.listRemove i +        V.EvKey (V.KChar 'w') [] ->+            toggleListWrapping+         V.EvKey V.KEsc [] -> M.halt          ev -> L.handleListEvent ev@@ -71,6 +80,9 @@       nextElement :: Vec.Vector Char -> Char       nextElement v = fromMaybe '?' $ Vec.find (flip Vec.notElem v) (Vec.fromList ['a' .. 'z']) appEvent _ = return ()++toggleListWrapping :: T.EventM () (L.List () Char) ()+toggleListWrapping = L.listScrollWrapL %= not  listDrawElement :: (Show a) => Bool -> a -> Widget () listDrawElement sel a =
src/Brick/Widgets/List.hs view
@@ -22,6 +22,11 @@   -- * Constructing a list   , list +  -- * Configuring wrapping+  , setScrollWrap+  , getScrollWrap+  , listScrollWrapL+   -- * Rendering a list   , renderList   , renderListWithIndex@@ -103,8 +108,8 @@ import Brick.AttrMap  -- | List state. Lists have a container @t@ of element type @e@ that is--- the data stored by the list. Internally, Lists handle the following--- events by default:+-- the data stored by the list. When using the event-handling functions+-- provided by this module, Lists handle the following events: -- -- * Up/down arrow keys: move cursor of selected item -- * Page up / page down keys: move cursor of selected item by one page@@ -112,6 +117,15 @@ -- * Home/end keys: move cursor of selected item to beginning or end of --   list --+-- Movement key behaviors (and their corresponding list transformation+-- functions) are subject to wrapping if the list's wrapping is enabled;+-- in that case, attempts to move the selection beyond either end of the+-- list will wrap the selection to the opposite end of the list. When+-- wrapping is disabled, attempts to move beyond either end of the list+-- will move the selection as far as possible without wrapping around+-- to the opposite end. To control whether wrapping is enabled, see+-- 'setScrollWrap'.+-- -- The 'List' type synonym fixes @t@ to 'V.Vector' for compatibility -- with previous versions of this library. --@@ -123,7 +137,6 @@ -- * 'listRemove': 'Semigroup' -- * 'listClear': 'Monoid' -- * 'listReverse': 'Reversible'--- data GenericList n t e =     List { listElements :: !(t e)          -- ^ The list's sequence of elements.@@ -133,6 +146,9 @@          -- ^ The list's name.          , listItemHeight :: Int          -- ^ The height of an individual item in the list.+         , listScrollWrap :: Bool+         -- ^ Whether moving beyond a list's first/last element+         -- should wrap to the last/first element.          } deriving (Functor, Foldable, Traversable, Show, Generic)  suffixLenses ''GenericList@@ -263,7 +279,8 @@ listSelectedFocusedAttr :: AttrName listSelectedFocusedAttr = listSelectedAttr <> attrName "focused" --- | Construct a list in terms of container 't' with element type 'e'.+-- | Construct a list, with wrapping initially disabled, in terms of+-- container 't' with element type 'e'. list :: (Foldable t)      => n      -- ^ The list name (must be unique)@@ -276,7 +293,7 @@ list name es h =     let selIndex = if null es then Nothing else Just 0         safeHeight = max 1 h-    in List es selIndex name safeHeight+    in List es selIndex name safeHeight False  -- | Render a list using the specified item drawing function. --@@ -465,8 +482,8 @@             | otherwise = 0     in l' & listSelectedL .~ newSel --- | Move the list selected index up by one. (Moves the cursor up,--- subtracts one from the index.)+-- | Move the list selected index up by one (moves the cursor up,+-- subtracts one from the index), subject to wrapping. listMoveUp :: (Foldable t, Splittable t)            => GenericList n t e            -> GenericList n t e@@ -477,8 +494,8 @@                => EventM n (GenericList n t e) () listMovePageUp = listMoveByPages (-1::Double) --- | Move the list selected index down by one. (Moves the cursor down,--- adds one to the index.)+-- | Move the list selected index down by one (moves the cursor down,+-- adds one to the index), subject to wrapping. listMoveDown :: (Foldable t, Splittable t)              => GenericList n t e              -> GenericList n t e@@ -489,7 +506,8 @@                  => EventM n (GenericList n t e) () listMovePageDown = listMoveByPages (1::Double) --- | Move the list selected index by some (fractional) number of pages.+-- | Move the list selected index by some (fractional) number of pages,+-- subject to wrapping. listMoveByPages :: (Foldable t, Splittable t, Ord n, RealFrac m)                 => m                 -> EventM n (GenericList n t e) ()@@ -506,8 +524,9 @@ -- | Move the list selected index. -- -- If the current selection is @Just x@, the selection is adjusted by--- the specified amount. The value is clamped to the extents of the list--- (i.e. the selection does not "wrap").+-- the specified amount. Whether the value is clamped to the extents of the+-- list or not (i.e. whether the selection doesn't wrap around the list or it+-- does), is determined by the list itself (see 'GenericList' for more info). -- -- If the current selection is @Nothing@ (i.e. there is no selection) -- and the direction is positive, set to @Just 0@ (first element),@@ -528,7 +547,10 @@             Nothing                 | amt > 0 -> 0                 | otherwise -> length l - 1-            Just i -> max 0 (amt + i)  -- don't be negative+            Just i+                | let wrap = l ^. listScrollWrapL+                , wrap -> (amt + i) `mod` length l+                | otherwise -> max 0 (amt + i)  -- don't be negative     in listMoveTo target l  -- | Set the selected index for a list to the specified index, subject@@ -623,7 +645,6 @@ --                                O(n) -- set, modify, traverse -- listSelectedElementL for 'Seq.Seq': O(log(min(i, n - i)))  -- all operations -- @--- listSelectedElementL :: (Splittable t, Traversable t, Semigroup (t e))                      => Traversal' (GenericList n t e) e listSelectedElementL f l =@@ -674,8 +695,8 @@     l & listElementsL %~ reverse       & listSelectedL %~ fmap (length l - 1 -) --- | Apply a function to the selected element. If no element is selected--- the list is not modified.+-- | Apply a function to the selected element. If no element is+-- selected, the list is not modified. -- -- Complexity: same as 'traverse' for the container type (typically -- /O(n)/).@@ -686,9 +707,19 @@ -- listModify for 'List': O(n) -- listModify for 'Seq.Seq': O(log(min(i, n - i))) -- @--- listModify :: (Traversable t, Splittable t, Semigroup (t e))            => (e -> e)            -> GenericList n t e            -> GenericList n t e listModify f = listSelectedElementL %~ f++-- | Sets the list's wrapping behavior; wrapping is enabled if given+-- @True@, or disabled if given @False@.+setScrollWrap :: (Traversable t, Splittable t, Semigroup (t e))+              => Bool -> GenericList n t e -> GenericList n t e+setScrollWrap b = listScrollWrapL .~ b++-- | Returns the list's wrapping setting; returns @True@ if wrapping is+-- enabled or @False@ otherwise.+getScrollWrap :: GenericList n t e -> Bool+getScrollWrap = listScrollWrap
tests/List.hs view
@@ -220,6 +220,20 @@         len = length l''     in maybe (len == 0) (== 0) (l'' ^. listSelectedL) +-- listMoveUp from beginning is the same as listMoveToEnd+prop_moveBeforeFirst :: Eq a => List n a -> Bool+prop_moveBeforeFirst l =+    let l' = setScrollWrap True l+    in listMoveUp (listMoveToBeginning l') =.= listMoveToEnd l'+  where (=.=) = (==) `on` (^. listSelectedL)++-- listMoveDown from end is the same as listMoveToBeginning+prop_moveAfterLast :: Eq a => List n a -> Bool+prop_moveAfterLast l =+    let l' = setScrollWrap True l+    in listMoveDown (listMoveToEnd l') =.= listMoveToBeginning l'+  where (=.=) = (==) `on` (^. listSelectedL)+ -- listMoveDown always reaches end of list (or list is empty) prop_moveDown :: (Eq a) => [ListOp a] -> List n a -> Bool prop_moveDown ops l =