module Ribosome.Menu.Simple where

import Control.Lens (_2, element, ifolded, over, set, toListOf, view, withIndex, (^..), (^?))
import qualified Control.Lens as Lens (filtered)
import Data.Composition ((.:))
import Data.Map.Strict ((!?))
import qualified Data.Map.Strict as Map (fromList, union)
import qualified Data.Ord as Ord (Down(Down))
import qualified Data.Text as Text (breakOn, null)
import qualified Text.Fuzzy as Fuzzy (Fuzzy(score, original), filter)

import Ribosome.Data.List (indexesComplement)
import Ribosome.Menu.Action (menuContinue, menuCycle, menuQuitWith, menuToggle, menuToggleAll)
import Ribosome.Menu.Data.BasicMenuAction (BasicMenuAction, BasicMenuChange)
import qualified Ribosome.Menu.Data.BasicMenuAction as BasicMenuAction (BasicMenuAction(..))
import qualified Ribosome.Menu.Data.BasicMenuAction as BasicMenuChange (BasicMenuChange(..))
import Ribosome.Menu.Data.FilteredMenuItem (FilteredMenuItem(FilteredMenuItem))
import qualified Ribosome.Menu.Data.FilteredMenuItem as FilteredMenuItem (index, item)
import Ribosome.Menu.Data.Menu (Menu(Menu), MenuFilter(MenuFilter))
import qualified Ribosome.Menu.Data.Menu as Menu (currentFilter, filtered, items, marked, selected)
import Ribosome.Menu.Data.MenuAction (MenuAction)
import qualified Ribosome.Menu.Data.MenuAction as MenuAction (MenuAction(..))
import Ribosome.Menu.Data.MenuConsumerAction (MenuConsumerAction)
import qualified Ribosome.Menu.Data.MenuConsumerAction as MenuConsumerAction (MenuConsumerAction(..))
import Ribosome.Menu.Data.MenuEvent (MenuEvent)
import qualified Ribosome.Menu.Data.MenuEvent as MenuEvent (MenuEvent(..))
import qualified Ribosome.Menu.Data.MenuEvent as QuitReason (QuitReason(..))
import Ribosome.Menu.Data.MenuItem (MenuItem)
import qualified Ribosome.Menu.Data.MenuItem as MenuItem (text)
import Ribosome.Menu.Data.MenuItemFilter (MenuItemFilter(MenuItemFilter))
import Ribosome.Menu.Data.MenuUpdate (MenuUpdate(MenuUpdate))
import Ribosome.Menu.Prompt.Data.Prompt (Prompt(Prompt))

type MappingHandler m a i = Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
type Mappings m a i = Map Text (MappingHandler m a i)

zipWithIndex :: [a] -> [(Int, a)]
zipWithIndex :: [a] -> [(Int, a)]
zipWithIndex =
  Getting (Endo [(Int, a)]) [a] (Int, a) -> [a] -> [(Int, a)]
forall a s. Getting (Endo [a]) s a -> s -> [a]
toListOf (Getting (Endo [(Int, a)]) [a] (Int, a) -> [a] -> [(Int, a)])
-> Getting (Endo [(Int, a)]) [a] (Int, a) -> [a] -> [(Int, a)]
forall a b. (a -> b) -> a -> b
$ Indexed Int a (Const (Endo [(Int, a)]) a)
-> [a] -> Const (Endo [(Int, a)]) [a]
forall i (f :: * -> *) a.
FoldableWithIndex i f =>
IndexedFold i (f a) a
ifolded (Indexed Int a (Const (Endo [(Int, a)]) a)
 -> [a] -> Const (Endo [(Int, a)]) [a])
-> (((Int, a) -> Const (Endo [(Int, a)]) (Int, a))
    -> Indexed Int a (Const (Endo [(Int, a)]) a))
-> Getting (Endo [(Int, a)]) [a] (Int, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((Int, a) -> Const (Endo [(Int, a)]) (Int, a))
-> Indexed Int a (Const (Endo [(Int, a)]) a)
forall i (p :: * -> * -> *) (f :: * -> *) s j t.
(Indexable i p, Functor f) =>
p (i, s) (f (j, t)) -> Indexed i s (f t)
withIndex

textContains :: Text -> Text -> Bool
textContains :: Text -> Text -> Bool
textContains Text
needle Text
haystack =
  Text -> Bool
Text.null Text
needle Bool -> Bool -> Bool
|| (Bool -> Bool
not (Text -> Bool
Text.null Text
haystack) Bool -> Bool -> Bool
&& Text -> Text -> Bool
search Text
needle Text
haystack)
  where
    search :: Text -> Text -> Bool
search =
      Bool -> Bool
not (Bool -> Bool) -> ((Text, Text) -> Bool) -> (Text, Text) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Bool
Text.null (Text -> Bool) -> ((Text, Text) -> Text) -> (Text, Text) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text, Text) -> Text
forall a b. (a, b) -> b
snd ((Text, Text) -> Bool)
-> (Text -> Text -> (Text, Text)) -> Text -> Text -> Bool
forall c d a b. (c -> d) -> (a -> b -> c) -> a -> b -> d
.: Text -> Text -> (Text, Text)
Text.breakOn

substringMenuItemMatcher :: MenuItemFilter a
substringMenuItemMatcher :: MenuItemFilter a
substringMenuItemMatcher =
  (Text -> [MenuItem a] -> [FilteredMenuItem a]) -> MenuItemFilter a
forall a.
(Text -> [MenuItem a] -> [FilteredMenuItem a]) -> MenuItemFilter a
MenuItemFilter Text -> [MenuItem a] -> [FilteredMenuItem a]
forall (f :: * -> *) a.
FoldableWithIndex Int f =>
Text -> f (MenuItem a) -> [FilteredMenuItem a]
filt
  where
    filt :: Text -> f (MenuItem a) -> [FilteredMenuItem a]
filt Text
text =
      (Int -> MenuItem a -> FilteredMenuItem a)
-> (Int, MenuItem a) -> FilteredMenuItem a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Int -> MenuItem a -> FilteredMenuItem a
forall a. Int -> MenuItem a -> FilteredMenuItem a
FilteredMenuItem ((Int, MenuItem a) -> FilteredMenuItem a)
-> (f (MenuItem a) -> [(Int, MenuItem a)])
-> f (MenuItem a)
-> [FilteredMenuItem a]
forall (f0 :: * -> *) (f1 :: * -> *) a b.
(Functor f0, Functor f1) =>
(a -> b) -> f1 (f0 a) -> f1 (f0 b)
<$$> Text -> f (MenuItem a) -> [(Int, MenuItem a)]
forall i (f :: * -> *) s a.
(FoldableWithIndex i f, HasMenuItem s a) =>
Text -> f s -> [(i, s)]
matcher Text
text
    matcher :: Text -> f s -> [(i, s)]
matcher Text
text =
      Getting (Endo [(i, s)]) (f s) (i, s) -> f s -> [(i, s)]
