brick 0.57.1 → 0.58
raw patch · 7 files changed
+147/−48 lines, 7 filesdep ~basePVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
+ Brick.Widgets.FileBrowser: actionFileBrowserBeginSearch :: FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListBottom :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListHalfPageDown :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListHalfPageUp :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListNext :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListPageDown :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListPageUp :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListPrev :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserListTop :: Ord n => FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserSelectCurrent :: FileBrowser n -> EventM n (FileBrowser n)
+ Brick.Widgets.FileBrowser: actionFileBrowserSelectEnter :: FileBrowser n -> EventM n (FileBrowser n)
- Brick.BorderMap: eBottomL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.BorderMap: eBottomL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.BorderMap: eLeftL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.BorderMap: eLeftL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.BorderMap: eRightL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.BorderMap: eRightL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.BorderMap: eTopL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.BorderMap: eTopL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.Types: bordersL :: forall n_axYn. Lens' (Result n_axYn) (BorderMap DynBorder)
+ Brick.Types: bordersL :: forall n_axYr. Lens' (Result n_axYr) (BorderMap DynBorder)
- Brick.Types: cursorLocationL :: forall n_awJM. Lens' (CursorLocation n_awJM) Location
+ Brick.Types: cursorLocationL :: forall n_awJQ. Lens' (CursorLocation n_awJQ) Location
- Brick.Types: cursorLocationNameL :: forall n_awJM n_ayBL. Lens (CursorLocation n_awJM) (CursorLocation n_ayBL) (Maybe n_awJM) (Maybe n_ayBL)
+ Brick.Types: cursorLocationNameL :: forall n_awJQ n_ayBP. Lens (CursorLocation n_awJQ) (CursorLocation n_ayBP) (Maybe n_awJQ) (Maybe n_ayBP)
- Brick.Types: cursorsL :: forall n_axYn. Lens' (Result n_axYn) [CursorLocation n_axYn]
+ Brick.Types: cursorsL :: forall n_axYr. Lens' (Result n_axYr) [CursorLocation n_axYr]
- Brick.Types: eBottomL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.Types: eBottomL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.Types: eLeftL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.Types: eLeftL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.Types: eRightL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.Types: eRightL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.Types: eTopL :: forall a_acT2. Lens' (Edges a_acT2) a_acT2
+ Brick.Types: eTopL :: forall a_acT6. Lens' (Edges a_acT6) a_acT6
- Brick.Types: extentsL :: forall n_axYn. Lens' (Result n_axYn) [Extent n_axYn]
+ Brick.Types: extentsL :: forall n_axYr. Lens' (Result n_axYr) [Extent n_axYr]
- Brick.Types: imageL :: forall n_axYn. Lens' (Result n_axYn) Image
+ Brick.Types: imageL :: forall n_axYr. Lens' (Result n_axYr) Image
- Brick.Types: visibilityRequestsL :: forall n_axYn. Lens' (Result n_axYn) [VisibilityRequest]
+ Brick.Types: visibilityRequestsL :: forall n_axYr. Lens' (Result n_axYr) [VisibilityRequest]
- Brick.Widgets.Dialog: dialogButtonsL :: forall a_a18wU a_a18xy. Lens (Dialog a_a18wU) (Dialog a_a18xy) [(String, a_a18wU)] [(String, a_a18xy)]
+ Brick.Widgets.Dialog: dialogButtonsL :: forall a_a18wY a_a18xC. Lens (Dialog a_a18wY) (Dialog a_a18xC) [(String, a_a18wY)] [(String, a_a18xC)]
- Brick.Widgets.Dialog: dialogSelectedIndexL :: forall a_a18wU. Lens' (Dialog a_a18wU) (Maybe Int)
+ Brick.Widgets.Dialog: dialogSelectedIndexL :: forall a_a18wY. Lens' (Dialog a_a18wY) (Maybe Int)
- Brick.Widgets.Dialog: dialogTitleL :: forall a_a18wU. Lens' (Dialog a_a18wU) (Maybe String)
+ Brick.Widgets.Dialog: dialogTitleL :: forall a_a18wY. Lens' (Dialog a_a18wY) (Maybe String)
- Brick.Widgets.Dialog: dialogWidthL :: forall a_a18wU. Lens' (Dialog a_a18wU) Int
+ Brick.Widgets.Dialog: dialogWidthL :: forall a_a18wY. Lens' (Dialog a_a18wY) Int
- Brick.Widgets.Edit: editContentsL :: forall t_a13sp n_a13sq t_a13t4. Lens (Editor t_a13sp n_a13sq) (Editor t_a13t4 n_a13sq) (TextZipper t_a13sp) (TextZipper t_a13t4)
+ Brick.Widgets.Edit: editContentsL :: forall t_a13st n_a13su t_a13t8. Lens (Editor t_a13st n_a13su) (Editor t_a13t8 n_a13su) (TextZipper t_a13st) (TextZipper t_a13t8)
- Brick.Widgets.FileBrowser: fileBrowserEntryFilterL :: forall n_a1iBu. Lens' (FileBrowser n_a1iBu) (Maybe (FileInfo -> Bool))
+ Brick.Widgets.FileBrowser: fileBrowserEntryFilterL :: forall n_a1iFp. Lens' (FileBrowser n_a1iFp) (Maybe (FileInfo -> Bool))
- Brick.Widgets.FileBrowser: fileBrowserSelectableL :: forall n_a1iBu. Lens' (FileBrowser n_a1iBu) (FileInfo -> Bool)
+ Brick.Widgets.FileBrowser: fileBrowserSelectableL :: forall n_a1iFp. Lens' (FileBrowser n_a1iFp) (FileInfo -> Bool)
- Brick.Widgets.List: listElementsL :: forall n_a1duY t_a1duZ e_a1dv0 t_a1dJC e_a1dJD. Lens (GenericList n_a1duY t_a1duZ e_a1dv0) (GenericList n_a1duY t_a1dJC e_a1dJD) (t_a1duZ e_a1dv0) (t_a1dJC e_a1dJD)
+ Brick.Widgets.List: listElementsL :: forall n_a1dv2 t_a1dv3 e_a1dv4 t_a1dJG e_a1dJH. Lens (GenericList n_a1dv2 t_a1dv3 e_a1dv4) (GenericList n_a1dv2 t_a1dJG e_a1dJH) (t_a1dv3 e_a1dv4) (t_a1dJG e_a1dJH)
- Brick.Widgets.List: listItemHeightL :: forall n_a1duY t_a1duZ e_a1dv0. Lens' (GenericList n_a1duY t_a1duZ e_a1dv0) Int
+ Brick.Widgets.List: listItemHeightL :: forall n_a1dv2 t_a1dv3 e_a1dv4. Lens' (GenericList n_a1dv2 t_a1dv3 e_a1dv4) Int
- Brick.Widgets.List: listNameL :: forall n_a1duY t_a1duZ e_a1dv0 n_a1dJE. Lens (GenericList n_a1duY t_a1duZ e_a1dv0) (GenericList n_a1dJE t_a1duZ e_a1dv0) n_a1duY n_a1dJE
+ Brick.Widgets.List: listNameL :: forall n_a1dv2 t_a1dv3 e_a1dv4 n_a1dJI. Lens (GenericList n_a1dv2 t_a1dv3 e_a1dv4) (GenericList n_a1dJI t_a1dv3 e_a1dv4) n_a1dv2 n_a1dJI
- Brick.Widgets.List: listSelectedL :: forall n_a1duY t_a1duZ e_a1dv0. Lens' (GenericList n_a1duY t_a1duZ e_a1dv0) (Maybe Int)
+ Brick.Widgets.List: listSelectedL :: forall n_a1dv2 t_a1dv3 e_a1dv4. Lens' (GenericList n_a1dv2 t_a1dv3 e_a1dv4) (Maybe Int)
Files
- CHANGELOG.md +24/−0
- README.md +1/−0
- brick.cabal +2/−2
- docs/guide.rst +1/−1
- src/Brick/Widgets/Core.hs +6/−1
- src/Brick/Widgets/FileBrowser.hs +102/−37
- src/Brick/Widgets/List.hs +11/−7
CHANGELOG.md view
@@ -2,6 +2,30 @@ Brick changelog --------------- +0.58+----++Package changes:+ * Updated dependency constraints to build on GHC 9.0.1 (thanks Ondřej+ Súkup)++API changes:+ * The FileBrowser module now exports individual functions for+ each of the events that it handles. This allows end users to+ trigger the behaviors directly rather than relying on the built-in+ `handleFileBrowserEvent` function. The documentation has been updated+ to indicate which functions are triggered by each key event. (Thanks+ David B. Lamkins)++Other changes:+ * The `List` module's `listFindBy` function now attempts to find a+ match anywhere in the list rather than just somewhere between the+ cursor and the end of the list.+ * The `FileBrowser` now positions a cursor at the beginning of the+ selected entry when the file browser is focused. (thanks Mario Lang)+ * The user guide's viewport visibility example got an important+ syntactic fix. (thanks Mario Lang)+ 0.57.1 ------
README.md view
@@ -67,6 +67,7 @@ | [`wrapping-editor`](https://github.com/ta0kira/wrapping-editor) | An embeddable editor with support for Brick | | [`git-brunch`](https://github.com/andys8/git-brunch) | A git branch checkout utility | | [`hascard`](https://github.com/Yvee1/hascard) | A program for reviewing "flash card" notes |+| [`ttyme`](https://github.com/evuez/ttyme) | A TUI for [Harvest](https://www.getharvest.com/) | These third-party packages also extend `brick`:
brick.cabal view
@@ -1,5 +1,5 @@ name: brick-version: 0.57.1+version: 0.58 synopsis: A declarative terminal user interface library description: Write terminal user interfaces (TUIs) painlessly with 'brick'! You@@ -113,7 +113,7 @@ Brick.Types.Internal Brick.Widgets.Internal - build-depends: base <= 4.14.1.0,+ build-depends: base <= 4.15, vty >= 5.31, transformers, data-clist >= 0.1,
docs/guide.rst view
@@ -1205,7 +1205,7 @@ -- Assuming that App uses 'Name' for its resource names: data Name = Viewport1 let w = viewport Viewport1 Horizontal $- (visible $ str "Hello," <+> (str " world!")+ (visible $ str "Hello,") <+> (str " world!") This example requests that the ``Viewport1`` viewport be scrolled so that "Hello," is visible. We could extend this example with a value
src/Brick/Widgets/Core.hs view
@@ -862,7 +862,12 @@ -- | When rendering the specified widget, force all attribute lookups -- in the attribute map to use the value currently assigned to the--- specified attribute name.+-- specified attribute name. This means that the attribute lookups will+-- behave as if they all used the name specified here. That further+-- means that the resolved attribute will still inherit from its parent+-- entry in the attribute map as would normally be the case. If you+-- want to have more control over the resulting attribute, consider+-- 'modifyDefAttr'. forceAttr :: AttrName -> Widget n -> Widget n forceAttr an p = Widget (hSize p) (vSize p) $ do
src/Brick/Widgets/FileBrowser.hs view
@@ -65,6 +65,19 @@ , updateFileBrowserSearch , setFileBrowserEntryFilter + -- * Actions+ , actionFileBrowserBeginSearch+ , actionFileBrowserSelectEnter+ , actionFileBrowserSelectCurrent+ , actionFileBrowserListPageUp+ , actionFileBrowserListPageDown+ , actionFileBrowserListHalfPageUp+ , actionFileBrowserListHalfPageDown+ , actionFileBrowserListTop+ , actionFileBrowserListBottom+ , actionFileBrowserListNext+ , actionFileBrowserListPrev+ -- * Handling events , handleFileBrowserEvent , maybeSelectCurrentEntry@@ -540,21 +553,81 @@ -- -- Events handled regardless of mode: ----- * @Enter@, @Space@: set the file browser's selected entry--- ('fileBrowserSelection') for use by the calling application,--- subject to 'fileBrowserSelectable'.--- * @Ctrl-n@: select the next entry--- * @Ctrl-p@: select the previous entry--- * 'List' navigation keys+-- * @Ctrl-b@: 'actionFileBrowserListPageUp'+-- * @Ctrl-f@: 'actionFileBrowserListPageDown'+-- * @Ctrl-d@: 'actionFileBrowserListHalfPageDown'+-- * @Ctrl-u@: 'actionFileBrowserListHalfPageUp'+-- * @g@: 'actionFileBrowserListTop'+-- * @G@: 'actionFileBrowserListBottom'+-- * @j@: 'actionFileBrowserListNext'+-- * @k@: 'actionFileBrowserListPrev'+-- * @Ctrl-n@: 'actionFileBrowserListNext'+-- * @Ctrl-p@: 'actionFileBrowserListPrev' -- -- Events handled only in normal mode: ----- * @/@: enter search mode+-- * @/@: 'actionFileBrowserBeginSearch'+-- * @Enter@: 'actionFileBrowserSelectEnter'+-- * @Space@: 'actionFileBrowserSelectCurrent' -- -- Events handled only in search mode: -- -- * @Esc@, @Ctrl-C@: cancel search mode -- * Text input: update search string++actionFileBrowserBeginSearch :: FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserBeginSearch b =+ return $ updateFileBrowserSearch (const $ Just "") b++actionFileBrowserSelectEnter :: FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserSelectEnter b =+ maybeSelectCurrentEntry b++actionFileBrowserSelectCurrent :: FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserSelectCurrent b =+ selectCurrentEntry b++actionFileBrowserListPageUp :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListPageUp b = do+ let old = b ^. fileBrowserEntriesL+ new <- listMovePageUp old+ return $ b & fileBrowserEntriesL .~ new++actionFileBrowserListPageDown :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListPageDown b = do+ let old = b ^. fileBrowserEntriesL+ new <- listMovePageDown old+ return $ b & fileBrowserEntriesL .~ new++actionFileBrowserListHalfPageUp :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListHalfPageUp b = do+ let old = b ^. fileBrowserEntriesL+ new <- listMoveByPages (-0.5::Double) old+ return $ b & fileBrowserEntriesL .~ new++actionFileBrowserListHalfPageDown :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListHalfPageDown b = do+ let old = b ^. fileBrowserEntriesL+ new <- listMoveByPages (0.5::Double) old+ return $ b & fileBrowserEntriesL .~ new++actionFileBrowserListTop :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListTop b =+ return $ b & fileBrowserEntriesL %~ listMoveTo 0++actionFileBrowserListBottom :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListBottom b = do+ let sz = length (listElements $ b^.fileBrowserEntriesL)+ return $ b & fileBrowserEntriesL %~ listMoveTo (sz - 1)++actionFileBrowserListNext :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListNext b =+ return $ b & fileBrowserEntriesL %~ listMoveBy 1++actionFileBrowserListPrev :: Ord n => FileBrowser n -> EventM n (FileBrowser n)+actionFileBrowserListPrev b =+ return $ b & fileBrowserEntriesL %~ listMoveBy (-1)+ handleFileBrowserEvent :: (Ord n) => Vty.Event -> FileBrowser n -> EventM n (FileBrowser n) handleFileBrowserEvent e b = if fileBrowserIsSearching b@@ -587,48 +660,39 @@ case e of Vty.EvKey (Vty.KChar '/') [] -> -- Begin file search- return $ updateFileBrowserSearch (const $ Just "") b+ actionFileBrowserBeginSearch b Vty.EvKey Vty.KEnter [] -> -- Select file or enter directory- maybeSelectCurrentEntry b+ actionFileBrowserSelectEnter b Vty.EvKey (Vty.KChar ' ') [] -> -- Select entry- selectCurrentEntry b+ actionFileBrowserSelectCurrent b _ -> handleFileBrowserEventCommon e b handleFileBrowserEventCommon :: (Ord n) => Vty.Event -> FileBrowser n -> EventM n (FileBrowser n) handleFileBrowserEventCommon e b = case e of- Vty.EvKey (Vty.KChar 'b') [Vty.MCtrl] -> do- let old = b ^. fileBrowserEntriesL- new <- listMovePageUp old- return $ b & fileBrowserEntriesL .~ new- Vty.EvKey (Vty.KChar 'f') [Vty.MCtrl] -> do- let old = b ^. fileBrowserEntriesL- new <- listMovePageDown old- return $ b & fileBrowserEntriesL .~ new- Vty.EvKey (Vty.KChar 'd') [Vty.MCtrl] -> do- let old = b ^. fileBrowserEntriesL- new <- listMoveByPages (0.5::Double) old- return $ b & fileBrowserEntriesL .~ new- Vty.EvKey (Vty.KChar 'u') [Vty.MCtrl] -> do- let old = b ^. fileBrowserEntriesL- new <- listMoveByPages (-0.5::Double) old- return $ b & fileBrowserEntriesL .~ new+ Vty.EvKey (Vty.KChar 'b') [Vty.MCtrl] ->+ actionFileBrowserListPageUp b+ Vty.EvKey (Vty.KChar 'f') [Vty.MCtrl] ->+ actionFileBrowserListPageDown b+ Vty.EvKey (Vty.KChar 'd') [Vty.MCtrl] ->+ actionFileBrowserListHalfPageDown b+ Vty.EvKey (Vty.KChar 'u') [Vty.MCtrl] ->+ actionFileBrowserListHalfPageUp b Vty.EvKey (Vty.KChar 'g') [] ->- return $ b & fileBrowserEntriesL %~ listMoveTo 0- Vty.EvKey (Vty.KChar 'G') [] -> do- let sz = length (listElements $ b^.fileBrowserEntriesL)- return $ b & fileBrowserEntriesL %~ listMoveTo (sz - 1)+ actionFileBrowserListTop b+ Vty.EvKey (Vty.KChar 'G') [] ->+ actionFileBrowserListBottom b Vty.EvKey (Vty.KChar 'j') [] ->- return $ b & fileBrowserEntriesL %~ listMoveBy 1+ actionFileBrowserListNext b Vty.EvKey (Vty.KChar 'k') [] ->- return $ b & fileBrowserEntriesL %~ listMoveBy (-1)+ actionFileBrowserListPrev b Vty.EvKey (Vty.KChar 'n') [Vty.MCtrl] ->- return $ b & fileBrowserEntriesL %~ listMoveBy 1+ actionFileBrowserListNext b Vty.EvKey (Vty.KChar 'p') [Vty.MCtrl] ->- return $ b & fileBrowserEntriesL %~ listMoveBy (-1)+ actionFileBrowserListPrev b _ -> handleEventLensed b fileBrowserEntriesL handleListEvent e @@ -715,14 +779,14 @@ in withDefAttr fileBrowserAttr $ vBox [ withDefAttr fileBrowserCurrentDirectoryAttr cwdHeader- , renderList (renderFileInfo foc maxFilenameLength (b^.fileBrowserSelectedFilesL))+ , renderList (renderFileInfo foc maxFilenameLength (b^.fileBrowserSelectedFilesL) (b^.fileBrowserNameL)) foc (b^.fileBrowserEntriesL) , maybeSearchInfo , withDefAttr fileBrowserSelectionInfoAttr selInfo ] -renderFileInfo :: Bool -> Int -> Set.Set String -> Bool -> FileInfo -> Widget n-renderFileInfo foc maxLen selFiles listSel info =+renderFileInfo :: Bool -> Int -> Set.Set String -> n -> Bool -> FileInfo -> Widget n+renderFileInfo foc maxLen selFiles n listSel info = (if foc then (if listSel then forceAttr listSelectedFocusedAttr else if sel then forceAttr fileBrowserSelectedAttr else id)@@ -734,6 +798,7 @@ addAttr = maybe id (withDefAttr . attrForFileType) (fileInfoFileType info) body = addAttr (hLimit (maxLen + 1) $ padRight Max $+ (if foc && listSel then showCursor n (Location (0,0)) else id) $ str $ fileInfoSanitizedFilename info <> suffix) suffix = (if fileInfoFileType info == Just Directory then "/" else "") <> (if sel then "*" else "")
src/Brick/Widgets/List.hs view
@@ -75,6 +75,7 @@ import Prelude hiding (reverse, splitAt) +import Control.Applicative ((<|>)) #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>), (<*>), pure) import Data.Foldable (Foldable, find, toList)@@ -574,10 +575,11 @@ -> GenericList n t e listMoveToElement e = listFindBy (== e) . set listSelectedL Nothing --- | Set the selected index to the next element matching the--- predicate. If there is no selected element, the search starts at--- the beginning. If no matching element is found, leave the list--- unmodified.+-- | Starting from the currently-selected position, attempt to find+-- and select the next element matching the predicate. If there are no+-- matches for the remainder of the list or if the list has no selection+-- at all, the search starts at the beginning. If no matching element is+-- found anywhere in the list, leave the list unmodified. -- -- /O(n)/. Only evaluates as much of the container as needed. listFindBy :: (Foldable t, Splittable t)@@ -586,9 +588,11 @@ -> GenericList n t e listFindBy test l = let start = maybe 0 (+1) (l ^. listSelectedL)- (_, t) = splitAt start (l ^. listElementsL)- result = find (test . snd) . zip [0..] . toList $ t- in maybe id (set listSelectedL . Just . (start +) . fst) result l+ (h, t) = splitAt start (l ^. listElementsL)+ tailResult = find (test . snd) . zip [start..] . toList $ t+ headResult = find (test . snd) . zip [0..] . toList $ h+ result = tailResult <|> headResult+ in maybe id (set listSelectedL . Just . fst) result l -- | Return a list's selected element, if any. --