module Chiasma.Data.Panes where

import Chiasma.Class.CmdArgs (cmdArgs)
import qualified Chiasma.Codec as Codec
import Chiasma.Codec (TmuxCodec, multi, single)
import qualified Chiasma.Data.DecodeError as DecodeFailure
import Chiasma.Data.DecodeError (DecodeError (DecodeError))
import qualified Chiasma.Data.PaneSelection as PaneSelection
import Chiasma.Data.PaneSelection (PaneSelection)
import qualified Chiasma.Data.Target as Target
import Chiasma.Data.TmuxId (PaneId)
import Chiasma.Data.TmuxQuery (TmuxQuery)
import Chiasma.Data.TmuxRequest (TmuxRequest (TmuxRequest))
import Chiasma.Data.TmuxResponse (TmuxResponse (TmuxResponse))
import Chiasma.Data.WithPaneId (WithPaneId (WithPaneId))
import Chiasma.Effect.TmuxApi (TmuxApi)

-- |A 'TmuxApi' command for listing panes, with different query criteria.
-- The constructors taking a 'PaneSelection' list all panes that are present in the selected scope, but may constrain
-- the return value.
-- The constructors 'Get' and 'Find' return only the pane with the requested ID.
data Panes (p :: Type) (a :: Type) :: Type where
  -- |Return all panes covered by the selection.
  List :: PaneSelection -> Panes p [p]
  -- |Return one pane covered by the selection, fail if there is none.
  First :: PaneSelection -> Panes p p
  -- |Return one pane covered by the selection, fail if there is none or more than one.
  One :: PaneSelection -> Panes p p
  -- |Return the pane with the specified ID, fail if there is none.
  Get :: PaneId -> Panes p p
  -- |Return the pane with the specified ID if it exists.
  Find :: PaneId -> Panes p (Maybe p)

type TmuxPanes p =
  TmuxApi (Panes p)

query ::
   p a .
  TmuxCodec p =>
  Panes p a ->
  TmuxQuery
query :: forall p a. TmuxCodec p => Panes p a -> TmuxQuery
query Panes p a
_ =
  forall a. TmuxCodec a => TmuxQuery
Codec.query @p

selection :: Panes p a -> PaneSelection
selection :: forall p a. Panes p a -> PaneSelection
selection = \case
  List PaneSelection
ps -> PaneSelection
ps
  First PaneSelection
ps -> PaneSelection
ps
  One PaneSelection
ps -> PaneSelection
ps
  Get PaneId
i -> Target -> PaneSelection
PaneSelection.InWindow (PaneId -> Target
Target.Pane PaneId
i)
  Find PaneId
_ -> PaneSelection
PaneSelection.All

request ::
  Panes p a ->
  TmuxQuery ->
  TmuxRequest
request :: forall p a. Panes p a -> TmuxQuery -> TmuxRequest
request (Panes p a -> PaneSelection
forall p a. Panes p a -> PaneSelection
selection -> PaneSelection
s) =
  Text -> [Text] -> Maybe TmuxQuery -> TmuxRequest
TmuxRequest Text
"list-panes" (PaneSelection -> [Text]
forall a. CmdArgs a => a -> [Text]
cmdArgs PaneSelection
s) (Maybe TmuxQuery -> TmuxRequest)
-> (TmuxQuery -> Maybe TmuxQuery) -> TmuxQuery -> TmuxRequest
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TmuxQuery -> Maybe TmuxQuery
forall a. a -> Maybe a
Just

encode ::
   p a .
  TmuxCodec p =>
  Panes p a ->
  TmuxRequest
encode :: forall p a. TmuxCodec p => Panes p a -> TmuxRequest
encode (Get PaneId
i) =
  Panes Any Any -> TmuxQuery -> TmuxRequest
forall p a. Panes p a -> TmuxQuery -> TmuxRequest
request (PaneId -> Panes Any Any
forall p. PaneId -> Panes p p
Get PaneId
i) (forall a. TmuxCodec a => TmuxQuery
Codec.query @(WithPaneId p))
encode (Find PaneId
i) =
  Panes Any (Maybe Any) -> TmuxQuery -> TmuxRequest
forall p a. Panes p a -> TmuxQuery -> TmuxRequest
request (PaneId -> Panes Any (Maybe Any)
forall p. PaneId -> Panes p (Maybe p)
Find PaneId
i) (forall a. TmuxCodec a => TmuxQuery
Codec.query @(WithPaneId p))
encode Panes p a
cmd =
  Panes p a -> TmuxQuery -> TmuxRequest