forall a s. Getting (Endo [a]) s a -> s -> [a]
toListOf (Getting (Endo [(i, s)]) (f s) (i, s) -> f s -> [(i, s)])
-> Getting (Endo [(i, s)]) (f s) (i, s) -> f s -> [(i, s)]
forall a b. (a -> b) -> a -> b
$ Indexed i s (Const (Endo [(i, s)]) s)
-> f s -> Const (Endo [(i, s)]) (f s)
forall i (f :: * -> *) a.
FoldableWithIndex i f =>
IndexedFold i (f a) a
ifolded (Indexed i s (Const (Endo [(i, s)]) s)
 -> f s -> Const (Endo [(i, s)]) (f s))
-> (((i, s) -> Const (Endo [(i, s)]) (i, s))
    -> Indexed i s (Const (Endo [(i, s)]) s))
-> Getting (Endo [(i, s)]) (f s) (i, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (s -> Bool) -> Optic' (Indexed i) (Const (Endo [(i, s)])) s s
forall (p :: * -> * -> *) (f :: * -> *) a.
(Choice p, Applicative f) =>
(a -> Bool) -> Optic' p f a a
Lens.filtered (Text -> Text -> Bool
textContains Text
text (Text -> Bool) -> (s -> Text) -> s -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting Text s Text -> s -> Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Text s Text
forall c a. HasMenuItem c a => Lens' c Text
MenuItem.text) Optic' (Indexed i) (Const (Endo [(i, s)])) s s
-> (((i, s) -> Const (Endo [(i, s)]) (i, s))
    -> Indexed i s (Const (Endo [(i, s)]) s))
-> ((i, s) -> Const (Endo [(i, s)]) (i, s))
-> Indexed i s (Const (Endo [(i, s)]) s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((i, s) -> Const (Endo [(i, s)]) (i, s))
-> Indexed i s (Const (Endo [(i, s)]) s)
forall i (p :: * -> * -> *) (f :: * -> *) s j t.
(Indexable i p, Functor f) =>
p (i, s) (f (j, t)) -> Indexed i s (f t)
withIndex

fuzzyMenuItemMatcher :: MenuItemFilter a
fuzzyMenuItemMatcher :: MenuItemFilter a
fuzzyMenuItemMatcher =
  (Text -> [MenuItem a] -> [FilteredMenuItem a]) -> MenuItemFilter a
forall a.
(Text -> [MenuItem a] -> [FilteredMenuItem a]) -> MenuItemFilter a
MenuItemFilter Text -> [MenuItem a] -> [FilteredMenuItem a]
forall a. Text -> [MenuItem a] -> [FilteredMenuItem a]
matcher
  where
    matcher :: Text -> [MenuItem a] -> [FilteredMenuItem a]
matcher =
      (Fuzzy (Int, MenuItem a) Text -> FilteredMenuItem a)
-> [Fuzzy (Int, MenuItem a) Text] -> [FilteredMenuItem a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Int -> MenuItem a -> FilteredMenuItem a)
-> (Int, MenuItem a) -> FilteredMenuItem a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Int -> MenuItem a -> FilteredMenuItem a
forall a. Int -> MenuItem a -> FilteredMenuItem a
FilteredMenuItem ((Int, MenuItem a) -> FilteredMenuItem a)
-> (Fuzzy (Int, MenuItem a) Text -> (Int, MenuItem a))
-> Fuzzy (Int, MenuItem a) Text
-> FilteredMenuItem a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fuzzy (Int, MenuItem a) Text -> (Int, MenuItem a)
forall t s. TextualMonoid s => Fuzzy t s -> t
Fuzzy.original) ([Fuzzy (Int, MenuItem a) Text] -> [FilteredMenuItem a])
-> ([Fuzzy (Int, MenuItem a) Text]
    -> [Fuzzy (Int, MenuItem a) Text])
-> [Fuzzy (Int, MenuItem a) Text]
-> [FilteredMenuItem a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Fuzzy (Int, MenuItem a) Text -> Down Int)
-> [Fuzzy (Int, MenuItem a) Text] -> [Fuzzy (Int, MenuItem a) Text]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (Int -> Down Int
forall a. a -> Down a
Ord.Down (Int -> Down Int)
-> (Fuzzy (Int, MenuItem a) Text -> Int)
-> Fuzzy (Int, MenuItem a) Text
-> Down Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fuzzy (Int, MenuItem a) Text -> Int
forall t s. TextualMonoid s => Fuzzy t s -> Int
Fuzzy.score) ([Fuzzy (Int, MenuItem a) Text] -> [FilteredMenuItem a])
-> (Text -> [MenuItem a] -> [Fuzzy (Int, MenuItem a) Text])
-> Text
-> [MenuItem a]
-> [FilteredMenuItem a]
forall c d a b. (c -> d) -> (a -> b -> c) -> a -> b -> d
.: Text -> [MenuItem a] -> [Fuzzy (Int, MenuItem a) Text]
forall i (f :: * -> *) a a.
(FoldableWithIndex i f, HasMenuItem a a) =>
Text -> f a -> [Fuzzy (i, a) Text]
filtered
    filtered :: Text -> f a -> [Fuzzy (i, a) Text]
filtered Text
text f a
items =
      Text
-> [(i, a)]
-> Text
-> Text
-> ((i, a) -> Text)
-> Bool
-> [Fuzzy (i, a) Text]
forall s t.
TextualMonoid s =>
s -> [t] -> s -> s -> (t -> s) -> Bool -> [Fuzzy t s]
Fuzzy.filter Text
text (f a
items f a -> Getting (Endo [(i, a)]) (f a) (i, a) -> [(i, a)]
forall s a. s -> Getting (Endo [a]) s a -> [a]
^.. Indexed i a (Const (Endo [(i, a)]) a)
-> f a -> Const (Endo [(i, a)]) (f a)
forall i (f :: * -> *) a.
FoldableWithIndex i f =>
IndexedFold i (f a) a
ifolded (Indexed i a (Const (Endo [(i, a)]) a)
 -> f a -> Const (Endo [(i, a)]) (f a))
-> (((i, a) -> Const (Endo [(i, a)]) (i, a))
    -> Indexed i a (Const (Endo [(i, a)]) a))
-> Getting (Endo [(i, a)]) (f a) (i, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((i, a) -> Const (Endo [(i, a)]) (i, a))
-> Indexed i a (Const (Endo [(i, a)]) a)
forall i (p :: * -> * -> *) (f :: * -> *) s j t.
(Indexable i p, Functor f) =>
p (i, s) (f (j, t)) -> Indexed i s (f t)
withIndex) Text
"" Text
"" (Getting Text (i, a) Text -> (i, a) -> Text
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((a -> Const Text a) -> (i, a) -> Const Text (i, a)
forall s t a b. Field2 s t a b => Lens s t a b
_2 ((a -> Const Text a) -> (i, a) -> Const Text (i, a))
-> ((Text -> Const Text Text) -> a -> Const Text a)
-> Getting Text (i, a) Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Const Text Text) -> a -> Const Text a
forall c a. HasMenuItem c a => Lens' c Text
MenuItem.text)) Bool
False

menuItemsNonequal :: [FilteredMenuItem i] -> [FilteredMenuItem i] -> Bool
menuItemsNonequal :: [FilteredMenuItem i] -> [FilteredMenuItem i] -> Bool
menuItemsNonequal [FilteredMenuItem i]
a [FilteredMenuItem i]
b =
  (Getting Int (FilteredMenuItem i) Int -> FilteredMenuItem i -> Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Int (FilteredMenuItem i) Int
forall c a. HasFilteredMenuItem c a => Lens' c Int
FilteredMenuItem.index (FilteredMenuItem i -> Int) -> [FilteredMenuItem i] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilteredMenuItem i]
a) [Int] -> [Int] -> Bool
forall a. Eq a => a -> a -> Bool
/= (Getting Int (FilteredMenuItem i) Int -> FilteredMenuItem i -> Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Int (FilteredMenuItem i) Int
forall c a. HasFilteredMenuItem c a => Lens' c Int
FilteredMenuItem.index (FilteredMenuItem i -> Int) -> [FilteredMenuItem i] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilteredMenuItem i]
b)

