Merge pull request #382 from frasertweedale/feature/selected-element-traversal

add listSelectedElementL Traversal
This commit is contained in:
Jonathan Daugherty 2022-07-28 09:27:55 -07:00 committed by GitHub
commit 1d8e0832d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 2 deletions

View File

@ -37,6 +37,7 @@ module Brick.Widgets.List
, listSelectedL
, listNameL
, listItemHeightL
, listSelectedElementL
-- * Accessors
, listElements
@ -81,7 +82,7 @@ import Control.Applicative ((<|>))
import Data.Foldable (find, toList)
import Control.Monad.Trans.State (evalState, get, put)
import Lens.Micro ((^.), (^?), (&), (.~), (%~), _2, _head, set)
import Lens.Micro (Traversal', (^.), (^?), (&), (.~), (%~), _2, _head, set)
import Data.Functor (($>))
import Data.List.NonEmpty (NonEmpty((:|)))
import Data.Maybe (fromMaybe)
@ -602,6 +603,31 @@ listFindBy test l =
result = tailResult <|> headResult
in maybe id (set listSelectedL . Just . fst) result l
-- | Traversal that targets the selected element, if any.
--
-- Complexity: depends on usage as well as container type
--
-- @
-- listSelectedElementL for 'List': O(1) -- preview, fold
-- 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 =
case l ^. listSelectedL of
Nothing -> pure l
Just i -> listElementsL go l
where
go l' =
let
(left, rest) = splitAt i l'
-- middle contains the target element (if any)
(middle, right) = splitAt 1 rest
in fmap (\m -> left <> m <> right) (traverse f middle)
-- | Return a list's selected element, if any.
--
-- Only evaluates as much of the container as needed.

View File

@ -356,7 +356,7 @@ prop_reverseAppend_Seq l1 l2 =
-- whole container to be evaluated.
--
newtype L a = L [a]
deriving (Functor, Foldable, Traversable)
deriving (Functor, Foldable, Traversable, Semigroup)
instance Splittable L where
splitAt i (L xs) = over both L (Data.List.splitAt i xs)
@ -383,6 +383,22 @@ prop_findByLazy =
l' ^. listSelectedL == Just 1
&& l'' ^. listSelectedL == Just 3
prop_listSelectedElement_lazy :: Bool
prop_listSelectedElement_lazy =
let
v = L (1:2:3:4:undefined) :: L Int
l = list () v 1 & listSelectedL .~ Just 3
in
listSelectedElement l == Just (3, 4)
prop_listSelectedElementL_lazy :: Bool
prop_listSelectedElementL_lazy =
let
v = L (1:2:3:4:undefined) :: L Int
l = list () v 1 & listSelectedL .~ Just 3
in
over listSelectedElementL (*2) l ^? listSelectedElementL == Just 8
return []