forall p a. Panes p a -> TmuxQuery -> TmuxRequest
request Panes p a
cmd (Panes p a -> TmuxQuery
forall p a. TmuxCodec p => Panes p a -> TmuxQuery
query Panes p a
cmd)

sameId :: PaneId -> WithPaneId a -> Maybe a
sameId :: forall a. PaneId -> WithPaneId a -> Maybe a
sameId PaneId
target (WithPaneId PaneId
paneId a
p)
  | PaneId
target PaneId -> PaneId -> Bool
forall a. Eq a => a -> a -> Bool
== PaneId
paneId = a -> Maybe a
forall a. a -> Maybe a
Just a
p
  | Bool
otherwise = Maybe a
forall a. Maybe a
Nothing

paneById ::
  TmuxCodec p =>
  PaneId ->
  [Text] ->
  Either DecodeError (Maybe p)
paneById :: forall p.
TmuxCodec p =>
PaneId -> [Text] -> Either DecodeError (Maybe p)
paneById PaneId
paneId [Text]
out = do
  (WithPaneId p -> Maybe p) -> [WithPaneId p] -> Maybe p
forall a b. (a -> Maybe b) -> [a] -> Maybe b
firstJust (PaneId -> WithPaneId p -> Maybe p
forall a. PaneId -> WithPaneId a -> Maybe a
sameId PaneId
paneId) ([WithPaneId p] -> Maybe p)
-> Either DecodeError [WithPaneId p]
-> Either DecodeError (Maybe p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Text] -> Either DecodeError [WithPaneId p]
forall a. TmuxCodec a => [Text] -> Either DecodeError [a]
multi [Text]
out

decode ::
   p a .
  TmuxCodec p =>
  TmuxResponse ->
  Panes p a ->
  Either DecodeError a
decode :: forall p a.
TmuxCodec p =>
TmuxResponse -> Panes p a -> Either DecodeError a
decode (TmuxResponse [Text]
out) = \case
  List PaneSelection
_ ->
    [Text] -> Either DecodeError [p]
forall a. TmuxCodec a => [Text] -> Either DecodeError [a]
multi [Text]
out
  First PaneSelection
_ ->
    [Text] -> Either DecodeError [a]
forall a. TmuxCodec a => [Text] -> Either DecodeError [a]
multi [Text]
out Either DecodeError [a]
-> ([a] -> Either DecodeError a) -> Either DecodeError a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
      [] -> DecodeError -> Either DecodeError a
forall a b. a -> Either a b
Left ([Text] -> DecodeFailure -> DecodeError
DecodeError [Text]
out DecodeFailure
DecodeFailure.TooFewFields)
      a
a : [a]
_ -> a -> Either DecodeError a
forall a b. b -> Either a b
Right a
a
  One PaneSelection
_ ->
    [Text] -> Either DecodeError a
forall a. TmuxCodec a => [Text] -> Either DecodeError a
single [Text]
out
  Get PaneId
paneId -> do
    [WithPaneId p]
ps <- forall a. TmuxCodec a => [Text] -> Either DecodeError [a]
multi @(WithPaneId p) [Text]
out
    DecodeError -> Maybe p -> Either DecodeError p
forall l r. l -> Maybe r -> Either l r
maybeToRight ([Text] -> DecodeFailure -> DecodeError
DecodeError [Text]
out DecodeFailure
DecodeFailure.TargetMissing) ((WithPaneId p -> Maybe p) -> [WithPaneId p] -> Maybe p
forall a b. (a -> Maybe b) -> [a] -> Maybe b
firstJust (PaneId -> WithPaneId p -> Maybe p
forall a. PaneId -> WithPaneId a -> Maybe a
sameId PaneId
paneId) [WithPaneId p]
ps)
  Find PaneId
paneId -> do
    [WithPaneId p]
ps <- forall a. TmuxCodec a => [Text] -> Either DecodeError [a]
multi @(WithPaneId p) [Text]
out
    pure ((WithPaneId p -> Maybe p) -> [WithPaneId p] -> Maybe p
forall a b. (a -> Maybe b) -> [a] -> Maybe b
firstJust (PaneId -> WithPaneId p -> Maybe p
forall a. PaneId -> WithPaneId a -> Maybe a
sameId PaneId
paneId) [WithPaneId p]
ps)