updateFilter :: MenuItemFilter i -> Text -> Menu i -> (BasicMenuChange, Menu i)
updateFilter :: MenuItemFilter i -> Text -> Menu i -> (BasicMenuChange, Menu i)
updateFilter (MenuItemFilter Text -> [MenuItem i] -> [FilteredMenuItem i]
itemFilter) Text
text menu :: Menu i
menu@(Menu [MenuItem i]
items [FilteredMenuItem i]
oldFiltered Int
_ [Int]
_ MenuFilter
_ Maybe Int
_) =
  (BasicMenuChange
change, Menu i -> Menu i
update Menu i
menu)
  where
    change :: BasicMenuChange
change =
      if [FilteredMenuItem i] -> [FilteredMenuItem i] -> Bool
forall i. [FilteredMenuItem i] -> [FilteredMenuItem i] -> Bool
menuItemsNonequal [FilteredMenuItem i]
filtered [FilteredMenuItem i]
oldFiltered
      then BasicMenuChange
BasicMenuChange.Change
      else BasicMenuChange
BasicMenuChange.NoChange
    update :: Menu i -> Menu i
update =
      ASetter (Menu i) (Menu i) [FilteredMenuItem i] [FilteredMenuItem i]
-> [FilteredMenuItem i] -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) [FilteredMenuItem i] [FilteredMenuItem i]
forall c a. HasMenu c a => Lens' c [FilteredMenuItem a]
Menu.filtered [FilteredMenuItem i]
filtered (Menu i -> Menu i) -> (Menu i -> Menu i) -> Menu i -> Menu i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ASetter (Menu i) (Menu i) MenuFilter MenuFilter
-> MenuFilter -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) MenuFilter MenuFilter
forall c a. HasMenu c a => Lens' c MenuFilter
Menu.currentFilter (Text -> MenuFilter
MenuFilter Text
text)
    filtered :: [FilteredMenuItem i]
filtered =
      Text -> [MenuItem i] -> [FilteredMenuItem i]
itemFilter Text
text [MenuItem i]
items

reapplyFilter :: MenuItemFilter i -> Menu i -> (BasicMenuChange, Menu i)
reapplyFilter :: MenuItemFilter i -> Menu i -> (BasicMenuChange, Menu i)
reapplyFilter MenuItemFilter i
itemFilter menu :: Menu i
menu@(Menu [MenuItem i]
_ [FilteredMenuItem i]
_ Int
_ [Int]
_ (MenuFilter Text
currentFilter) Maybe Int
_) =
  MenuItemFilter i -> Text -> Menu i -> (BasicMenuChange, Menu i)
forall i.
MenuItemFilter i -> Text -> Menu i -> (BasicMenuChange, Menu i)
updateFilter MenuItemFilter i
itemFilter Text
currentFilter Menu i
menu

basicMenuTransform :: MenuItemFilter i -> MenuEvent m a i -> Menu i -> BasicMenuAction m a i
basicMenuTransform :: MenuItemFilter i
-> MenuEvent m a i -> Menu i -> BasicMenuAction m a i
basicMenuTransform MenuItemFilter i
matcher (MenuEvent.PromptChange (Prompt Int
_ PromptState
_ Text
text)) =
  BasicMenuChange -> Menu i -> BasicMenuAction m a i
forall (m :: * -> *) a i.
BasicMenuChange -> Menu i -> BasicMenuAction m a i
BasicMenuAction.Continue BasicMenuChange
BasicMenuChange.Reset (Menu i -> BasicMenuAction m a i)
-> (Menu i -> Menu i) -> Menu i -> BasicMenuAction m a i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (BasicMenuChange, Menu i) -> Menu i
forall a b. (a, b) -> b
snd ((BasicMenuChange, Menu i) -> Menu i)
-> (Menu i -> (BasicMenuChange, Menu i)) -> Menu i -> Menu i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MenuItemFilter i -> Text -> Menu i -> (BasicMenuChange, Menu i)
forall i.
MenuItemFilter i -> Text -> Menu i -> (BasicMenuChange, Menu i)
updateFilter MenuItemFilter i
matcher Text
text
basicMenuTransform MenuItemFilter i
_ (MenuEvent.Mapping Text
_ Prompt
_) =
  BasicMenuChange -> Menu i -> BasicMenuAction m a i
forall (m :: * -> *) a i.
BasicMenuChange -> Menu i -> BasicMenuAction m a i
BasicMenuAction.Continue BasicMenuChange
BasicMenuChange.NoChange
basicMenuTransform MenuItemFilter i
matcher (MenuEvent.NewItems [MenuItem i]
items) =
  (BasicMenuChange -> Menu i -> BasicMenuAction m a i)
-> (BasicMenuChange, Menu i) -> BasicMenuAction m a i
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry BasicMenuChange -> Menu i -> BasicMenuAction m a i
forall (m :: * -> *) a i.
BasicMenuChange -> Menu i -> BasicMenuAction m a i
BasicMenuAction.Continue ((BasicMenuChange, Menu i) -> BasicMenuAction m a i)
-> (Menu i -> (BasicMenuChange, Menu i))
-> Menu i
-> BasicMenuAction m a i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. MenuItemFilter i -> Menu i -> (BasicMenuChange, Menu i)
forall i. MenuItemFilter i -> Menu i -> (BasicMenuChange, Menu i)
reapplyFilter MenuItemFilter i
matcher (Menu i -> (BasicMenuChange, Menu i))
-> (Menu i -> Menu i) -> Menu i -> (BasicMenuChange, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ASetter (Menu i) (Menu i) [MenuItem i] [MenuItem i]
-> ([MenuItem i] -> [MenuItem i]) -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter (Menu i) (Menu i) [MenuItem i] [MenuItem i]
forall c a. HasMenu c a => Lens' c [MenuItem a]
Menu.items ([MenuItem i] -> [MenuItem i] -> [MenuItem i]
forall a. [a] -> [a] -> [a]
++ [MenuItem i]
items)
basicMenuTransform MenuItemFilter i
_ (MenuEvent.Init Prompt
_) =
  BasicMenuChange -> Menu i -> BasicMenuAction m a i
forall (m :: * -> *) a i.
BasicMenuChange -> Menu i -> BasicMenuAction m a i
BasicMenuAction.Continue BasicMenuChange
BasicMenuChange.Change
basicMenuTransform MenuItemFilter i
_ (MenuEvent.Quit QuitReason m a
reason) =
  BasicMenuAction m a i -> Menu i -> BasicMenuAction m a i
forall a b. a -> b -> a
const (BasicMenuAction m a i -> Menu i -> BasicMenuAction m a i)
-> BasicMenuAction m a i -> Menu i -> BasicMenuAction m a i
forall a b. (a -> b) -> a -> b
$ QuitReason m a -> BasicMenuAction m a i
forall (m :: * -> *) a i. QuitReason m a -> BasicMenuAction m a i
BasicMenuAction.Quit QuitReason m a
reason

resetSelection :: BasicMenuChange -> Menu i -> Menu i
resetSelection :: BasicMenuChange -> Menu i -> Menu i
resetSelection BasicMenuChange
BasicMenuChange.Reset (Menu [MenuItem i]
i [FilteredMenuItem i]
f Int
_ [Int]
_ MenuFilter
filt Maybe Int
mi) =
  [MenuItem i]
-> [FilteredMenuItem i]
-> Int
-> [Int]
-> MenuFilter
-> Maybe Int
-> Menu i
forall a.
[MenuItem a]
-> [FilteredMenuItem a]
-> Int
-> [Int]
-> MenuFilter
-> Maybe Int
-> Menu a
Menu [MenuItem i]
i [FilteredMenuItem i]
f Int
0 [] MenuFilter
filt Maybe Int
mi
resetSelection BasicMenuChange
_ Menu i
m =
  Menu i
m

menuAction ::
  MenuItemFilter i ->
  Bool ->
  MenuConsumerAction m a ->
  Menu i ->
  (MenuAction m a, Menu i)
menuAction :: MenuItemFilter i
-> Bool
-> MenuConsumerAction m a
-> Menu i
-> (MenuAction m a, Menu i)
menuAction MenuItemFilter i
itemFilter Bool
_ MenuConsumerAction m a
MenuConsumerAction.Filter Menu i
menu =
  (Bool -> MenuAction m a
forall (m :: * -> *) a. Bool -> MenuAction m a
MenuAction.Render Bool
True, (BasicMenuChange -> Menu i -> Menu i)
-> (BasicMenuChange, Menu i) -> Menu i
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry BasicMenuChange -> Menu i -> Menu i
forall i. BasicMenuChange -> Menu i -> Menu i
resetSelection ((BasicMenuChange, Menu i) -> Menu i)
-> (BasicMenuChange, Menu i) -> Menu i
forall a b. (a -> b) -> a -> b
$ MenuItemFilter i -> Menu i -> (BasicMenuChange, Menu i)
forall i. MenuItemFilter i -> Menu i -> (BasicMenuChange, Menu i)
reapplyFilter MenuItemFilter i
itemFilter Menu i
menu)
menuAction MenuItemFilter i
_ Bool
True MenuConsumerAction m a
MenuConsumerAction.Continue Menu i
menu =
  (Bool -> MenuAction m a
forall (m :: * -> *) a. Bool -> MenuAction m a
MenuAction.Render Bool
True, Menu i
menu)
menuAction MenuItemFilter i
_ Bool
False MenuConsumerAction m a
MenuConsumerAction.Continue Menu i
menu =
  (MenuAction m a
forall (m :: * -> *) a. MenuAction m a
MenuAction.Continue, Menu i
menu)
menuAction MenuItemFilter i
_ Bool
_ (MenuConsumerAction.Execute m ()
thunk) Menu i
menu =
  (m () -> MenuAction m a
forall (m :: * -> *) a. m () -> MenuAction m a
MenuAction.Execute m ()
thunk, Menu i
menu)
menuAction MenuItemFilter i
_ Bool
basicChanged (MenuConsumerAction.Render Bool
consumerChanged) Menu i
menu =
  (Bool -> MenuAction m a
forall (m :: * -> *) a. Bool -> MenuAction m a
MenuAction.Render (Bool
basicChanged Bool -> Bool -> Bool
|| Bool
consumerChanged), Menu i
menu)
menuAction MenuItemFilter i
_ Bool
_ (MenuConsumerAction.QuitWith m a
ma) Menu i
menu =
  (QuitReason m a -> MenuAction m a
forall (m :: * -> *) a. QuitReason m a -> MenuAction m a
MenuAction.Quit (m a -> QuitReason m a
forall (m :: * -> *) a. m a -> QuitReason m a
QuitReason.Execute m a
ma), Menu i
menu)
menuAction MenuItemFilter i
_ Bool
_ MenuConsumerAction m a
MenuConsumerAction.Quit Menu i
menu =
  (QuitReason m a -> MenuAction m a
forall (m :: * -> *) a. QuitReason m a -> MenuAction m a
MenuAction.Quit QuitReason m a
forall (m :: * -> *) a. QuitReason m a
QuitReason.Aborted, Menu i
menu)
menuAction MenuItemFilter i
_ Bool
_ (MenuConsumerAction.Return a
a) Menu i
menu =
  (QuitReason m a -> MenuAction m a
forall (m :: * -> *) a. QuitReason m a -> MenuAction m a
MenuAction.Quit (a -> QuitReason m a
forall (m :: * -> *) a. a -> QuitReason m a
QuitReason.Return a
a), Menu i
menu)
menuAction MenuItemFilter i
_ Bool
_ (MenuConsumerAction.UpdatePrompt Prompt
prompt) Menu i
menu =
  (Prompt -> MenuAction m a
forall (m :: * -> *) a. Prompt -> MenuAction m a
MenuAction.UpdatePrompt Prompt
prompt, Menu i
menu)

basicMenuAction ::
  Monad m =>
  MenuItemFilter i ->
  (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)) ->
  MenuUpdate m a i ->
  BasicMenuAction m a i ->
  m (MenuAction m a, Menu i)
basicMenuAction :: MenuItemFilter i
-> (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
-> MenuUpdate m a i
-> BasicMenuAction m a i
-> m (MenuAction m a, Menu i)
basicMenuAction MenuItemFilter i
itemFilter MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)
consumer (MenuUpdate MenuEvent m a i
event Menu i
menu) =
  BasicMenuAction m a i -> m (MenuAction m a, Menu i)
act
  where
    act :: BasicMenuAction m a i -> m (MenuAction m a, Menu i)
act (BasicMenuAction.Quit QuitReason m a
reason) =
      (MenuAction m a, Menu i) -> m (MenuAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (QuitReason m a -> MenuAction m a
forall (m :: * -> *) a. QuitReason m a -> MenuAction m a
MenuAction.Quit QuitReason m a
reason, Menu i
menu)
    act (BasicMenuAction.Continue BasicMenuChange
change Menu i
m) = do
      (MenuConsumerAction m a
action, Menu i
updatedMenu) <- Menu i -> m (MenuConsumerAction m a, Menu i)
consumerTransform (BasicMenuChange -> Menu i -> Menu i
forall i. BasicMenuChange -> Menu i -> Menu i
resetSelection BasicMenuChange
change Menu i
m)
      (MenuAction m a, Menu i) -> m (MenuAction m a, Menu i)
forall (m :: * -> *) a. Monad m => a -> m a
return ((MenuAction m a, Menu i) -> m (MenuAction m a, Menu i))
-> (MenuAction m a, Menu i) -> m (MenuAction m a, Menu i)
forall a b. (a -> b) -> a -> b
$ MenuItemFilter i
-> Bool
-> MenuConsumerAction m a
-> Menu i
-> (MenuAction m a, Menu i)
forall i (m :: * -> *) a.
MenuItemFilter i
-> Bool
-> MenuConsumerAction m a
-> Menu i
-> (MenuAction m a, Menu i)
menuAction MenuItemFilter i
itemFilter (BasicMenuChange
change BasicMenuChange -> BasicMenuChange -> Bool
forall a. Eq a => a -> a -> Bool
/= BasicMenuChange
BasicMenuChange.NoChange) MenuConsumerAction m a
action Menu i
updatedMenu
    consumerTransform :: Menu i -> m (MenuConsumerAction m a, Menu i)
consumerTransform Menu i
newMenu =
      MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)
