packages feed

chiasma-0.12.2.0: lib/Chiasma/Codec.hs

module Chiasma.Codec where

import qualified Data.Text as Text
import GHC.Generics (Rep, to)
import Prelude hiding (to)

import Chiasma.Codec.Decode (TmuxDataDecode (..))
import Chiasma.Codec.Query (TmuxDataQuery (..))
import qualified Chiasma.Data.DecodeError as DecodeFailure (DecodeFailure (..))
import Chiasma.Data.DecodeError (DecodeError (DecodeError), DecodeFailure)
import Chiasma.Data.TmuxId (PaneId, SessionId, WindowId)
import Chiasma.Data.TmuxQuery (TmuxQuery (TmuxQuery))

-- | Remove one leading and trailing space from tmux output if both are present.
tryTrim :: Text -> Maybe Text
tryTrim text = do
  (prefix, lastChar) <- Text.unsnoc text
  guard (lastChar == ' ')
  (firstChar, payload) <- Text.uncons prefix
  guard (firstChar == ' ')
  pure payload

trim :: Text -> Text
trim text =
  fromMaybe text (tryTrim text)

checkRemainder :: ([Text], b) -> Either DecodeFailure b
checkRemainder = \case
  ([], result) -> Right result
  (a, _) -> Left (DecodeFailure.TooManyFields a)

genDecode ::
  Generic a =>
  TmuxDataDecode (Rep a) =>
  Text ->
  Either DecodeError a
genDecode fields = do
  bimap (DecodeError [fields]) to do
    checkRemainder =<< dataDecode (Text.splitOn " " (trim fields))

class TmuxCodec a where
  decode :: Text -> Either DecodeError a
  default decode ::
    Generic a =>
    TmuxDataDecode (Rep a) =>
    Text ->
    Either DecodeError a
  decode =
    genDecode

  query :: TmuxQuery
  default query :: TmuxDataQuery (Rep a) => TmuxQuery
  query =
    TmuxQuery (Text.unwords (dataQuery @(Rep a)))

instance TmuxCodec SessionId
instance TmuxCodec WindowId
instance TmuxCodec PaneId

multi ::
  TmuxCodec a =>
  [Text] ->
  Either DecodeError [a]
multi =
  traverse decode

single ::
  TmuxCodec a =>
  [Text] ->
  Either DecodeError a
single = \case
  [out] -> decode out
  [] -> Left (DecodeError [] DecodeFailure.TargetMissing)
  out -> Left (DecodeError out (DecodeFailure.TooManyRecords out))