-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor implementation of fragments.
Fragments deal with how content is shown piece by piece. For example, if we have the slide: Foo . . . Bar There are two fragments. First, only `Foo` is visible. When the user goes to the next fragment, `Foo` and `Bar` are both visible. The first implementation of fragments in patat would compute the state of all the visible items. In this case, that would be: 1. `[Foo]` 2. `[Foo, Bar]` This does not work elegantly if you want another pass to add further fragments: you now need to split `Foo` in multiple places (and the thunk is no longer shared). This PR refactors this to use "instructions" over the slide content. For the example, these instructions would be: 1. `Append [Foo]` 2. `Pause` 3. `Append [Bar]` The `Pause`s are explicit, and indicate how many fragments are present. There are more constructors, for manipulation of lists which is necessary if nested lists are shown incrementally. This all for allows much nicer manipulation of the fragments, which in turn is useful for #52.
- Loading branch information
Showing
7 changed files
with
193 additions
and
142 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
-------------------------------------------------------------------------------- | ||
-- | The Pandoc AST is not extensible, so we need to use another way to model | ||
-- different parts of slides that we want to appear bit by bit. | ||
-- | ||
-- We do this by modelling a slide as a list of instructions, that manipulate | ||
-- the contents on a slide in a (for now) very basic way. | ||
module Patat.Presentation.Instruction | ||
( Instructions | ||
, fromList | ||
, toList | ||
|
||
, Instruction (..) | ||
, numFragments | ||
|
||
, Fragment (..) | ||
, renderFragment | ||
) where | ||
|
||
import qualified Text.Pandoc as Pandoc | ||
|
||
newtype Instructions a = Instructions [Instruction a] deriving (Show) | ||
|
||
-- A smart constructor that guarantees some invariants: | ||
-- | ||
-- * No consecutive pauses. | ||
-- * All pauses moved to the top level. | ||
-- * No pauses at the end. | ||
fromList :: [Instruction a] -> Instructions a | ||
fromList = Instructions . go | ||
where | ||
go instrs = case break (not . isPause) instrs of | ||
(_, []) -> [] | ||
(_ : _, remainder) -> Pause : go remainder | ||
([], x : remainder) -> x : go remainder | ||
|
||
toList :: Instructions a -> [Instruction a] | ||
toList (Instructions xs) = xs | ||
|
||
data Instruction a | ||
-- Pause. | ||
= Pause | ||
-- Append items. | ||
| Append [a] | ||
-- Modify the last block with the provided instruction. | ||
| ModifyLast (Instruction a) | ||
deriving (Show) | ||
|
||
isPause :: Instruction a -> Bool | ||
isPause Pause = True | ||
isPause (Append _) = False | ||
isPause (ModifyLast i) = isPause i | ||
|
||
numPauses :: Instructions a -> Int | ||
numPauses (Instructions xs) = length $ filter isPause xs | ||
|
||
numFragments :: Instructions a -> Int | ||
numFragments = succ . numPauses | ||
|
||
newtype Fragment = Fragment [Pandoc.Block] deriving (Show) | ||
|
||
renderFragment :: Int -> Instructions Pandoc.Block -> Fragment | ||
renderFragment = \n (Instructions instrs) -> Fragment $ go [] n instrs | ||
where | ||
go acc _ [] = acc | ||
go acc n (Pause : instrs) = if n <= 0 then acc else go acc (n - 1) instrs | ||
go acc n (instr : instrs) = go (goBlocks instr acc) n instrs | ||
|
||
goBlocks :: Instruction Pandoc.Block -> [Pandoc.Block] -> [Pandoc.Block] | ||
goBlocks Pause xs = xs | ||
goBlocks (Append ys) xs = xs ++ ys | ||
goBlocks (ModifyLast f) xs | ||
| null xs = xs -- Shouldn't happen unless instructions are malformed. | ||
| otherwise = modifyLast (goBlock f) xs | ||
|
||
goBlock :: Instruction Pandoc.Block -> Pandoc.Block -> Pandoc.Block | ||
goBlock Pause x = x | ||
goBlock (Append ys) block = case block of | ||
-- We can only append to a few specific block types for now. | ||
Pandoc.BulletList xs -> Pandoc.BulletList $ xs ++ [ys] | ||
Pandoc.OrderedList attr xs -> Pandoc.OrderedList attr $ xs ++ [ys] | ||
_ -> block | ||
goBlock (ModifyLast f) block = case block of | ||
-- We can only modify the last content of a few specific block types for | ||
-- now. | ||
Pandoc.BulletList xs -> Pandoc.BulletList $ modifyLast (goBlocks f) xs | ||
Pandoc.OrderedList attr xs -> | ||
Pandoc.OrderedList attr $ modifyLast (goBlocks f) xs | ||
_ -> block | ||
|
||
modifyLast :: (a -> a) -> [a] -> [a] | ||
modifyLast f (x : y : zs) = x : modifyLast f (y : zs) | ||
modifyLast f (x : []) = [f x] | ||
modifyLast _ [] = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.