packages feed

patat 0.10.0.0 → 0.10.1.0

raw patch · 10 files changed

+182/−44 lines, 10 filesdep ~ansi-terminaldep ~ansi-wl-pprintdep ~mtlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: ansi-terminal, ansi-wl-pprint, mtl, random

API changes (from Hackage documentation)

- Patat.Transition.SlideLeft: slideLeft :: Config -> TransitionGen
+ Patat.Transition: instance Data.Aeson.Types.FromJSON.FromJSON Patat.Transition.RandomTransitionSettings
+ Patat.Transition.Dissolve: instance Data.Aeson.Types.FromJSON.FromJSON Patat.Transition.Dissolve.Config
+ Patat.Transition.Dissolve: transition :: Config -> TransitionGen
+ Patat.Transition.Internal: evenlySpacedFrames :: Maybe Double -> Maybe Int -> NonEmpty (Double, Duration)
+ Patat.Transition.SlideLeft: transition :: Config -> TransitionGen

Files

CHANGELOG.md view
@@ -1,5 +1,13 @@ # Changelog +## 0.10.1.0 (2023-10-15)++ *  Add dissolve transition effect (#150)++ *  Add random transitions (#151)++    Set transition `type` to `random` to randomly sample transition effects+ ## 0.10.0.0 (2023-10-12)   *  Add transition effects (#149)
README.md view
@@ -803,11 +803,31 @@ Supported transitions `type`s:   -  `slideLeft`: slides the new slide in from right to left.+ -  `dissolve`: changes characters over time. -    Arguments:+All transitions currently take these arguments: -     -  `frameRate`: number of frames per second.  Defaults to 24.-     -  `duration`: duration of the animation in seconds.  Defaults to 1.+ -  `frameRate`: number of frames per second.  Defaults to 24.+ -  `duration`: duration of the animation in seconds.  Defaults to 1.++#### Random transitions++You can set `type` to `random` to randomly pick a transition effect.++```yaml+patat:+  transition:+    type: random+    items:+    - type: dissolve+      duration: 3+    - type: slideLeft+      frameRate: 10+```++You can optionally set `items` to a non-empty list of transition effects to+randomly sample from.  If `items` is not set, `patat` will simply sample from+all transition effects using their respective default settings.  Trivia ------
lib/Data/Aeson/Extended.hs view
@@ -3,12 +3,14 @@     ( module Data.Aeson      , FlexibleNum (..)++    , resultToEither     ) where  import           Data.Aeson-import qualified Data.Text  as T+import qualified Data.Text        as T import           Prelude-import           Text.Read  (readMaybe)+import           Text.Read        (readMaybe)  -- | This can be parsed from a JSON string in addition to a JSON number. newtype FlexibleNum a = FlexibleNum {unFlexibleNum :: a}@@ -19,3 +21,7 @@         Nothing -> fail $ "Could not parse " ++ T.unpack str ++ " as a number"         Just x  -> return (FlexibleNum x)     parseJSON val = FlexibleNum <$> parseJSON val++resultToEither :: Result a -> Either String a+resultToEither (Success x)   = Right x+resultToEither (Error   err) = Left err
lib/Patat/Main.hs view
@@ -13,8 +13,7 @@ import           Control.Concurrent.Chan.Extended (Chan) import qualified Control.Concurrent.Chan.Extended as Chan import           Control.Exception                (bracket)-import           Control.Monad                    (forever, join, unless, void,-                                                   when)+import           Control.Monad                    (forever, unless, void, when) import qualified Data.Aeson.Extended              as A import           Data.Foldable                    (for_) import           Data.Functor                     (($>))
lib/Patat/Presentation/Read.hs view
@@ -16,7 +16,7 @@ import           Control.Monad.Except           (ExceptT (..), runExceptT,                                                  throwError) import           Control.Monad.Trans            (liftIO)-import qualified Data.Aeson                     as A+import qualified Data.Aeson.Extended            as A import qualified Data.Aeson.KeyMap              as AKM import           Data.Bifunctor                 (first) import           Data.Maybe                     (fromMaybe)@@ -166,13 +166,9 @@     Nothing -> Right mempty     Just (Left err) -> Left err     Just (Right (A.Object obj)) | Just val <- AKM.lookup "patat" obj ->-       resultToEither $! A.fromJSON val+       first (\err -> "Error parsing patat settings from metadata: " ++ err) $!+       A.resultToEither $! A.fromJSON val     Just (Right _) -> Right mempty-  where-    resultToEither :: A.Result a -> Either String a-    resultToEither (A.Success x) = Right x-    resultToEither (A.Error   e) = Left $!-        "Error parsing patat settings from metadata: " ++ e   --------------------------------------------------------------------------------
lib/Patat/Transition.hs view
@@ -1,5 +1,9 @@ --------------------------------------------------------------------------------+{-# LANGUAGE DeriveFoldable    #-}+{-# LANGUAGE DeriveFunctor     #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TemplateHaskell   #-} module Patat.Transition     ( Duration (..)     , threadDelayDuration@@ -13,30 +17,70 @@   ---------------------------------------------------------------------------------import qualified Data.Aeson                  as A+import qualified Data.Aeson.Extended         as A+import qualified Data.Aeson.TH.Extended      as A+import           Data.Bifunctor              (first) import qualified Data.HashMap.Strict         as HMS+import           Data.List.NonEmpty          (NonEmpty (..))+import qualified Data.List.NonEmpty          as NonEmpty import           Data.Text                   (Text) import qualified Data.Text                   as T+import           Data.Traversable            (for) import           Patat.Presentation.Settings (TransitionSettings (..))+import qualified Patat.Transition.Dissolve   as Dissolve import           Patat.Transition.Internal import qualified Patat.Transition.SlideLeft  as SlideLeft+import           System.Random               (uniformR)   ---------------------------------------------------------------------------------transitions :: HMS.HashMap Text Transition-transitions = HMS.fromList-    [ ("slideLeft", Transition SlideLeft.slideLeft)-    ]+data RandomTransitionSettings = RandomTransitionSettings+    { rtsItems :: Maybe (NonEmpty TransitionSettings)+    }   --------------------------------------------------------------------------------+$(A.deriveFromJSON A.dropPrefixOptions ''RandomTransitionSettings)+++--------------------------------------------------------------------------------+random :: NonEmpty TransitionGen -> TransitionGen+random items size matrix0 matrix1 rg0 =+    let (idx, rg1) = uniformR (0, length items - 1) rg0 in+    (items NonEmpty.!! idx) size matrix0 matrix1 rg1+++--------------------------------------------------------------------------------+transitions :: NonEmpty (Text, Transition)+transitions =+    ("dissolve",  Transition Dissolve.transition) :|+    ("slideLeft", Transition SlideLeft.transition) : []+++--------------------------------------------------------------------------------+transitionTable :: HMS.HashMap Text Transition+transitionTable = foldMap (uncurry HMS.singleton) transitions+++-------------------------------------------------------------------------------- parseTransitionSettings     :: TransitionSettings -> Either String TransitionGen-parseTransitionSettings ts = case HMS.lookup ty transitions of-    Nothing             -> Left $ "unknown transition type: " ++ show ty-    Just (Transition f) -> case A.fromJSON (A.Object $ tsParams ts) of-        A.Success conf -> Right $ f conf-        A.Error   err  -> Left $-            "could not parse " ++ T.unpack ty ++ " transition: " ++ err+parseTransitionSettings ts+    -- Random is treated specially here.+    | ty == "random" = fmap random $ do+        settings <- A.resultToEither . A.fromJSON . A.Object $ tsParams ts+        case rtsItems settings of+            -- Items specified: parse those+            Just items -> traverse parseTransitionSettings items+            -- No items specified: parse default transition settings.+            Nothing -> for transitions $ \(typ, _) -> parseTransitionSettings+                TransitionSettings {tsType = typ, tsParams = mempty}+    -- Found the transition type.+    | Just (Transition f) <- HMS.lookup ty transitionTable =+        fmap (f $) . first (\err ->+            "could not parse " ++ T.unpack ty ++ " transition: " ++ err) .+        A.resultToEither . A.fromJSON . A.Object $ tsParams ts+    -- Not found, error.+    | otherwise = Left $ "unknown transition type: " ++ show ty   where-   ty = tsType ts+    ty = tsType ts
+ lib/Patat/Transition/Dissolve.hs view
@@ -0,0 +1,49 @@+--------------------------------------------------------------------------------+{-# LANGUAGE TemplateHaskell #-}+module Patat.Transition.Dissolve+    ( transition+    ) where+++--------------------------------------------------------------------------------+import qualified Data.Aeson.Extended       as A+import qualified Data.Aeson.TH.Extended    as A+import           Data.Bifunctor            (first)+import qualified Data.Vector               as V+import           Patat.PrettyPrint.Matrix+import           Patat.Size                (Size (..))+import           Patat.Transition.Internal+import           System.Random.Stateful+++--------------------------------------------------------------------------------+data Config = Config+    { cDuration  :: Maybe (A.FlexibleNum Double)+    , cFrameRate :: Maybe (A.FlexibleNum Int)+    }+++--------------------------------------------------------------------------------+transition :: Config -> TransitionGen+transition config (Size rows cols) initial final rgen =+    first frame <$>+    evenlySpacedFrames+        (A.unFlexibleNum <$> cDuration  config)+        (A.unFlexibleNum <$> cFrameRate config)+  where+    -- Generate a random number between 0 and 1 for each position.+    noise :: V.Vector Double+    noise = runStateGen_ rgen $ \g ->+        V.replicateM (rows * cols) (uniformRM (0, 1) g)++    -- Select the initial or final value depending on the noise.+    frame :: Double -> Matrix+    frame t = V.zipWith3+        (\treshold l r -> if t < treshold then l else r)+        noise+        initial+        final+++--------------------------------------------------------------------------------+$(A.deriveFromJSON A.dropPrefixOptions ''Config)
lib/Patat/Transition/Internal.hs view
@@ -10,6 +10,8 @@     , TransitionInstance (..)     , newTransition     , stepTransition++    , evenlySpacedFrames     ) where  @@ -17,6 +19,7 @@ import           Control.Concurrent       (threadDelay) import qualified Data.Aeson               as A import           Data.List.NonEmpty       (NonEmpty ((:|)))+import           Data.Maybe               (fromMaybe) import           Data.Unique              (Unique, newUnique) import qualified Patat.PrettyPrint        as PP import           Patat.PrettyPrint.Matrix@@ -79,3 +82,20 @@ stepTransition _       trans                         = case tiFrames trans of     _ :| []     -> Nothing     _ :| f : fs -> Just trans {tiFrames = f :| fs}+++--------------------------------------------------------------------------------+-- | Given an optional duration and frame rate, generate a sequence of evenly+-- spaced frames, represented by a number ranging from [0 .. 1].+evenlySpacedFrames+    :: Maybe Double -> Maybe Int -> NonEmpty (Double, Duration)+evenlySpacedFrames mbDuration mbFrameRate =+    frame 0 :| map frame [1 .. frames - 1]+  where+    duration  = fromMaybe 1  mbDuration+    frameRate = fromMaybe 24 mbFrameRate++    frames = round $ duration * fromIntegral frameRate :: Int+    delay  = duration / fromIntegral (frames + 1)++    frame idx = (fromIntegral (idx + 1) / fromIntegral frames, Duration delay)
lib/Patat/Transition/SlideLeft.hs view
@@ -1,16 +1,15 @@ -------------------------------------------------------------------------------- {-# LANGUAGE TemplateHaskell #-} module Patat.Transition.SlideLeft-    ( slideLeft+    ( transition     ) where   -------------------------------------------------------------------------------- import qualified Data.Aeson.Extended       as A import qualified Data.Aeson.TH.Extended    as A+import           Data.Bifunctor            (first) import           Data.Foldable             (for_)-import           Data.List.NonEmpty        (NonEmpty ((:|)))-import           Data.Maybe                (fromMaybe) import qualified Data.Vector               as V import qualified Data.Vector.Mutable       as VM import           Patat.PrettyPrint.Matrix@@ -26,19 +25,15 @@   ---------------------------------------------------------------------------------slideLeft :: Config -> TransitionGen-slideLeft config (Size rows cols) initial final _rgen =-    fmap (\f -> (f, Duration delay)) $-    frame 0 :| map frame [1 .. frames - 1]+transition :: Config -> TransitionGen+transition config (Size rows cols) initial final _rgen =+    first frame <$>+    evenlySpacedFrames+        (A.unFlexibleNum <$> cDuration  config)+        (A.unFlexibleNum <$> cFrameRate config)   where-    duration  = fromMaybe 1  $ A.unFlexibleNum <$> cDuration  config-    frameRate = fromMaybe 24 $ A.unFlexibleNum <$> cFrameRate config--    frames = round $ duration * fromIntegral frameRate :: Int-    delay  = duration / fromIntegral (frames + 1)--    frame :: Int -> Matrix-    frame idx = V.create $ do+    frame :: Double -> Matrix+    frame t = V.create $ do         ini <- V.unsafeThaw initial         fin <- V.unsafeThaw final         mat <- VM.replicate (rows * cols) emptyCell@@ -52,7 +47,7 @@         pure mat       where         offset = max 0 . min cols . (round :: Double -> Int) $-            fromIntegral (idx + 1) / fromIntegral frames * fromIntegral cols+            t * fromIntegral cols   --------------------------------------------------------------------------------
patat.cabal view
@@ -1,5 +1,5 @@ Name:                patat-Version:             0.10.0.0+Version:             0.10.1.0 Synopsis:            Terminal-based presentations using Pandoc Description:         Terminal-based presentations using Pandoc. License:             GPL-2@@ -47,7 +47,7 @@     pandoc               >= 3.1  && < 3.2,     pandoc-types         >= 1.23 && < 1.24,     process              >= 1.6  && < 1.7,-    random               >= 1.1  && < 1.3,+    random               >= 1.2  && < 1.3,     skylighting          >= 0.10 && < 0.15,     terminal-size        >= 0.3  && < 0.4,     text                 >= 1.2  && < 2.1,@@ -95,6 +95,7 @@     Patat.Theme     Patat.Transition     Patat.Transition.Internal+    Patat.Transition.Dissolve     Patat.Transition.SlideLeft    Other-modules: