-- | Module    : Hum.Modes.ExMode
-- Copyright   : (c) Itai Y. Efrat 2020-2021
-- License     : GPLv2-or-later (see LICENSE)
-- Maintainer  : Itai Y. Efrat <itai3397@gmail.com>
--
-- Functions for the ex mode style prompt.

module Hum.Modes.ExMode where

import           Brick.Widgets.Edit      hiding ( decodeUtf8 )
import           Brick.Types
import           Brick.Main
import           Hum.Types
import           Hum.Views
import           Hum.Rebuild
import           Graphics.Vty.Input.Events
import qualified Data.Text.Zipper              as Z
import qualified Data.Text                     as T
import           Control.Lens hiding (uncons)
import qualified Network.MPD                   as MPD
import           Hum.Utils

-- | Executed after pressing enter in the ex mode prompt.
-- Either executes the command, or updates the search state for n/N to work.
exEnd :: HumState -> EventM Name (Next HumState)
exEnd :: HumState -> EventM Name (Next HumState)
exEnd HumState
s =
    let searched :: Text
searched = (HumState
s HumState
-> Getting (TextZipper Text) HumState (TextZipper Text)
-> TextZipper Text
forall s a. s -> Getting a s a -> a
^. (ExState -> Const (TextZipper Text) ExState)
-> HumState -> Const (TextZipper Text) HumState
Lens' HumState ExState
exL ((ExState -> Const (TextZipper Text) ExState)
 -> HumState -> Const (TextZipper Text) HumState)
-> ((TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
    -> ExState -> Const (TextZipper Text) ExState)
-> Getting (TextZipper Text) HumState (TextZipper Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
-> ExState -> Const (TextZipper Text) ExState
Lens' ExState (Editor Text Name)
exEditorL ((Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
 -> ExState -> Const (TextZipper Text) ExState)
-> ((TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
    -> Editor Text Name -> Const (TextZipper Text) (Editor Text Name))
-> (TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
-> ExState
-> Const (TextZipper Text) ExState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (TextZipper Text -> Const (TextZipper Text) (TextZipper Text))
-> Editor Text Name -> Const (TextZipper Text) (Editor Text Name)
forall t1 n t2.
Lens (Editor t1 n) (Editor t2 n) (TextZipper t1) (TextZipper t2)
editContentsL TextZipper Text -> (TextZipper Text -> Text) -> Text
forall a b. a -> (a -> b) -> b
& TextZipper Text -> Text
forall a. Monoid a => TextZipper a -> a
Z.currentLine)
        s' :: HumState
s'= HumState
s HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (ExState -> Identity ExState) -> HumState -> Identity HumState
Lens' HumState ExState
exL ((ExState -> Identity ExState) -> HumState -> Identity HumState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> ExState -> Identity ExState)
-> (Editor Text Name -> Identity (Editor Text Name))
-> HumState
-> Identity HumState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Editor Text Name -> Identity (Editor Text Name))
-> ExState -> Identity ExState
Lens' ExState (Editor Text Name)
exEditorL ((Editor Text Name -> Identity (Editor Text Name))
 -> HumState -> Identity HumState)
-> Editor Text Name -> HumState -> HumState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Name -> Maybe Int -> Text -> Editor Text Name
forall n. n -> Maybe Int -> Text -> Editor Text n
editorText Name
ExEditor (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Text
""
              HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (Mode -> Identity Mode) -> HumState -> Identity HumState
Lens' HumState Mode
modeL ((Mode -> Identity Mode) -> HumState -> Identity HumState)
-> Mode -> HumState -> HumState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Mode
NormalMode
              HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (Focus -> Identity Focus) -> HumState -> Identity HumState
Lens' HumState Focus
focusL ((Focus -> Identity Focus) -> HumState -> Identity HumState)
-> ((Bool -> Identity Bool) -> Focus -> Identity Focus)
-> (Bool -> Identity Bool)
-> HumState
-> Identity HumState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Identity Bool) -> Focus -> Identity Focus
Lens' Focus Bool
focExL ((Bool -> Identity Bool) -> HumState -> Identity HumState)
-> Bool -> HumState -> HumState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Bool
False
    in
          case HumState
s HumState -> Getting ExSubMode HumState ExSubMode -> ExSubMode
forall s a. s -> Getting a s a -> a
^. (ExState -> Const ExSubMode ExState)
-> HumState -> Const ExSubMode HumState
Lens' HumState ExState
exL ((ExState -> Const ExSubMode ExState)
 -> HumState -> Const ExSubMode HumState)
-> ((ExSubMode -> Const ExSubMode ExSubMode)
    -> ExState -> Const ExSubMode ExState)
-> Getting ExSubMode HumState ExSubMode
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ExSubMode -> Const ExSubMode ExSubMode)
-> ExState -> Const ExSubMode ExState
Lens' ExState ExSubMode
exPrefixL of
            ExSubMode
Cmd -> [Text] -> HumState -> EventM Name (Next HumState)
exCmdExecute (Text -> [Text]
forall t. IsText t "words" => t -> [t]
words Text
searched) (HumState
s' HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (ExState -> Identity ExState) -> HumState -> Identity HumState
Lens' HumState ExState
exL ((ExState -> Identity ExState) -> HumState -> Identity HumState)
-> (([Text] -> Identity [Text]) -> ExState -> Identity ExState)
-> ([Text] -> Identity [Text])
-> HumState
-> Identity HumState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text] -> Identity [Text]) -> ExState -> Identity ExState
Lens' ExState [Text]
cmdHistoryL (([Text] -> Identity [Text]) -> HumState -> Identity HumState)
-> ([Text] -> [Text]) -> HumState -> HumState
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (Text
searched Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
:) )
            ExSubMode
srch -> case HumState -> View
hview HumState
s' of
                View
QueueView     -> HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue (HumState -> EventM Name (Next HumState))
-> EventM Name HumState -> EventM Name (Next HumState)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Bool -> HumState -> EventM Name HumState
queueSearch (ExSubMode
srch ExSubMode -> ExSubMode -> Bool
forall a. Eq a => a -> a -> Bool
== ExSubMode
FSearch) HumState
s''
                View
LibraryView   -> HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue (HumState -> EventM Name (Next HumState))
-> EventM Name HumState -> EventM Name (Next HumState)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Bool -> HumState -> EventM Name HumState
librarySearch (ExSubMode
srch ExSubMode -> ExSubMode -> Bool
forall a. Eq a => a -> a -> Bool
== ExSubMode
FSearch) HumState
s''
                View
PlaylistsView -> HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue (HumState -> EventM Name (Next HumState))
-> EventM Name HumState -> EventM Name (Next HumState)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Bool -> HumState -> EventM Name HumState
playlistsSearch (ExSubMode
srch ExSubMode -> ExSubMode -> Bool
forall a. Eq a => a -> a -> Bool
== ExSubMode
FSearch) HumState
s''
                View
HelpView      -> HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue (HumState -> EventM Name (Next HumState))
-> EventM Name HumState -> EventM Name (Next HumState)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Bool -> HumState -> EventM Name HumState
helpSearch (ExSubMode
srch ExSubMode -> ExSubMode -> Bool
forall a. Eq a => a -> a -> Bool
== ExSubMode
FSearch) HumState
s''
                where s'' :: HumState
s''= HumState
s' HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (ExState -> Identity ExState) -> HumState -> Identity HumState
Lens' HumState ExState
exL ((ExState -> Identity ExState) -> HumState -> Identity HumState)
-> (([Text] -> Identity [Text]) -> ExState -> Identity ExState)
-> ([Text] -> Identity [Text])
-> HumState
-> Identity HumState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Text] -> Identity [Text]) -> ExState -> Identity ExState
Lens' ExState [Text]
searchHistoryL (([Text] -> Identity [Text]) -> HumState -> Identity HumState)
-> ([Text] -> [Text]) -> HumState -> HumState
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ (Text
searched Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
:)