consumer (MenuEvent m a i -> Menu i -> MenuUpdate m a i
forall (m :: * -> *) a i.
MenuEvent m a i -> Menu i -> MenuUpdate m a i
MenuUpdate MenuEvent m a i
event Menu i
newMenu)

basicMenu ::
  Monad m =>
  MenuItemFilter i ->
  (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)) ->
  MenuUpdate m a i ->
  m (MenuAction m a, Menu i)
basicMenu :: MenuItemFilter i
-> (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
-> MenuUpdate m a i
-> m (MenuAction m a, Menu i)
basicMenu MenuItemFilter i
itemFilter MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)
consumer update :: MenuUpdate m a i
update@(MenuUpdate MenuEvent m a i
event Menu i
menu) =
  MenuItemFilter i
-> (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
-> MenuUpdate m a i
-> BasicMenuAction m a i
-> m (MenuAction m a, Menu i)
forall (m :: * -> *) i a.
Monad m =>
MenuItemFilter i
-> (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
-> MenuUpdate m a i
-> BasicMenuAction m a i
-> m (MenuAction m a, Menu i)
basicMenuAction MenuItemFilter i
itemFilter MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)
consumer MenuUpdate m a i
update BasicMenuAction m a i
basicTransform
  where
    basicTransform :: BasicMenuAction m a i
basicTransform =
      MenuItemFilter i
-> MenuEvent m a i -> Menu i -> BasicMenuAction m a i
forall i (m :: * -> *) a.
MenuItemFilter i
-> MenuEvent m a i -> Menu i -> BasicMenuAction m a i
basicMenuTransform MenuItemFilter i
itemFilter MenuEvent m a i
event Menu i
menu

mappingConsumer ::
  Monad m =>
  Mappings m a i ->
  MenuUpdate m a i ->
  m (MenuConsumerAction m a, Menu i)
mappingConsumer :: Mappings m a i
-> MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)
mappingConsumer Mappings m a i
mappings (MenuUpdate (MenuEvent.Mapping Text
char Prompt
prompt) Menu i
menu) =
  Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
handler Menu i
menu Prompt
prompt
  where
    handler :: Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
handler =
      (Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i))
-> Maybe (Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i))
-> Menu i
-> Prompt
-> m (MenuConsumerAction m a, Menu i)
forall a. a -> Maybe a -> a
fromMaybe (m (MenuConsumerAction m a, Menu i)
-> Prompt -> m (MenuConsumerAction m a, Menu i)
forall a b. a -> b -> a
const (m (MenuConsumerAction m a, Menu i)
 -> Prompt -> m (MenuConsumerAction m a, Menu i))
-> (Menu i -> m (MenuConsumerAction m a, Menu i))
-> Menu i
-> Prompt
-> m (MenuConsumerAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Menu i -> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) i a.
Applicative m =>
Menu i -> m (MenuConsumerAction m a, Menu i)
menuContinue) (Mappings m a i
mappings Mappings m a i
-> Text
-> Maybe (Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i))
forall k a. Ord k => Map k a -> k -> Maybe a
!? Text
char)
mappingConsumer Mappings m a i
_ (MenuUpdate MenuEvent m a i
_ Menu i
menu) =
  Menu i -> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) i a.
Applicative m =>
Menu i -> m (MenuConsumerAction m a, Menu i)
menuContinue Menu i
menu

simpleMenu ::
  Monad m =>
  Mappings m a i ->
  MenuUpdate m a i ->
  m (MenuAction m a, Menu i)
simpleMenu :: Mappings m a i -> MenuUpdate m a i -> m (MenuAction m a, Menu i)
simpleMenu =
  MenuItemFilter i
