{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Patat.Presentation.Interactive
( PresentationCommand (..)
, readPresentationCommand
, UpdatedPresentation (..)
, updatePresentation
) where
import Data.Char (isDigit)
import Patat.Presentation.Instruction (Var)
import Patat.Presentation.Internal
import Patat.Presentation.Read
import qualified System.IO as IO
import qualified Text.Pandoc as Pandoc
import Text.Read (readMaybe)
data PresentationCommand
= Exit
| Forward
| Backward
| SkipForward
| SkipBackward
| First
| Last
| Reload
| Seek Int
| UpdateVar Var [Pandoc.Block]
| UnknownCommand String
deriving (PresentationCommand -> PresentationCommand -> Bool
(PresentationCommand -> PresentationCommand -> Bool)
-> (PresentationCommand -> PresentationCommand -> Bool)
-> Eq PresentationCommand
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PresentationCommand -> PresentationCommand -> Bool
== :: PresentationCommand -> PresentationCommand -> Bool
$c/= :: PresentationCommand -> PresentationCommand -> Bool
/= :: PresentationCommand -> PresentationCommand -> Bool
Eq, Int -> PresentationCommand -> ShowS
[PresentationCommand] -> ShowS
PresentationCommand -> String
(Int -> PresentationCommand -> ShowS)
-> (PresentationCommand -> String)
-> ([PresentationCommand] -> ShowS)
-> Show PresentationCommand
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PresentationCommand -> ShowS
showsPrec :: Int -> PresentationCommand -> ShowS
$cshow :: PresentationCommand -> String
show :: PresentationCommand -> String
$cshowList :: [PresentationCommand] -> ShowS
showList :: [PresentationCommand] -> ShowS
Show)
readPresentationCommand :: IO.Handle -> IO PresentationCommand
readPresentationCommand :: Handle -> IO PresentationCommand
readPresentationCommand Handle
h = do
String
k <- IO String
readKeys
case String
k of
String
"q" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Exit
String
"\n" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Forward
String
"\DEL" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Backward
String
"h" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Backward
String
"j" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
SkipForward
String
"k" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
SkipBackward
String
"l" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Forward
String
"\ESC[C" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Forward
String
"\ESC[D" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Backward
String
"\ESC[B" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
SkipForward
String
"\ESC[A" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
SkipBackward
String
"\ESC[6" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Forward
String
"\ESC[5" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Backward
String
"0" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
First
String
"G" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Last
String
"r" -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return PresentationCommand
Reload
String
_ | Just Int
n <- String -> Maybe Int
forall a. Read a => String -> Maybe a
readMaybe String
k -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> PresentationCommand
Seek Int
n)
String
_ -> PresentationCommand -> IO PresentationCommand
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> PresentationCommand
UnknownCommand String
k)
where
readKeys :: IO String
readKeys :: IO String
readKeys = do
Char
c0 <- Handle -> IO Char
IO.hGetChar Handle
h
case Char
c0 of
Char
'\ESC' -> do
Char
c1 <- Handle -> IO Char
IO.hGetChar Handle
h
case Char
c1 of
Char
'[' -> do
Char
c2 <- Handle -> IO Char
IO.hGetChar Handle
h
String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char
c0, Char
c1, Char
c2]
Char
_ -> String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char
c0, Char
c1]
Char
_ | Char -> Bool
isDigit Char
c0 Bool -> Bool -> Bool
&& Char
c0 Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/= Char
'0' -> (Char
c0 Char -> ShowS
forall a. a -> [a] -> [a]
:) ShowS -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO String
readDigits
Char
_ -> String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char
c0]
readDigits :: IO String
readDigits :: IO String
readDigits = do
Char
c <- Handle -> IO Char
IO.hGetChar Handle
h
if Char -> Bool
isDigit Char
c then (Char
c Char -> ShowS
forall a. a -> [a] -> [a]
:) ShowS -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO String
readDigits else String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char
c]
data UpdatedPresentation
= UpdatedPresentation !Presentation
| ExitedPresentation
| ErroredPresentation String
updatePresentation
:: PresentationCommand -> Presentation -> IO UpdatedPresentation
updatePresentation :: PresentationCommand -> Presentation -> IO UpdatedPresentation
updatePresentation PresentationCommand
cmd Presentation
presentation = case PresentationCommand
cmd of
PresentationCommand
Exit -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure UpdatedPresentation
ExitedPresentation
PresentationCommand
Forward -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ (Index -> Index) -> UpdatedPresentation
goToSlide ((Index -> Index) -> UpdatedPresentation)
-> (Index -> Index) -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ \(Int
s, Int
f) -> (Int
s, Int
f Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
PresentationCommand
Backward -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ (Index -> Index) -> UpdatedPresentation
goToSlide ((Index -> Index) -> UpdatedPresentation)
-> (Index -> Index) -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ \(Int
s, Int
f) -> (Int
s, Int
f Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
PresentationCommand
SkipForward -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ (Index -> Index) -> UpdatedPresentation
goToSlide ((Index -> Index) -> UpdatedPresentation)
-> (Index -> Index) -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ \(Int
s, Int
_) -> (Int
s Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
10, Int
0)
PresentationCommand
SkipBackward -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ (Index -> Index) -> UpdatedPresentation
goToSlide ((Index -> Index) -> UpdatedPresentation)
-> (Index -> Index) -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ \(Int
s, Int
_) -> (Int
s Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
10, Int
0)
PresentationCommand
First -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ (Index -> Index) -> UpdatedPresentation
goToSlide ((Index -> Index) -> UpdatedPresentation)
-> (Index -> Index) -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ \Index
_ -> (Int
0, Int
0)
PresentationCommand
Last -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ (Index -> Index) -> UpdatedPresentation
goToSlide ((Index -> Index) -> UpdatedPresentation)
-> (Index -> Index) -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ \Index
_ -> (Presentation -> Int
numSlides Presentation
presentation, Int
0)
Seek Int
n -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ (Index -> Index) -> UpdatedPresentation
goToSlide ((Index -> Index) -> UpdatedPresentation)
-> (Index -> Index) -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ \Index
_ -> (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int
0)
PresentationCommand
Reload -> IO UpdatedPresentation
reloadPresentation
UnknownCommand String
_ -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ Presentation -> UpdatedPresentation
UpdatedPresentation Presentation
presentation
UpdateVar Var
v [Block]
b -> UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ Presentation -> UpdatedPresentation
UpdatedPresentation (Presentation -> UpdatedPresentation)
-> Presentation -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ Var -> [Block] -> Presentation -> Presentation
updateVar Var
v [Block]
b Presentation
presentation
where
numSlides :: Presentation -> Int
numSlides :: Presentation -> Int
numSlides Presentation
pres = Seq Slide -> Int
forall a. Seq a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Presentation -> Seq Slide
pSlides Presentation
pres)
clip :: Index -> Presentation -> Index
clip :: Index -> Presentation -> Index
clip (Int
slide, Int
fragment) Presentation
pres
| Int
slide Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Presentation -> Int
numSlides Presentation
pres = (Presentation -> Int
numSlides Presentation
pres Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int
lastFragments Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
| Int
slide Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = (Int
0, Int
0)
| Int
fragment Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int -> Int
numFragments' Int
slide =
if Int
slide Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Presentation -> Int
numSlides Presentation
pres
then (Int
slide, Int
lastFragments Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
else (Int
slide Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1, Int
0)
| Int
fragment Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 =
if Int
slide Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
0
then (Int
slide Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1, Int -> Int
numFragments' (Int
slide Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
else (Int
slide, Int
0)
| Bool
otherwise = (Int
slide, Int
fragment)
where
numFragments' :: Int -> Int
numFragments' Int
s = Int -> (Slide -> Int) -> Maybe Slide -> Int
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
1 Slide -> Int
numFragments (Int -> Presentation -> Maybe Slide
getSlide Int
s Presentation
pres)
lastFragments :: Int
lastFragments = Int -> Int
numFragments' (Presentation -> Int
numSlides Presentation
pres Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
goToSlide :: (Index -> Index) -> UpdatedPresentation
goToSlide :: (Index -> Index) -> UpdatedPresentation
goToSlide Index -> Index
f = Presentation -> UpdatedPresentation
UpdatedPresentation (Presentation -> UpdatedPresentation)
-> Presentation -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ Presentation
presentation
{ pActiveFragment = clip (f $ pActiveFragment presentation) presentation
}
reloadPresentation :: IO UpdatedPresentation
reloadPresentation = do
Either String Presentation
errOrPres <- VarGen -> String -> IO (Either String Presentation)
readPresentation (Presentation -> VarGen
pVarGen Presentation
presentation) (Presentation -> String
pFilePath Presentation
presentation)
UpdatedPresentation -> IO UpdatedPresentation
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (UpdatedPresentation -> IO UpdatedPresentation)
-> UpdatedPresentation -> IO UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ case Either String Presentation
errOrPres of
Left String
err -> String -> UpdatedPresentation
ErroredPresentation String
err
Right Presentation
pres -> Presentation -> UpdatedPresentation
UpdatedPresentation (Presentation -> UpdatedPresentation)
-> Presentation -> UpdatedPresentation
forall a b. (a -> b) -> a -> b
$ Presentation
pres
{ pActiveFragment = clip (pActiveFragment presentation) pres
}