-- | Handle key inputs for ex mode.
handleExEvent
    :: HumState -> BrickEvent Name HumEvent -> EventM Name (Next HumState)
handleExEvent :: HumState -> BrickEvent Name HumEvent -> EventM Name (Next HumState)
handleExEvent HumState
s BrickEvent Name HumEvent
e = case BrickEvent Name HumEvent
e of
    VtyEvent (EvKey Key
KEsc []) ->
        HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue (HumState -> EventM Name (Next HumState))
-> HumState -> EventM Name (Next HumState)
forall a b. (a -> b) -> a -> b
$ HumState
s HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (ExState -> Identity ExState) -> HumState -> Identity HumState
Lens' HumState ExState
exL ((ExState -> Identity ExState) -> HumState -> Identity HumState)
-> ((Editor Text Name -> Identity (Editor Text Name))
    -> ExState -> Identity ExState)
-> (Editor Text Name -> Identity (Editor Text Name))
-> HumState
-> Identity HumState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Editor Text Name -> Identity (Editor Text Name))
-> ExState -> Identity ExState
Lens' ExState (Editor Text Name)
exEditorL ((Editor Text Name -> Identity (Editor Text Name))
 -> HumState -> Identity HumState)
-> Editor Text Name -> HumState -> HumState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Name -> Maybe Int -> Text -> Editor Text Name
forall n. n -> Maybe Int -> Text -> Editor Text n
editorText Name
ExEditor (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1) Text
""
                     HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (Mode -> Identity Mode) -> HumState -> Identity HumState