-> (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
-> MenuUpdate m a i
-> m (MenuAction m a, Menu i)
forall (m :: * -> *) i a.
Monad m =>
MenuItemFilter i
-> (MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
-> MenuUpdate m a i
-> m (MenuAction m a, Menu i)
basicMenu MenuItemFilter i
forall a. MenuItemFilter a
fuzzyMenuItemMatcher ((MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
 -> MenuUpdate m a i -> m (MenuAction m a, Menu i))
-> (Mappings m a i
    -> MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i))
-> Mappings m a i
-> MenuUpdate m a i
-> m (MenuAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mappings m a i
-> MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) a i.
Monad m =>
Mappings m a i
-> MenuUpdate m a i -> m (MenuConsumerAction m a, Menu i)
mappingConsumer

defaultMappings ::
  Monad m =>
  Mappings m a i
defaultMappings :: Mappings m a i
defaultMappings =
  [(Text, MappingHandler m a i)] -> Mappings m a i
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [
    (Text
"k", Int -> MappingHandler m a i
forall (m :: * -> *) i a.
Monad m =>
Int -> Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuCycle Int
1),
    (Text
"c-k", Int -> MappingHandler m a i
forall (m :: * -> *) i a.
Monad m =>
Int -> Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuCycle Int
1),
    (Text
"j", Int -> MappingHandler m a i
forall (m :: * -> *) i a.
Monad m =>
Int -> Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuCycle (-Int
1)),
    (Text
"c-j", Int -> MappingHandler m a i
forall (m :: * -> *) i a.
Monad m =>
Int -> Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuCycle (-Int
1)),
    (Text
"space", MappingHandler m a i
forall (m :: * -> *) i a.
Monad m =>
Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuToggle),
    (Text
"*", MappingHandler m a i
forall (m :: * -> *) i a.
Monad m =>
Menu i -> Prompt -> m (MenuConsumerAction m a, Menu i)
menuToggleAll)
    ]

defaultMenu ::
  Monad m =>
  Mappings m a i ->
  MenuUpdate m a i ->
  m (MenuAction m a, Menu i)
defaultMenu :: Mappings m a i -> MenuUpdate m a i -> m (MenuAction m a, Menu i)
defaultMenu =
  Mappings m a i -> MenuUpdate m a i -> m (MenuAction m a, Menu i)
forall (m :: * -> *) a i.
Monad m =>
Mappings m a i -> MenuUpdate m a i -> m (MenuAction m a, Menu i)
simpleMenu (Mappings m a i -> MenuUpdate m a i -> m (MenuAction m a, Menu i))
-> (Mappings m a i -> Mappings m a i)
-> Mappings m a i
-> MenuUpdate m a i
-> m (MenuAction m a, Menu i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Mappings m a i -> Mappings m a i -> Mappings m a i
forall k a. Ord k => Map k a -> Map k a -> Map k a
`Map.union` Mappings m a i
forall (m :: * -> *) a i. Monad m => Mappings m a i
defaultMappings)

selectedMenuItem :: Menu i -> Maybe (MenuItem i)
selectedMenuItem :: Menu i -> Maybe (MenuItem i)
selectedMenuItem (Menu [MenuItem i]
_ [FilteredMenuItem i]
filtered Int
selected [Int]
_ MenuFilter
_ Maybe Int
_) =
  [FilteredMenuItem i]
filtered [FilteredMenuItem i]
-> Getting (First (MenuItem i)) [FilteredMenuItem i] (MenuItem i)
-> Maybe (MenuItem i)
forall s a. s -> Getting (First a) s a -> Maybe a
^? Int
-> IndexedTraversal' Int [FilteredMenuItem i] (FilteredMenuItem i)
forall (t :: * -> *) a.
Traversable t =>
Int -> IndexedTraversal' Int (t a) a
element Int
selected ((FilteredMenuItem i
  -> Const (First (MenuItem i)) (FilteredMenuItem i))
 -> [FilteredMenuItem i]
 -> Const (First (MenuItem i)) [FilteredMenuItem i])
-> ((MenuItem i -> Const (First (MenuItem i)) (MenuItem i))
    -> FilteredMenuItem i
    -> Const (First (MenuItem i)) (FilteredMenuItem i))
-> Getting (First (MenuItem i)) [FilteredMenuItem i] (MenuItem i)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MenuItem i -> Const (First (MenuItem i)) (MenuItem i))
-> FilteredMenuItem i
-> Const (First (MenuItem i)) (FilteredMenuItem i)
forall c a. HasFilteredMenuItem c a => Lens' c (MenuItem a)
FilteredMenuItem.item

withSelectedMenuItem ::
  Monad m =>
  (MenuItem i -> m (MenuConsumerAction m a, Menu i)) ->
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
withSelectedMenuItem :: (MenuItem i -> m (MenuConsumerAction m a, Menu i))
-> Menu i -> m (MenuConsumerAction m a, Menu i)
withSelectedMenuItem MenuItem i -> m (MenuConsumerAction m a, Menu i)
f Menu i
m =
  m (MenuConsumerAction m a, Menu i)
-> ((MenuConsumerAction m a, Menu i)
    -> m (MenuConsumerAction m a, Menu i))
-> Maybe (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (Menu i -> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) i a.
Applicative m =>
Menu i -> m (MenuConsumerAction m a, Menu i)
menuContinue Menu i
m) (MenuConsumerAction m a, Menu i)
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (MenuConsumerAction m a, Menu i)
 -> m (MenuConsumerAction m a, Menu i))
-> m (Maybe (MenuConsumerAction m a, Menu i))
-> m (MenuConsumerAction m a, Menu i)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (MenuItem i -> m (MenuConsumerAction m a, Menu i))
-> Maybe (MenuItem i) -> m (Maybe (MenuConsumerAction m a, Menu i))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse MenuItem i -> m (MenuConsumerAction m a, Menu i)
f (Menu i -> Maybe (MenuItem i)
forall i. Menu i -> Maybe (MenuItem i)
selectedMenuItem Menu i
m)

filterIndexes :: [Int] -> [a] -> [a]
filterIndexes :: [Int] -> [a] -> [a]
filterIndexes [Int]
indexes =
  [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [Int] -> [a] -> [a] -> [a]
forall a a. (Eq a, Num a) => a -> [a] -> [a] -> [a] -> [a]
go Int
0 ([Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [Int]
indexes) []
  where
    go :: a -> [a] -> [a] -> [a] -> [a]
go a
current (a
i : [a]
is) [a]
result (a
a : [a]
asTail) | a
i a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
current =
      a -> [a] -> [a] -> [a] -> [a]
go (a
current a -> a -> a
forall a. Num a => a -> a -> a
+ a
1) [a]
is (a
a a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
result) [a]
asTail
    go a
current [a]
is [a]
result (a
_ : [a]
asTail) =
      a -> [a] -> [a] -> [a] -> [a]
go (a
current a -> a -> a
forall a. Num a => a -> a -> a
+ a
1) [a]
is [a]
result [a]
asTail
    go a
_ [a]
_ [a]
result [a]
_ =
      [a]
result

markedIndexes :: Menu i -> [Int]
markedIndexes :: Menu i -> [Int]
markedIndexes (Menu [MenuItem i]
_ [FilteredMenuItem i]
_ Int
selected [] MenuFilter
_ Maybe Int
_) =
  [Int
Item [Int]
selected]
markedIndexes (Menu [MenuItem i]
_ [FilteredMenuItem i]
_ Int
_ [Int]
marked MenuFilter
_ Maybe Int
_) =
  [Int]
marked

menuItemsByIndexes :: [Int] -> Menu i -> [MenuItem i]
menuItemsByIndexes :: [Int] -> Menu i -> [MenuItem i]
menuItemsByIndexes [Int]
indexes (Menu [MenuItem i]
_ [FilteredMenuItem i]
filtered Int
_ [Int]
_ MenuFilter
_ Maybe Int
_) =
  Getting (MenuItem i) (FilteredMenuItem i) (MenuItem i)
-> FilteredMenuItem i -> MenuItem i
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (MenuItem i) (FilteredMenuItem i) (MenuItem i)
forall c a. HasFilteredMenuItem c a => Lens' c (MenuItem a)
FilteredMenuItem.item (FilteredMenuItem i -> MenuItem i)
-> [FilteredMenuItem i] -> [MenuItem i]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int] -> [FilteredMenuItem i] -> [FilteredMenuItem i]
forall a. [Int] -> [a] -> [a]
filterIndexes [Int]
indexes [FilteredMenuItem i]
filtered

markedMenuItemsOnly :: Menu i -> Maybe (NonEmpty (MenuItem i))
markedMenuItemsOnly :: Menu i -> Maybe (NonEmpty (MenuItem i))
markedMenuItemsOnly (Menu [MenuItem i]
_ [FilteredMenuItem i]
_ Int
_ [] MenuFilter
_ Maybe Int
_) =
  Maybe (NonEmpty (MenuItem i))
forall a. Maybe a
Nothing
markedMenuItemsOnly (Menu [MenuItem i]
_ [FilteredMenuItem i]
filtered Int
_ [Int]
marked MenuFilter
_ Maybe Int
_) =
  [MenuItem i] -> Maybe (NonEmpty (MenuItem i))
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty ([MenuItem i] -> Maybe (NonEmpty (MenuItem i)))
-> [MenuItem i] -> Maybe (NonEmpty (MenuItem i))
forall a b. (a -> b) -> a -> b
$ Getting (MenuItem i) (FilteredMenuItem i) (MenuItem i)
-> FilteredMenuItem i -> MenuItem i
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting (MenuItem i) (FilteredMenuItem i) (MenuItem i)
forall c a. HasFilteredMenuItem c a => Lens' c (MenuItem a)
FilteredMenuItem.item (FilteredMenuItem i -> MenuItem i)
-> [FilteredMenuItem i] -> [MenuItem i]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int] -> [FilteredMenuItem i] -> [FilteredMenuItem i]
forall a. [Int] -> [a] -> [a]
filterIndexes [Int]
marked [FilteredMenuItem i]
filtered

markedMenuItems :: Menu i -> Maybe (NonEmpty (MenuItem i))
markedMenuItems :: Menu i -> Maybe (NonEmpty (MenuItem i))
markedMenuItems Menu i
m =
  Menu i -> Maybe (NonEmpty (MenuItem i))
forall i. Menu i -> Maybe (NonEmpty (MenuItem i))
markedMenuItemsOnly Menu i
m Maybe (NonEmpty (MenuItem i))
-> Maybe (NonEmpty (MenuItem i)) -> Maybe (NonEmpty (MenuItem i))
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (MenuItem i -> NonEmpty (MenuItem i)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (MenuItem i -> NonEmpty (MenuItem i))
-> Maybe (MenuItem i) -> Maybe (NonEmpty (MenuItem i))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Menu i -> Maybe (MenuItem i)
forall i. Menu i -> Maybe (MenuItem i)
selectedMenuItem Menu i
m)

unmarkedMenuItems :: Menu i -> [MenuItem i]
unmarkedMenuItems :: Menu i -> [MenuItem i]
unmarkedMenuItems Menu i
menu =
  [Int] -> Menu i -> [MenuItem i]
forall i. [Int] -> Menu i -> [MenuItem i]
menuItemsByIndexes (Int -> [Int] -> [Int]
indexesComplement ([FilteredMenuItem i] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Getting [FilteredMenuItem i] (Menu i) [FilteredMenuItem i]
-> Menu i -> [FilteredMenuItem i]
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting [FilteredMenuItem i] (Menu i) [FilteredMenuItem i]
forall c a. HasMenu c a => Lens' c [FilteredMenuItem a]
Menu.filtered Menu i
menu)) (Menu i -> [Int]
forall a. Menu a -> [Int]
indexes Menu i
menu)) Menu i
menu
  where
    indexes :: Menu a -> [Int]
indexes (Menu [MenuItem a]
_ [FilteredMenuItem a]
_ Int
selected [] MenuFilter
_ Maybe Int
_) =
      [Int
Item [Int]
selected]
    indexes (Menu [MenuItem a]
_ [FilteredMenuItem a]
_ Int
_ [Int]
marked MenuFilter
_ Maybe Int
_) =
      [Int]
marked

withMarkedMenuItems ::
  Monad m =>
  (NonEmpty (MenuItem i) -> m a) ->
  Menu i ->
  m (Maybe a)
withMarkedMenuItems :: (NonEmpty (MenuItem i) -> m a) -> Menu i -> m (Maybe a)
withMarkedMenuItems NonEmpty (MenuItem i) -> m a
f Menu i
m =
  (NonEmpty (MenuItem i) -> m a)
-> Maybe (NonEmpty (MenuItem i)) -> m (Maybe a)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse NonEmpty (MenuItem i) -> m a
f (Menu i -> Maybe (NonEmpty (MenuItem i))
forall i. Menu i -> Maybe (NonEmpty (MenuItem i))
markedMenuItems Menu i
m)

withMarkedMenuItems_ ::
  Monad m =>
  (NonEmpty (MenuItem i) -> m ()) ->
  Menu i ->
  m ()
withMarkedMenuItems_ :: (NonEmpty (MenuItem i) -> m ()) -> Menu i -> m ()
withMarkedMenuItems_ NonEmpty (MenuItem i) -> m ()
f Menu i
m =
  (NonEmpty (MenuItem i) -> m ())
-> Maybe (NonEmpty (MenuItem i)) -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ NonEmpty (MenuItem i) -> m ()
f (Menu i -> Maybe (NonEmpty (MenuItem i))
forall i. Menu i -> Maybe (NonEmpty (MenuItem i))
markedMenuItems Menu i
m)

actionWithMarkedMenuItems ::
  Monad m =>
  (m (NonEmpty b) -> Menu i -> m (MenuConsumerAction m a, Menu i)) ->
  (MenuItem i -> m b) ->
  Menu i ->
  m (MenuConsumerAction m a, Menu i)
actionWithMarkedMenuItems :: (m (NonEmpty b) -> Menu i -> m (MenuConsumerAction m a, Menu i))
-> (MenuItem i -> m b)
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
actionWithMarkedMenuItems m (NonEmpty b) -> Menu i -> m (MenuConsumerAction m a, Menu i)
next MenuItem i -> m b
f Menu i
m =
  (MenuConsumerAction m a, Menu i)
-> Maybe (MenuConsumerAction m a, Menu i)
-> (MenuConsumerAction m a, Menu i)
forall a. a -> Maybe a -> a
fromMaybe (MenuConsumerAction m a
forall (m :: * -> *) a. MenuConsumerAction m a
MenuConsumerAction.Continue, Menu i
m) (Maybe (MenuConsumerAction m a, Menu i)
 -> (MenuConsumerAction m a, Menu i))
-> m (Maybe (MenuConsumerAction m a, Menu i))
-> m (MenuConsumerAction m a, Menu i)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (NonEmpty (MenuItem i) -> m (MenuConsumerAction m a, Menu i))
-> Menu i -> m (Maybe (MenuConsumerAction m a, Menu i))
forall (m :: * -> *) i a.
Monad m =>
(NonEmpty (MenuItem i) -> m a) -> Menu i -> m (Maybe a)
withMarkedMenuItems NonEmpty (MenuItem i) -> m (MenuConsumerAction m a, Menu i)
run Menu i
m
  where
    run :: NonEmpty (MenuItem i) -> m (MenuConsumerAction m a, Menu i)
run NonEmpty (MenuItem i)
items =
      m (NonEmpty b) -> Menu i -> m (MenuConsumerAction m a, Menu i)
next ((MenuItem i -> m b) -> NonEmpty (MenuItem i) -> m (NonEmpty b)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse MenuItem i -> m b
f NonEmpty (MenuItem i)
items) Menu i
m

traverseMarkedMenuItems ::
  Monad m =>
  (MenuItem i -> m a) ->
  Menu i ->
  m (Maybe (NonEmpty a))
traverseMarkedMenuItems :: (MenuItem i -> m a) -> Menu i -> m (Maybe (NonEmpty a))
traverseMarkedMenuItems =
  (NonEmpty (MenuItem i) -> m (NonEmpty a))
-> Menu i -> m (Maybe (NonEmpty a))
forall (m :: * -> *) i a.
Monad m =>
(NonEmpty (MenuItem i) -> m a) -> Menu i -> m (Maybe a)
withMarkedMenuItems ((NonEmpty (MenuItem i) -> m (NonEmpty a))
 -> Menu i -> m (Maybe (NonEmpty a)))