Lens' HumState Mode
modeL ((Mode -> Identity Mode) -> HumState -> Identity HumState)
-> Mode -> HumState -> HumState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Mode
NormalMode
                     HumState -> (HumState -> HumState) -> HumState
forall a b. a -> (a -> b) -> b
& (Focus -> Identity Focus) -> HumState -> Identity HumState
Lens' HumState Focus
focusL ((Focus -> Identity Focus) -> HumState -> Identity HumState)
-> ((Bool -> Identity Bool) -> Focus -> Identity Focus)
-> (Bool -> Identity Bool)
-> HumState
-> Identity HumState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool -> Identity Bool) -> Focus -> Identity Focus
Lens' Focus Bool
focExL ((Bool -> Identity Bool) -> HumState -> Identity HumState)
-> Bool -> HumState -> HumState
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Bool
False
    VtyEvent (EvKey Key
KEnter []) -> HumState -> EventM Name (Next HumState)
exEnd HumState
s
    VtyEvent Event
vtye ->
        HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue (HumState -> EventM Name (Next HumState))
-> EventM Name HumState -> EventM Name (Next HumState)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< HumState
-> Lens' HumState (Editor Text Name)
-> (Event -> Editor Text Name -> EventM Name (Editor Text Name))
-> Event
-> EventM Name HumState
forall a b e n.
a -> Lens' a b -> (e -> b -> EventM n b) -> e -> EventM n a
handleEventLensed HumState
s ((ExState -> f ExState) -> HumState -> f HumState
Lens' HumState ExState
exL ((ExState -> f ExState) -> HumState -> f HumState)
-> ((Editor Text Name -> f (Editor Text Name))
    -> ExState -> f ExState)
-> (Editor Text Name -> f (Editor Text Name))
-> HumState
-> f HumState
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Editor Text Name -> f (Editor Text Name)) -> ExState -> f ExState
Lens' ExState (Editor Text Name)
exEditorL) Event -> Editor Text Name -> EventM Name (Editor Text Name)
forall t n.
(DecodeUtf8 t, Eq t, Monoid t) =>
Event -> Editor t n -> EventM n (Editor t n)
handleEditorEvent Event
vtye
    BrickEvent Name HumEvent
_ -> HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue HumState
s

-- | Prefix of ex mode prompt.
exPrefixTxt :: ExSubMode -> Text
exPrefixTxt :: ExSubMode -> Text
exPrefixTxt ExSubMode
Cmd = Text
":"
exPrefixTxt ExSubMode
FSearch= Text
"/"
exPrefixTxt ExSubMode
BSearch = Text
"?"

-- | Executes ex mode command.
exCmdExecute :: [Text] -> HumState -> EventM Name (Next HumState)
exCmdExecute :: [Text] -> HumState -> EventM Name (Next HumState)
exCmdExecute (Text
"help":[Text]
_) HumState
s = HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue HumState
s { hview :: View
hview = View
HelpView }
exCmdExecute (Text
"q":[Text]
_) HumState
s = HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
halt HumState
s
exCmdExecute (Text
"save":[Text]
name) HumState
s =
  let name' :: Text
name'  = if [Text] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Text]
name then Text
"unnamed" else [Text] -> Text
forall t. IsText t "unwords" => [t] -> t
unwords [Text]
name in
    do
    PlaylistName
name'' <- IO PlaylistName -> EventM Name PlaylistName
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO PlaylistName -> EventM Name PlaylistName)
-> IO PlaylistName -> EventM Name PlaylistName
forall a b. (a -> b) -> a -> b
$ PlaylistName -> IO PlaylistName
unusedPlName (String -> PlaylistName
forall a. IsString a => String -> a
fromString (String -> PlaylistName)
-> (Text -> String) -> Text -> PlaylistName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack (Text -> PlaylistName) -> Text -> PlaylistName
forall a b. (a -> b) -> a -> b
$ Text
name')
    Response ()
_ <- IO (Response ()) -> EventM Name (Response ())
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Response ()) -> EventM Name (Response ()))
-> IO (Response ()) -> EventM Name (Response ())
forall a b. (a -> b) -> a -> b
$ MPD () -> IO (Response ())
forall a. MPD a -> IO (Response a)
MPD.withMPD (MPD () -> IO (Response ())) -> MPD () -> IO (Response ())
forall a b. (a -> b) -> a -> b
$ PlaylistName -> MPD ()
forall (m :: * -> *). MonadMPD m => PlaylistName -> m ()
MPD.save PlaylistName
name''
    HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue (HumState -> EventM Name (Next HumState))
-> EventM Name HumState -> EventM Name (Next HumState)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< HumState -> EventM Name HumState
forall (m :: * -> *). MonadIO m => HumState -> m HumState
rebuildPl HumState
s
exCmdExecute [Text]
_ HumState
s = HumState -> EventM Name (Next HumState)
forall s n. s -> EventM n (Next s)
continue HumState
s