-> ((MenuItem i -> m a) -> NonEmpty (MenuItem i) -> m (NonEmpty a))
-> (MenuItem i -> m a)
-> Menu i
-> m (Maybe (NonEmpty a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MenuItem i -> m a) -> NonEmpty (MenuItem i) -> m (NonEmpty a)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse

traverseMarkedMenuItems_ ::
  Monad m =>
  (MenuItem i -> m ()) ->
  Menu i ->
  m ()
traverseMarkedMenuItems_ :: (MenuItem i -> m ()) -> Menu i -> m ()
traverseMarkedMenuItems_ =
  (NonEmpty (MenuItem i) -> m ()) -> Menu i -> m ()
forall (m :: * -> *) i.
Monad m =>
(NonEmpty (MenuItem i) -> m ()) -> Menu i -> m ()
withMarkedMenuItems_ ((NonEmpty (MenuItem i) -> m ()) -> Menu i -> m ())
-> ((MenuItem i -> m ()) -> NonEmpty (MenuItem i) -> m ())
-> (MenuItem i -> m ())
-> Menu i
-> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (MenuItem i -> m ()) -> NonEmpty (MenuItem i) -> m ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_

traverseMarkedMenuItemsAndQuit ::
  Monad m =>
  (MenuItem i -> m a) ->
  Menu i ->
  m (MenuConsumerAction m (NonEmpty a), Menu i)
traverseMarkedMenuItemsAndQuit :: (MenuItem i -> m a)
-> Menu i -> m (MenuConsumerAction m (NonEmpty a), Menu i)
traverseMarkedMenuItemsAndQuit =
  (m (NonEmpty a)
 -> Menu i -> m (MenuConsumerAction m (NonEmpty a), Menu i))
-> (MenuItem i -> m a)
-> Menu i
-> m (MenuConsumerAction m (NonEmpty a), Menu i)
forall (m :: * -> *) b i a.
Monad m =>
(m (NonEmpty b) -> Menu i -> m (MenuConsumerAction m a, Menu i))
-> (MenuItem i -> m b)
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
actionWithMarkedMenuItems m (NonEmpty a)
-> Menu i -> m (MenuConsumerAction m (NonEmpty a), Menu i)
forall (m :: * -> *) a i.
Applicative m =>
m a -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuQuitWith

traverseMarkedMenuItemsAndQuit_ ::
  Monad m =>
  (MenuItem i -> m ()) ->
  Menu i ->
  m (MenuConsumerAction m (), Menu i)
traverseMarkedMenuItemsAndQuit_ :: (MenuItem i -> m ())
-> Menu i -> m (MenuConsumerAction m (), Menu i)
traverseMarkedMenuItemsAndQuit_ MenuItem i -> m ()
f =
  (MenuConsumerAction m (NonEmpty ()) -> MenuConsumerAction m ())
-> (MenuConsumerAction m (NonEmpty ()), Menu i)
-> (MenuConsumerAction m (), Menu i)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first MenuConsumerAction m (NonEmpty ()) -> MenuConsumerAction m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void ((MenuConsumerAction m (NonEmpty ()), Menu i)
 -> (MenuConsumerAction m (), Menu i))
-> (Menu i -> m (MenuConsumerAction m (NonEmpty ()), Menu i))
-> Menu i
-> m (MenuConsumerAction m (), Menu i)
forall (f0 :: * -> *) (f1 :: * -> *) a b.
(Functor f0, Functor f1) =>
(a -> b) -> f1 (f0 a) -> f1 (f0 b)
<$$> (m (NonEmpty ())
 -> Menu i -> m (MenuConsumerAction m (NonEmpty ()), Menu i))
-> (MenuItem i -> m ())
-> Menu i
-> m (MenuConsumerAction m (NonEmpty ()), Menu i)
forall (m :: * -> *) b i a.
Monad m =>
(m (NonEmpty b) -> Menu i -> m (MenuConsumerAction m a, Menu i))
-> (MenuItem i -> m b)
-> Menu i
-> m (MenuConsumerAction m a, Menu i)
actionWithMarkedMenuItems m (NonEmpty ())
-> Menu i -> m (MenuConsumerAction m (NonEmpty ()), Menu i)
forall (m :: * -> *) a i.
Applicative m =>
m a -> Menu i -> m (MenuConsumerAction m a, Menu i)
menuQuitWith MenuItem i -> m ()
f

deleteByFilteredIndex :: [Int] -> Menu i -> Menu i
deleteByFilteredIndex :: [Int] -> Menu i -> Menu i
deleteByFilteredIndex [Int]
indexes menu :: Menu i
menu@(Menu [MenuItem i]
items [FilteredMenuItem i]
filtered Int
_ [Int]
_ MenuFilter
_ Maybe Int
_) =
  ASetter (Menu i) (Menu i) [MenuItem i] [MenuItem i]
-> [MenuItem i] -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) [MenuItem i] [MenuItem i]
forall c a. HasMenu c a => Lens' c [MenuItem a]
Menu.items [MenuItem i]
newItems (Menu i -> Menu i) -> (Menu i -> Menu i) -> Menu i -> Menu i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ASetter (Menu i) (Menu i) [FilteredMenuItem i] [FilteredMenuItem i]
-> [FilteredMenuItem i] -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) [FilteredMenuItem i] [FilteredMenuItem i]
forall c a. HasMenu c a => Lens' c [FilteredMenuItem a]
Menu.filtered [] (Menu i -> Menu i) -> Menu i -> Menu i
forall a b. (a -> b) -> a -> b
$ Menu i
menu
  where
    newItems :: [MenuItem i]
newItems =
      [Int] -> [MenuItem i] -> [MenuItem i]
forall a. [Int] -> [a] -> [a]
filterIndexes (Int -> [Int] -> [Int]
indexesComplement ([MenuItem i] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [MenuItem i]
items) [Int]
unfilteredIndexes) [MenuItem i]
items
    unfilteredIndexes :: [Int]
unfilteredIndexes =
      Getting Int (FilteredMenuItem i) Int -> FilteredMenuItem i -> Int
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Int (FilteredMenuItem i) Int
forall c a. HasFilteredMenuItem c a => Lens' c Int
FilteredMenuItem.index (FilteredMenuItem i -> Int) -> [FilteredMenuItem i] -> [Int]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int] -> [FilteredMenuItem i] -> [FilteredMenuItem i]
forall a. [Int] -> [a] -> [a]
filterIndexes [Int]
indexes [FilteredMenuItem i]
filtered

deleteMarked :: Menu i -> Menu i
deleteMarked :: Menu i -> Menu i
deleteMarked Menu i
menu =
  ASetter (Menu i) (Menu i) Int Int -> Int -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) Int Int
forall c a. HasMenu c a => Lens' c Int
Menu.selected Int
0 (Menu i -> Menu i) -> (Menu i -> Menu i) -> Menu i -> Menu i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ASetter (Menu i) (Menu i) [Int] [Int] -> [Int] -> Menu i -> Menu i
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter (Menu i) (Menu i) [Int] [Int]
forall c a. HasMenu c a => Lens' c [Int]
Menu.marked [] (Menu i -> Menu i) -> (Menu i -> Menu i) -> Menu i -> Menu i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Int] -> Menu i -> Menu i
forall i. [Int] -> Menu i -> Menu i
deleteByFilteredIndex (Menu i -> [Int]
forall a. Menu a -> [Int]
markedIndexes Menu i
menu) (Menu i -> Menu i) -> Menu i -> Menu i
forall a b. (a -> b) -> a -> b
$ Menu i
menu