patat 0.10.1.1 → 0.11.0.0
raw patch · 12 files changed
+414/−168 lines, 12 filesdep ~aesondep ~bytestringdep ~containersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, bytestring, containers, filepath, tasty, text
API changes (from Hackage documentation)
- Patat.PrettyPrint: NotTrimmable :: !a -> Trimmable a
- Patat.PrettyPrint: Trimmable :: !a -> Trimmable a
- Patat.PrettyPrint: data Trimmable a
- Patat.PrettyPrint.Internal: NotTrimmable :: !a -> Trimmable a
- Patat.PrettyPrint.Internal: Trimmable :: !a -> Trimmable a
- Patat.PrettyPrint.Internal: data Trimmable a
- Patat.PrettyPrint.Internal: instance Data.Foldable.Foldable Patat.PrettyPrint.Internal.Trimmable
- Patat.PrettyPrint.Internal: instance Data.Traversable.Traversable Patat.PrettyPrint.Internal.Trimmable
- Patat.PrettyPrint.Internal: instance GHC.Base.Functor Patat.PrettyPrint.Internal.Trimmable
+ Patat.Presentation.Display.Internal: [dsMargins] :: DisplaySettings -> !Margins
+ Patat.Presentation.Display.Internal: [dsSize] :: DisplaySettings -> !Size
+ Patat.Presentation.Display.Internal: [dsWrap] :: DisplaySettings -> !Wrap
+ Patat.Presentation.Internal: [evalWrap] :: EvalSettings -> !EvalSettingsWrap
+ Patat.Presentation.Settings: Auto :: AutoOr a
+ Patat.Presentation.Settings: AutoWrap :: Wrap
+ Patat.Presentation.Settings: EvalWrapCode :: EvalSettingsWrap
+ Patat.Presentation.Settings: EvalWrapRaw :: EvalSettingsWrap
+ Patat.Presentation.Settings: EvalWrapRawInline :: EvalSettingsWrap
+ Patat.Presentation.Settings: NoWrap :: Wrap
+ Patat.Presentation.Settings: NotAuto :: a -> AutoOr a
+ Patat.Presentation.Settings: WrapAt :: Int -> Wrap
+ Patat.Presentation.Settings: [evalWrap] :: EvalSettings -> !EvalSettingsWrap
+ Patat.Presentation.Settings: data AutoOr a
+ Patat.Presentation.Settings: data EvalSettingsWrap
+ Patat.Presentation.Settings: data Wrap
+ Patat.Presentation.Settings: instance Data.Aeson.Types.FromJSON.FromJSON Patat.Presentation.Settings.EvalSettingsWrap
+ Patat.Presentation.Settings: instance Data.Aeson.Types.FromJSON.FromJSON Patat.Presentation.Settings.Wrap
+ Patat.Presentation.Settings: instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Patat.Presentation.Settings.AutoOr a)
+ Patat.Presentation.Settings: instance GHC.Show.Show Patat.Presentation.Settings.EvalSettingsWrap
+ Patat.Presentation.Settings: instance GHC.Show.Show Patat.Presentation.Settings.Wrap
+ Patat.Presentation.Settings: instance GHC.Show.Show a => GHC.Show.Show (Patat.Presentation.Settings.AutoOr a)
+ Patat.PrettyPrint: Indentation :: Int -> a -> Indentation a
+ Patat.PrettyPrint: data Indentation a
+ Patat.PrettyPrint: deindent :: Doc -> Doc
+ Patat.PrettyPrint.Internal: Indentation :: Int -> a -> Indentation a
+ Patat.PrettyPrint.Internal: data Indentation a
+ Patat.PrettyPrint.Internal: instance Data.Foldable.Foldable Patat.PrettyPrint.Internal.Indentation
+ Patat.PrettyPrint.Internal: instance Data.Traversable.Traversable Patat.PrettyPrint.Internal.Indentation
+ Patat.PrettyPrint.Internal: instance GHC.Base.Functor Patat.PrettyPrint.Internal.Indentation
- Patat.Presentation: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe MarginSettings -> !Maybe Bool -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe SpeakerNotesSettings -> !Maybe TransitionSettings -> PresentationSettings
+ Patat.Presentation: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe MarginSettings -> !Maybe Wrap -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe SpeakerNotesSettings -> !Maybe TransitionSettings -> PresentationSettings
- Patat.Presentation: [psWrap] :: PresentationSettings -> !Maybe Bool
+ Patat.Presentation: [psWrap] :: PresentationSettings -> !Maybe Wrap
- Patat.Presentation.Display.Internal: DisplaySettings :: !Theme -> !SyntaxMap -> DisplaySettings
+ Patat.Presentation.Display.Internal: DisplaySettings :: !Size -> !Wrap -> !Margins -> !Theme -> !SyntaxMap -> DisplaySettings
- Patat.Presentation.Internal: EvalSettings :: !Text -> !Bool -> !Bool -> EvalSettings
+ Patat.Presentation.Internal: EvalSettings :: !Text -> !Bool -> !Bool -> !EvalSettingsWrap -> EvalSettings
- Patat.Presentation.Internal: MarginSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> MarginSettings
+ Patat.Presentation.Internal: MarginSettings :: !Maybe (AutoOr (FlexibleNum Int)) -> !Maybe (AutoOr (FlexibleNum Int)) -> !Maybe (AutoOr (FlexibleNum Int)) -> MarginSettings
- Patat.Presentation.Internal: Margins :: Int -> Int -> Int -> Margins
+ Patat.Presentation.Internal: Margins :: AutoOr Int -> AutoOr Int -> AutoOr Int -> Margins
- Patat.Presentation.Internal: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe MarginSettings -> !Maybe Bool -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe SpeakerNotesSettings -> !Maybe TransitionSettings -> PresentationSettings
+ Patat.Presentation.Internal: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe MarginSettings -> !Maybe Wrap -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe SpeakerNotesSettings -> !Maybe TransitionSettings -> PresentationSettings
- Patat.Presentation.Internal: [mLeft] :: Margins -> Int
+ Patat.Presentation.Internal: [mLeft] :: Margins -> AutoOr Int
- Patat.Presentation.Internal: [mRight] :: Margins -> Int
+ Patat.Presentation.Internal: [mRight] :: Margins -> AutoOr Int
- Patat.Presentation.Internal: [mTop] :: Margins -> Int
+ Patat.Presentation.Internal: [mTop] :: Margins -> AutoOr Int
- Patat.Presentation.Internal: [msLeft] :: MarginSettings -> !Maybe (FlexibleNum Int)
+ Patat.Presentation.Internal: [msLeft] :: MarginSettings -> !Maybe (AutoOr (FlexibleNum Int))
- Patat.Presentation.Internal: [msRight] :: MarginSettings -> !Maybe (FlexibleNum Int)
+ Patat.Presentation.Internal: [msRight] :: MarginSettings -> !Maybe (AutoOr (FlexibleNum Int))
- Patat.Presentation.Internal: [msTop] :: MarginSettings -> !Maybe (FlexibleNum Int)
+ Patat.Presentation.Internal: [msTop] :: MarginSettings -> !Maybe (AutoOr (FlexibleNum Int))
- Patat.Presentation.Internal: [psWrap] :: PresentationSettings -> !Maybe Bool
+ Patat.Presentation.Internal: [psWrap] :: PresentationSettings -> !Maybe Wrap
- Patat.Presentation.Settings: EvalSettings :: !Text -> !Bool -> !Bool -> EvalSettings
+ Patat.Presentation.Settings: EvalSettings :: !Text -> !Bool -> !Bool -> !EvalSettingsWrap -> EvalSettings
- Patat.Presentation.Settings: MarginSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> MarginSettings
+ Patat.Presentation.Settings: MarginSettings :: !Maybe (AutoOr (FlexibleNum Int)) -> !Maybe (AutoOr (FlexibleNum Int)) -> !Maybe (AutoOr (FlexibleNum Int)) -> MarginSettings
- Patat.Presentation.Settings: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe MarginSettings -> !Maybe Bool -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe SpeakerNotesSettings -> !Maybe TransitionSettings -> PresentationSettings
+ Patat.Presentation.Settings: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe MarginSettings -> !Maybe Wrap -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe SpeakerNotesSettings -> !Maybe TransitionSettings -> PresentationSettings
- Patat.Presentation.Settings: [msLeft] :: MarginSettings -> !Maybe (FlexibleNum Int)
+ Patat.Presentation.Settings: [msLeft] :: MarginSettings -> !Maybe (AutoOr (FlexibleNum Int))
- Patat.Presentation.Settings: [msRight] :: MarginSettings -> !Maybe (FlexibleNum Int)
+ Patat.Presentation.Settings: [msRight] :: MarginSettings -> !Maybe (AutoOr (FlexibleNum Int))
- Patat.Presentation.Settings: [msTop] :: MarginSettings -> !Maybe (FlexibleNum Int)
+ Patat.Presentation.Settings: [msTop] :: MarginSettings -> !Maybe (AutoOr (FlexibleNum Int))
- Patat.Presentation.Settings: [psWrap] :: PresentationSettings -> !Maybe Bool
+ Patat.Presentation.Settings: [psWrap] :: PresentationSettings -> !Maybe Wrap
- Patat.PrettyPrint: indent :: Trimmable Doc -> Trimmable Doc -> Doc -> Doc
+ Patat.PrettyPrint: indent :: Indentation Doc -> Indentation Doc -> Doc -> Doc
- Patat.PrettyPrint.Internal: Indent :: LineBuffer -> LineBuffer -> d -> DocE d
+ Patat.PrettyPrint.Internal: Indent :: Indentation [Chunk] -> Indentation [Chunk] -> d -> DocE d
- Patat.PrettyPrint.Internal: [indentFirstLine] :: DocE d -> LineBuffer
+ Patat.PrettyPrint.Internal: [indentFirstLine] :: DocE d -> Indentation [Chunk]
- Patat.PrettyPrint.Internal: [indentOtherLines] :: DocE d -> LineBuffer
+ Patat.PrettyPrint.Internal: [indentOtherLines] :: DocE d -> Indentation [Chunk]
Files
- CHANGELOG.md +68/−0
- README.md +75/−25
- lib/Patat/Eval.hs +10/−4
- lib/Patat/Presentation/Display.hs +75/−55
- lib/Patat/Presentation/Display/CodeBlock.hs +1/−1
- lib/Patat/Presentation/Display/Internal.hs +10/−4
- lib/Patat/Presentation/Display/Table.hs +3/−1
- lib/Patat/Presentation/Internal.hs +7/−5
- lib/Patat/Presentation/Settings.hs +60/−16
- lib/Patat/PrettyPrint.hs +28/−4
- lib/Patat/PrettyPrint/Internal.hs +54/−31
- patat.cabal +23/−22
CHANGELOG.md view
@@ -1,5 +1,73 @@ # Changelog +## 0.11.0.0 (2024-02-14)++ * Support wrapping at a specific column (#164)++ Using a specific wrap column, e.g. `wrap: 60`, works well together with+ `auto` margins (see below).++ * Support centering content with auto margins (#164)++ Configuration is done through the existing `margins` setting.++ To vertically center content, use `top: auto`. To horizontally center+ content, use both `left: auto` and `right: auto`. For example:++ ```markdown+ ---+ title: Centered presentation+ author: John Doe+ patat:+ margins:+ left: auto+ right: auto+ top: auto+ ...++ Hello world+ ```++ Setting `wrap: true` is recommended when vertically centering content if+ there are any lines that are too wide for the terminal.++## 0.10.2.0 (2023-11-25)++ * Add eval.wrap option++ This adds a new `wrap` section to the `eval` configuration.++ By default, the output is wrapped in a code block again with the original syntax+ highlighting. You can customize this behaviour by setting `wrap` to:++ * `code`: the default setting.+ * `raw`: no formatting applied.+ * `rawInline`: no formatting applied and no trailing newline.++ You can use `rawInline` to draw graphics. In order to do that, for example,+ we could configure `kitten` code snippets to evaluate using [Kitty]'s+ command `icat`. This uses the `rawInline` code setting to ensure that the+ resulting output is not wrapped in a code block, and the `fragment` and+ `replace` settings immediately replace the snippet:++ ---+ patat:+ eval:+ kitten:+ command: sed 's/^/kitten /' | bash+ replace: true+ fragment: false+ wrap: rawInline+ ...++ See, for example:++ ```kitten+ icat --align left dank-meme.jpg+ ```++[Kitty]: https://sw.kovidgoyal.net/kitty/+ ## 0.10.1.1 (2023-10-18) * Fix issues in text wrapping when starting a transition
README.md view
@@ -18,8 +18,8 @@ - [Transition effects](#transitions). - Supports [smart slide splitting](#input-format). - [Auto advancing](#auto-advancing) with configurable delay.-- Optionally [re-wrapping](#line-wrapping) text to terminal width with proper- indentation.+- [Centering](#centering) and [re-wrapping](#line-wrapping) text to terminal+ width with proper indentation. - [Theming](#theming) support including 24-bit RGB. - Hihgly portable as it only requires an ANSI terminal as opposed to something like `ncurses`.@@ -34,8 +34,7 @@ - [Table of Contents](#table-of-contents) - [Installation](#installation)- - [Pre-built-packages](#pre-built-packages)- - [Homebrew](#homebrew)+ - [Pre-built packages](#pre-built-packages) - [From source](#from-source) - [Running](#running) - [Options](#options)@@ -61,31 +60,23 @@ Installation ------------ -### Pre-built-packages--- Archlinux: <https://aur.archlinux.org/packages/patat-bin>-- Debian: <https://packages.debian.org/unstable/patat>-- Ubuntu: <https://packages.ubuntu.com/bionic/patat>-- openSUSE: <https://build.opensuse.org/package/show/openSUSE:Factory:ARM/patat>-- Fedora: <https://src.fedoraproject.org/rpms/patat>-- NixOS: <https://search.nixos.org/packages?show=haskellPackages.patat>+### Pre-built packages -You can also find generic Linux and Mac OS binaries here:-<https://github.com/jaspervdj/patat/releases>.+Linux: -### Homebrew+- [Archlinux](https://aur.archlinux.org/packages/patat-bin)+- [Debian](https://packages.debian.org/unstable/patat)+- [Fedora](https://src.fedoraproject.org/rpms/patat)+- [NixOS](https://search.nixos.org/packages?show=haskellPackages.patat)+- [openSUSE](https://build.opensuse.org/package/show/openSUSE:Factory:ARM/patat)+- [Ubuntu](https://packages.ubuntu.com/bionic/patat) -[Homebrew] packages are offered by a-[third-party repository](https://github.com/nicholasdille/homebrew-tap).-**Unfortunately this repo has been archived, and the latest version that can-be installed from there is v0.8.7.0**. If you would like to contribute here,-please contact us by opening an issue.+Mac OS: -1. Run `brew tap nicholasdille/tap`.-2. Run `brew install patat-bin` to receive the official binaries or- `brew install patat` for pre-built ("bottled") binaries.+- [Homebrew](https://formulae.brew.sh/formula/patat) -[Homebrew]: https://brew.sh/+You can also find generic Linux and Mac OS binaries here:+<https://github.com/jaspervdj/patat/releases>. ### From source @@ -310,7 +301,8 @@ ### Line wrapping Line wrapping can be enabled by setting `wrap: true` in the configuration. This-will re-wrap all lines to fit the terminal width better.+will re-wrap all lines to fit the terminal width better. You can also ask patat+to wrap at a specific column using e.g. `wrap: 60`. ### Margins @@ -342,6 +334,28 @@ By default, the `left` and `right` margin are set to 0, and the `top` margin is set to 1. +#### Centering++To vertically center content, use `top: auto`. To horizontally center content,+use both `left: auto` and `right: auto`. For example:++```markdown+---+title: Centered presentation+author: John Doe+patat:+ margins:+ left: auto+ right: auto+ top: auto+...++Hello world+```++[Line wrapping](#line-wrapping) is recommended when vertically centering content+if there are any lines that are too wide for the terminal.+ ### Auto advancing By setting `autoAdvanceDelay` to a number of seconds, `patat` will automatically@@ -595,6 +609,8 @@ ### Images +#### Native Images support+ `patat-0.8.0.0` and newer include images support for some terminal emulators. ```markdown@@ -633,6 +649,33 @@ path: '/home/jasper/.local/bin/w3mimgdisplay' ``` +#### Images using Evaluation++Rather than using the built-in image support, you can also use programs that+write ASCII escape codes directly to the screen with+[code evaluation](#evaluating-code).++In order to do that, for example, we could configure `kitten` code snippets+to evaluate using [Kitty]'s command `icat`. This uses the `rawInline` code+setting to ensure that the resulting output is not wrapped in a code block,+and the `fragment` and `replace` settings immediately replace the snippet.++ ---+ patat:+ eval:+ kitten:+ command: sed 's/^/kitten /' | bash+ replace: true+ fragment: false+ wrap: rawInline+ ...++ See, for example:++ ```kitten+ icat --align left dank-meme.jpg+ ```+ ### Breadcrumbs By default, `patat` will print a breadcrumbs-style header, e.g.:@@ -669,6 +712,7 @@ command: irb --noecho --noverbose fragment: true # Optional replace: false # Optional+ wrap: code # Optional ... Here is an example of a code block that is evaluated:@@ -690,6 +734,12 @@ between showing the original code block and the output. Defaults to `true`. - `replace`: Remove the original code block and replace it with the output rather than appending the output in a new code block. Defaults to `false`.+ - `wrap`: By default, the output is wrapped in a code block again with the+ original syntax highlighting. You can customize this behaviour by setting+ `wrap` to:+ * `code`: the default setting.+ * `raw`: no formatting applied.+ * `rawInline`: no formatting applied and no trailing newline. Setting `fragment: false` and `replace: true` offers a way to "filter" code blocks, which can be used to render ASCII graphics.
lib/Patat/Eval.hs view
@@ -15,6 +15,7 @@ import qualified Data.Text.IO as T import Patat.Presentation.Instruction import Patat.Presentation.Internal+import Patat.Presentation.Settings import System.Exit (ExitCode (..)) import qualified System.IO as IO import System.IO.Unsafe (unsafeInterleaveIO)@@ -70,15 +71,20 @@ ExitFailure i -> evalCommand <> ": exit code " <> T.pack (show i) <> "\n" <> erStderr+ let fmt = "eval"+ blocks = case evalWrap of+ EvalWrapCode -> [Pandoc.CodeBlock attr out]+ EvalWrapRaw -> [Pandoc.RawBlock fmt out]+ EvalWrapRawInline -> [Pandoc.Plain [Pandoc.RawInline fmt out]] pure $ case (evalFragment, evalReplace) of- (False, True) -> [Append [Pandoc.CodeBlock attr out]]- (False, False) -> [Append [orig, Pandoc.CodeBlock attr out]]+ (False, True) -> [Append blocks]+ (False, False) -> [Append (orig : blocks)] (True, True) -> [ Append [orig], Pause- , Delete, Append [Pandoc.CodeBlock attr out]+ , Delete, Append blocks ] (True, False) ->- [Append [orig], Pause, Append [Pandoc.CodeBlock attr out]]+ [Append [orig], Pause, Append blocks] | _ : _ : _ <- lookupSettings classes settings = let msg = "patat eval matched multiple settings for " <> T.intercalate "," classes in
lib/Patat/Presentation/Display.hs view
@@ -23,6 +23,7 @@ import Patat.Presentation.Display.Internal import Patat.Presentation.Display.Table import Patat.Presentation.Internal+import Patat.Presentation.Settings import Patat.PrettyPrint ((<$$>), (<+>)) import qualified Patat.PrettyPrint as PP import Patat.Size@@ -41,7 +42,7 @@ -- | Display something within the presentation borders that draw the title and -- the active slide number and so on. displayWithBorders- :: Size -> Presentation -> (Size -> DisplaySettings -> PP.Doc) -> PP.Doc+ :: Size -> Presentation -> (DisplaySettings -> PP.Doc) -> PP.Doc displayWithBorders (Size rows columns) pres@Presentation {..} f = (if null title then mempty@@ -49,18 +50,20 @@ let titleRemainder = columns - titleWidth - titleOffset wrappedTitle = PP.spaces titleOffset <> PP.string title <> PP.spaces titleRemainder in borders wrappedTitle <> PP.hardline) <>- mconcat (replicate topMargin PP.hardline) <>- formatWith settings (f canvasSize ds) <> PP.hardline <>+ f ds <> PP.hardline <> PP.goToLine (rows - 2) <> borders (PP.space <> PP.string author <> middleSpaces <> PP.string active <> PP.space) <> PP.hardline where -- Get terminal width/title- (sidx, _) = pActiveFragment- settings = (activeSettings pres) {psColumns = Just $ A.FlexibleNum columns}- ds = DisplaySettings- { dsTheme = fromMaybe Theme.defaultTheme (psTheme settings)- , dsSyntaxMap = pSyntaxMap+ (sidx, _) = pActiveFragment+ settings = activeSettings pres+ ds = DisplaySettings+ { dsSize = canvasSize+ , dsWrap = fromMaybe NoWrap $ psWrap settings+ , dsMargins = margins settings+ , dsTheme = fromMaybe Theme.defaultTheme (psTheme settings)+ , dsSyntaxMap = pSyntaxMap } -- Compute title.@@ -82,8 +85,7 @@ borders = themed ds themeBorders -- Room left for content- topMargin = mTop $ margins settings- canvasSize = Size (rows - 2 - topMargin) columns+ canvasSize = Size (rows - 3) columns -- Compute footer. active@@ -105,18 +107,12 @@ , Just image <- onlyImage fragment -> DisplayImage $ T.unpack image Just (ActiveContent fragment) -> DisplayDoc $- displayWithBorders size pres $ \_canvasSize theme ->+ displayWithBorders size pres $ \theme -> prettyFragment theme fragment Just (ActiveTitle block) -> DisplayDoc $- displayWithBorders size pres $ \canvasSize theme ->- let pblock = prettyBlock theme block- (prows, pcols) = PP.dimensions pblock- Margins {..} = margins (activeSettings pres)- offsetRow = (sRows canvasSize `div` 2) - (prows `div` 2)- offsetCol = ((sCols canvasSize - mLeft - mRight) `div` 2) - (pcols `div` 2)- spaces = PP.NotTrimmable $ PP.spaces offsetCol in- mconcat (replicate (offsetRow - 3) PP.hardline) <$$>- PP.indent spaces spaces pblock+ displayWithBorders size pres $ \ds ->+ let auto = Margins {mTop = Auto, mRight = Auto, mLeft = Auto} in+ prettyFragment ds {dsMargins = auto} $ Fragment [block] where -- Check if the fragment consists of "just a single image". Discard@@ -132,11 +128,10 @@ -- | Displays an error in the place of the presentation. This is useful if we -- want to display an error but keep the presentation running. displayPresentationError :: Size -> Presentation -> String -> PP.Doc-displayPresentationError size pres err =- displayWithBorders size pres $ \_ ds ->- themed ds themeStrong "Error occurred in the presentation:" <$$>- "" <$$>- (PP.string err)+displayPresentationError size pres err = displayWithBorders size pres $ \ds ->+ themed ds themeStrong "Error occurred in the presentation:" <$$>+ "" <$$>+ (PP.string err) --------------------------------------------------------------------------------@@ -149,11 +144,10 @@ dumpSlide :: Int -> [PP.Doc] dumpSlide i = do slide <- maybeToList $ getSlide i pres- map (formatWith (getSettings i pres)) $- dumpComment slide <> L.intercalate ["{fragment}"]- [ dumpFragment (i, j)- | j <- [0 .. numFragments slide - 1]- ]+ dumpComment slide <> L.intercalate ["{fragment}"]+ [ dumpFragment (i, j)+ | j <- [0 .. numFragments slide - 1]+ ] dumpComment :: Slide -> [PP.Doc] dumpComment slide = do@@ -178,26 +172,51 @@ ---------------------------------------------------------------------------------formatWith :: PresentationSettings -> PP.Doc -> PP.Doc-formatWith ps = wrap . indent- where- Margins {..} = margins ps- wrap = case (psWrap ps, psColumns ps) of- (Just True, Just (A.FlexibleNum col)) -> PP.wrapAt (Just $ col - mRight)- _ -> id- spaces = PP.NotTrimmable $ PP.spaces mLeft- indent = PP.indent spaces spaces----------------------------------------------------------------------------------- prettyFragment :: DisplaySettings -> Fragment -> PP.Doc-prettyFragment ds (Fragment blocks) =- prettyBlocks ds blocks <>+prettyFragment ds (Fragment blocks) = vertical $+ PP.vcat (map (horizontal . prettyBlock ds) blocks) <> case prettyReferences ds blocks of [] -> mempty- refs -> PP.hardline <> PP.vcat refs+ refs -> PP.hardline <> PP.vcat (map horizontal refs)+ where+ Size rows columns = dsSize ds+ Margins {..} = dsMargins ds + vertical doc0 =+ mconcat (replicate top PP.hardline) <> doc0+ where+ top = case mTop of+ Auto -> let (r, _) = PP.dimensions doc0 in (rows - r) `div` 2+ NotAuto x -> x + horizontal = horizontalIndent . horizontalWrap++ horizontalIndent doc0 = PP.indent indentation indentation doc1+ where+ doc1 = case (mLeft, mRight) of+ (Auto, Auto) -> PP.deindent doc0+ _ -> doc0+ (_, dcols) = PP.dimensions doc1+ left = case mLeft of+ NotAuto x -> x+ Auto -> case mRight of+ NotAuto _ -> 0+ Auto -> (columns - dcols) `div` 2+ indentation = PP.Indentation left mempty++ horizontalWrap doc0 = case dsWrap ds of+ NoWrap -> doc0+ AutoWrap -> PP.wrapAt (Just $ columns - right - left) doc0+ WrapAt col -> PP.wrapAt (Just col) doc0+ where+ right = case mRight of+ Auto -> 0+ NotAuto x -> x+ left = case mLeft of+ Auto -> 0+ NotAuto x -> x++ -------------------------------------------------------------------------------- prettyBlock :: DisplaySettings -> Pandoc.Block -> PP.Doc @@ -215,13 +234,13 @@ prettyBlock ds (Pandoc.BulletList bss) = PP.vcat [ PP.indent- (PP.NotTrimmable $ themed ds themeBulletList prefix)- (PP.Trimmable " ")+ (PP.Indentation 2 $ themed ds themeBulletList prefix)+ (PP.Indentation 4 mempty) (prettyBlocks ds' bs) | bs <- bss ] <> PP.hardline where- prefix = " " <> PP.string [marker] <> " "+ prefix = PP.string [marker] <> " " marker = case T.unpack <$> themeBulletListMarkers theme of Just (x : _) -> x _ -> '-'@@ -236,8 +255,8 @@ prettyBlock ds (Pandoc.OrderedList _ bss) = PP.vcat [ PP.indent- (PP.NotTrimmable $ themed ds themeOrderedList $ PP.string prefix)- (PP.Trimmable " ")+ (PP.Indentation 0 $ themed ds themeOrderedList $ PP.string prefix)+ (PP.Indentation 4 mempty) (prettyBlocks ds bs) | (prefix, bs) <- zip padded bss ] <> PP.hardline@@ -253,7 +272,7 @@ prettyBlock _ds Pandoc.HorizontalRule = "---" prettyBlock ds (Pandoc.BlockQuote bs) =- let quote = PP.NotTrimmable (themed ds themeBlockQuote "> ") in+ let quote = PP.Indentation 0 (themed ds themeBlockQuote "> ") in PP.indent quote quote (themed ds themeBlockQuote $ prettyBlocks ds bs) prettyBlock ds (Pandoc.DefinitionList terms) =@@ -263,8 +282,8 @@ themed ds themeDefinitionTerm (prettyInlines ds term) <$$> PP.hardline <> PP.vcat [ PP.indent- (PP.NotTrimmable (themed ds themeDefinitionList ": "))- (PP.Trimmable " ") $+ (PP.Indentation 0 (themed ds themeDefinitionList ": "))+ (PP.Indentation 4 mempty) $ prettyBlocks ds (Pandoc.plainToPara definition) | definition <- definitions ]@@ -289,7 +308,7 @@ prettyBlock ds (Pandoc.Div _attrs blocks) = prettyBlocks ds blocks prettyBlock ds (Pandoc.LineBlock inliness) =- let ind = PP.NotTrimmable (themed ds themeLineBlock "| ") in+ let ind = PP.Indentation 0 (themed ds themeLineBlock "| ") in PP.wrapAt Nothing $ PP.indent ind ind $ PP.vcat $@@ -352,10 +371,11 @@ " <> ")" +prettyInline _ (Pandoc.RawInline _ t) = PP.text t+ -- These elements aren't really supported. prettyInline ds (Pandoc.Cite _ t) = prettyInlines ds t prettyInline ds (Pandoc.Span _ t) = prettyInlines ds t-prettyInline _ds (Pandoc.RawInline _ t) = PP.text t prettyInline ds (Pandoc.Note t) = prettyBlocks ds t prettyInline ds (Pandoc.Superscript t) = prettyInlines ds t prettyInline ds (Pandoc.Subscript t) = prettyInlines ds t
lib/Patat/Presentation/Display/CodeBlock.hs view
@@ -76,7 +76,7 @@ blockified :: Skylighting.SourceLine -> PP.Doc blockified line = let len = sourceLineLength line- indent = PP.NotTrimmable " " in+ indent = PP.Indentation 3 mempty in PP.indent indent indent $ themed ds themeCodeBlock $ " " <>
lib/Patat/Presentation/Display/Internal.hs view
@@ -6,14 +6,20 @@ ---------------------------------------------------------------------------------import qualified Patat.PrettyPrint as PP-import qualified Patat.Theme as Theme-import qualified Skylighting as Skylighting+import Patat.Presentation.Internal (Margins)+import Patat.Presentation.Settings (Wrap)+import qualified Patat.PrettyPrint as PP+import Patat.Size (Size)+import qualified Patat.Theme as Theme+import qualified Skylighting as Skylighting -------------------------------------------------------------------------------- data DisplaySettings = DisplaySettings- { dsTheme :: !Theme.Theme+ { dsSize :: !Size+ , dsWrap :: !Wrap+ , dsMargins :: !Margins+ , dsTheme :: !Theme.Theme , dsSyntaxMap :: !Skylighting.SyntaxMap }
lib/Patat/Presentation/Display/Table.hs view
@@ -30,7 +30,7 @@ -------------------------------------------------------------------------------- prettyTable :: DisplaySettings -> Table -> PP.Doc prettyTable ds Table {..} =- PP.indent (PP.Trimmable " ") (PP.Trimmable " ") $+ PP.indent indentation indentation $ lineIf (not isHeaderLess) (hcat2 headerHeight [ themed ds themeTableHeader $ PP.align w a (vpad headerHeight header)@@ -48,6 +48,8 @@ lineIf (not $ PP.null tCaption) (PP.hardline <> "Table: " <> tCaption) where+ indentation = PP.Indentation 2 mempty+ lineIf cond line = if cond then line <> PP.hardline else mempty joinRows
lib/Patat/Presentation/Internal.hs view
@@ -78,9 +78,9 @@ -------------------------------------------------------------------------------- data Margins = Margins- { mTop :: Int- , mLeft :: Int- , mRight :: Int+ { mTop :: AutoOr Int+ , mLeft :: AutoOr Int+ , mRight :: AutoOr Int } deriving (Show) @@ -92,8 +92,10 @@ , mTop = get 1 msTop } where- get def f = fromMaybe def . fmap A.unFlexibleNum $ psMargins ps >>= f-+ get def f = case psMargins ps >>= f of+ Just Auto -> Auto+ Nothing -> NotAuto def+ Just (NotAuto fn) -> NotAuto $ A.unFlexibleNum fn -------------------------------------------------------------------------------- data Slide = Slide
lib/Patat/Presentation/Settings.hs view
@@ -6,6 +6,8 @@ ( PresentationSettings (..) , defaultPresentationSettings + , Wrap (..)+ , AutoOr (..) , MarginSettings (..) , ExtensionList (..)@@ -14,6 +16,7 @@ , ImageSettings (..) , EvalSettingsMap+ , EvalSettingsWrap (..) , EvalSettings (..) , SpeakerNotesSettings (..)@@ -23,18 +26,19 @@ ---------------------------------------------------------------------------------import Control.Monad (mplus)-import qualified Data.Aeson.Extended as A-import qualified Data.Aeson.TH.Extended as A-import qualified Data.Foldable as Foldable-import Data.Function (on)-import qualified Data.HashMap.Strict as HMS-import Data.List (intercalate)-import qualified Data.Text as T-import qualified Patat.Theme as Theme+import Control.Applicative ((<|>))+import Control.Monad (mplus)+import qualified Data.Aeson.Extended as A+import qualified Data.Aeson.TH.Extended as A+import qualified Data.Foldable as Foldable+import Data.Function (on)+import qualified Data.HashMap.Strict as HMS+import Data.List (intercalate)+import qualified Data.Text as T+import qualified Patat.Theme as Theme import Prelude-import qualified Text.Pandoc as Pandoc-import Text.Read (readMaybe)+import qualified Text.Pandoc as Pandoc+import Text.Read (readMaybe) --------------------------------------------------------------------------------@@ -44,7 +48,7 @@ { psRows :: !(Maybe (A.FlexibleNum Int)) , psColumns :: !(Maybe (A.FlexibleNum Int)) , psMargins :: !(Maybe MarginSettings)- , psWrap :: !(Maybe Bool)+ , psWrap :: !(Maybe Wrap) , psTheme :: !(Maybe Theme.Theme) , psIncrementalLists :: !(Maybe Bool) , psAutoAdvanceDelay :: !(Maybe (A.FlexibleNum Int))@@ -100,10 +104,31 @@ --------------------------------------------------------------------------------+data Wrap = NoWrap | AutoWrap | WrapAt Int deriving (Show)+++--------------------------------------------------------------------------------+instance A.FromJSON Wrap where+ parseJSON val =+ ((\w -> if w then AutoWrap else NoWrap) <$> A.parseJSON val) <|>+ (WrapAt <$> A.parseJSON val)+++--------------------------------------------------------------------------------+data AutoOr a = Auto | NotAuto a deriving (Show)+++--------------------------------------------------------------------------------+instance A.FromJSON a => A.FromJSON (AutoOr a) where+ parseJSON (A.String "auto") = pure Auto+ parseJSON val = NotAuto <$> A.parseJSON val+++-------------------------------------------------------------------------------- data MarginSettings = MarginSettings- { msTop :: !(Maybe (A.FlexibleNum Int))- , msLeft :: !(Maybe (A.FlexibleNum Int))- , msRight :: !(Maybe (A.FlexibleNum Int))+ { msTop :: !(Maybe (AutoOr (A.FlexibleNum Int)))+ , msLeft :: !(Maybe (AutoOr (A.FlexibleNum Int)))+ , msRight :: !(Maybe (AutoOr (A.FlexibleNum Int))) } deriving (Show) @@ -196,10 +221,28 @@ --------------------------------------------------------------------------------+data EvalSettingsWrap+ = EvalWrapCode+ | EvalWrapRaw+ | EvalWrapRawInline+ deriving (Show)+++--------------------------------------------------------------------------------+instance A.FromJSON EvalSettingsWrap where+ parseJSON = A.withText "FromJSON EvalSettingsWrap" $ \txt -> case txt of+ "code" -> pure EvalWrapCode+ "raw" -> pure EvalWrapRaw+ "rawInline" -> pure EvalWrapRawInline+ _ -> fail $ "unknown wrap: " <> show txt+++-------------------------------------------------------------------------------- data EvalSettings = EvalSettings { evalCommand :: !T.Text , evalReplace :: !Bool , evalFragment :: !Bool+ , evalWrap :: !EvalSettingsWrap } deriving (Show) @@ -207,8 +250,9 @@ instance A.FromJSON EvalSettings where parseJSON = A.withObject "FromJSON EvalSettings" $ \o -> EvalSettings <$> o A..: "command"- <*> o A..:? "replace" A..!= False+ <*> o A..:? "replace" A..!= False <*> o A..:? "fragment" A..!= True+ <*> o A..:? "wrap" A..!= EvalWrapCode --------------------------------------------------------------------------------
lib/Patat/PrettyPrint.hs view
@@ -24,8 +24,9 @@ , wrapAt - , Trimmable (..)+ , Indentation (..) , indent+ , deindent , ansi @@ -91,12 +92,35 @@ ---------------------------------------------------------------------------------indent :: Trimmable Doc -> Trimmable Doc -> Doc -> Doc+indent :: Indentation Doc -> Indentation Doc -> Doc -> Doc indent firstLineDoc otherLinesDoc doc = mkDoc $ Indent- { indentFirstLine = traverse docToChunks firstLineDoc- , indentOtherLines = traverse docToChunks otherLinesDoc+ { indentFirstLine = fmap docToChunks firstLineDoc+ , indentOtherLines = fmap docToChunks otherLinesDoc , indentDoc = doc }+++--------------------------------------------------------------------------------+-- | Only strips leading spaces+deindent :: Doc -> Doc+deindent = Doc . concatMap go . unDoc+ where+ go :: DocE Doc -> [DocE Doc]+ go doc@(Indent {..})+ | fs0 <= 0 && os0 <= 0 = [doc]+ | fs1 == 0 && os1 == 0 && L.null fc && L.null oc =+ concatMap go $ unDoc indentDoc+ | otherwise = pure $ Indent+ { indentFirstLine = Indentation fs1 fc+ , indentOtherLines = Indentation os1 oc+ , indentDoc = indentDoc+ }+ where+ Indentation fs0 fc = indentFirstLine+ Indentation os0 oc = indentOtherLines+ fs1 = fs0 - min fs0 os0+ os1 = os0 - min fs0 os0+ go doc = [doc] --------------------------------------------------------------------------------
lib/Patat/PrettyPrint/Internal.hs view
@@ -15,11 +15,11 @@ , DocE (..) , chunkToDocE + , Indentation (..)+ , Doc (..) , docToChunks - , Trimmable (..)- , toString , dimensions , null@@ -34,7 +34,7 @@ -------------------------------------------------------------------------------- import Control.Monad.Reader (asks, local) import Control.Monad.RWS (RWS, runRWS)-import Control.Monad.State (get, gets, modify)+import Control.Monad.State (get, modify) import Control.Monad.Writer (tell) import Data.Char.WCWidth.Extended (wcstrwidth) import qualified Data.List as L@@ -119,8 +119,8 @@ , ansiDoc :: d } | Indent- { indentFirstLine :: LineBuffer- , indentOtherLines :: LineBuffer+ { indentFirstLine :: Indentation [Chunk]+ , indentOtherLines :: Indentation [Chunk] , indentDoc :: d } | Control Control@@ -151,9 +151,9 @@ -------------------------------------------------------------------------------- data DocEnv = DocEnv- { deCodes :: [Ansi.SGR] -- ^ Most recent ones first in the list- , deIndent :: LineBuffer -- ^ Don't need to store first-line indent- , deWrap :: Maybe Int -- ^ Wrap at columns+ { deCodes :: [Ansi.SGR] -- ^ Most recent ones first in the list+ , deIndent :: [Indentation [Chunk]] -- ^ No need to store first-line indent+ , deWrap :: Maybe Int -- ^ Wrap at columns } @@ -162,33 +162,49 @@ ---------------------------------------------------------------------------------data Trimmable a- = NotTrimmable !a- | Trimmable !a+-- | Note that the lists here are reversed so we have fast append.+-- We also store the current length to avoid having to recompute it.+data LineBuffer = LineBuffer Int [Indentation [Chunk]] [Chunk]+++--------------------------------------------------------------------------------+emptyLineBuffer :: LineBuffer+emptyLineBuffer = LineBuffer 0 [] []+++--------------------------------------------------------------------------------+data Indentation a = Indentation Int a deriving (Foldable, Functor, Traversable) ----------------------------------------------------------------------------------- | Note that this is reversed so we have fast append-type LineBuffer = [Trimmable Chunk]+indentationToChunks :: Indentation [Chunk] -> [Chunk]+indentationToChunks (Indentation 0 c) = c+indentationToChunks (Indentation n c) = StringChunk [] (replicate n ' ') : c --------------------------------------------------------------------------------+indentationWidth :: Indentation [Chunk] -> Int+indentationWidth (Indentation s c) =+ s + sum (map (wcstrwidth . chunkToString) c)+++-------------------------------------------------------------------------------- bufferToChunks :: LineBuffer -> Chunks-bufferToChunks = map trimmableToChunk . reverse . dropWhile isTrimmable+bufferToChunks (LineBuffer _ ind chunks) = case chunks of+ [] -> concatMap indentationToChunks $ reverse $+ dropWhile emptyIndentation ind+ _ -> concatMap indentationToChunks (reverse ind) ++ reverse chunks where- isTrimmable (NotTrimmable _) = False- isTrimmable (Trimmable _) = True-- trimmableToChunk (NotTrimmable c) = c- trimmableToChunk (Trimmable c) = c+ emptyIndentation (Indentation _ []) = True+ emptyIndentation _ = False -------------------------------------------------------------------------------- docToChunks :: Doc -> Chunks docToChunks doc0 = let env0 = DocEnv [] [] Nothing- ((), b, cs) = runRWS (go $ unDoc doc0) env0 mempty in+ ((), b, cs) = runRWS (go $ unDoc doc0) env0 emptyLineBuffer in optimizeChunks (cs <> bufferToChunks b) where go :: [DocE Doc] -> DocM ()@@ -197,7 +213,7 @@ go (String str : docs) = do chunk <- makeChunk str- modify (NotTrimmable chunk :)+ appendChunk chunk go docs go (Softspace : docs) = do@@ -206,7 +222,7 @@ go (Hardspace : docs) = do chunk <- makeChunk " "- modify (NotTrimmable chunk :)+ appendChunk chunk go docs go (Softline : docs) = do@@ -216,12 +232,15 @@ go (Hardline : docs) = do buffer <- get tell $ bufferToChunks buffer <> [NewlineChunk]- indentation <- asks deIndent- modify $ \_ -> if L.null docs then [] else indentation+ ind <- asks deIndent+ modify $ \_ -> case docs of+ [] -> emptyLineBuffer+ _ : _ -> LineBuffer (sum $ map indentationWidth ind) ind [] go docs go (WrapAt {..} : docs) = do- local (\env -> env {deWrap = wrapAtCol}) $ go (unDoc wrapDoc)+ il <- asks $ sum . map indentationWidth . deIndent+ local (\env -> env {deWrap = fmap (+ il) wrapAtCol}) $ go (unDoc wrapDoc) go docs go (Ansi {..} : docs) = do@@ -230,8 +249,9 @@ go docs go (Indent {..} : docs) = do- local (\env -> env {deIndent = indentOtherLines ++ deIndent env}) $ do- modify (indentFirstLine ++)+ local (\e -> e {deIndent = indentOtherLines : deIndent e}) $ do+ modify $ \(LineBuffer w i c) -> LineBuffer+ (w + indentationWidth indentFirstLine) (indentFirstLine : i) c go (unDoc indentDoc) go docs @@ -245,6 +265,10 @@ codes <- asks deCodes return $ StringChunk codes str + appendChunk :: Chunk -> DocM ()+ appendChunk c = modify $ \(LineBuffer w i cs) ->+ LineBuffer (w + wcstrwidth (chunkToString c)) i (c : cs)+ -- Convert 'Softspace' or 'Softline' to 'Hardspace' or 'Hardline' softConversion :: DocE Doc -> [DocE Doc] -> DocM (DocE Doc) softConversion soft docs = do@@ -252,9 +276,7 @@ case mbWrapCol of Nothing -> return hard Just maxCol -> do- -- Slow.- currentLine <- gets (concatMap chunkToString . bufferToChunks)- let currentCol = wcstrwidth currentLine+ LineBuffer currentCol _ _ <- get case nextWordLength docs of Nothing -> return hard Just l@@ -316,4 +338,5 @@ -------------------------------------------------------------------------------- string :: String -> Doc-string = mkDoc . String -- TODO (jaspervdj): Newline conversion?+string "" = Doc []+string str = mkDoc $ String str -- TODO (jaspervdj): Newline conversion?
patat.cabal view
@@ -1,16 +1,17 @@-Name: patat-Version: 0.10.1.1-Synopsis: Terminal-based presentations using Pandoc-Description: Terminal-based presentations using Pandoc.-License: GPL-2-License-file: LICENSE-Author: Jasper Van der Jeugt <m@jaspervdj.be>-Maintainer: Jasper Van der Jeugt <m@jaspervdj.be>-Homepage: http://github.com/jaspervdj/patat-Copyright: 2016 Jasper Van der Jeugt-Category: Text-Build-type: Simple-Cabal-version: >=1.10+Name: patat+Version: 0.11.0.0+Synopsis: Terminal-based presentations using Pandoc+Description: Terminal-based presentations using Pandoc.+License: GPL-2+License-file: LICENSE+Author: Jasper Van der Jeugt <m@jaspervdj.be>+Maintainer: Jasper Van der Jeugt <m@jaspervdj.be>+Homepage: http://github.com/jaspervdj/patat+Copyright: 2016 Jasper Van der Jeugt+Category: Text+Build-type: Simple+Cabal-version: >=1.10+Tested-with: GHC ==9.2.8 || ==9.4.8 || ==9.6.3 || ==9.8.1 Extra-source-files: CHANGELOG.md@@ -18,7 +19,7 @@ Source-repository head Type: git- Location: git://github.com/jaspervdj/patat.git+ Location: https://github.com/jaspervdj/patat.git Flag patat-make-man Description: Build the executable to generate the man page@@ -31,17 +32,17 @@ Default-language: Haskell2010 Build-depends:- aeson >= 2.0 && < 2.2,+ aeson >= 2.0 && < 2.3, ansi-terminal >= 0.6 && < 1.1, ansi-wl-pprint >= 0.6 && < 1.1, async >= 2.2 && < 2.3, base >= 4.9 && < 5, base64-bytestring >= 1.0 && < 1.3,- bytestring >= 0.10 && < 0.12,+ bytestring >= 0.10 && < 0.13, colour >= 2.3 && < 2.4, containers >= 0.5 && < 0.7, directory >= 1.2 && < 1.4,- filepath >= 1.4 && < 1.5,+ filepath >= 1.4 && < 1.6, mtl >= 2.2 && < 2.4, optparse-applicative >= 0.16 && < 0.19, pandoc >= 3.1 && < 3.2,@@ -50,7 +51,7 @@ random >= 1.2 && < 1.3, skylighting >= 0.10 && < 0.15, terminal-size >= 0.3 && < 0.4,- text >= 1.2 && < 2.1,+ text >= 1.2 && < 2.2, time >= 1.4 && < 1.13, unordered-containers >= 0.2 && < 0.3, yaml >= 0.8 && < 0.12,@@ -128,11 +129,11 @@ Build-depends: base >= 4.9 && < 5,- containers >= 0.6 && < 0.7,+ containers >= 0.6 && < 0.8, doctemplates >= 0.8 && < 0.12, mtl >= 2.2 && < 2.4, pandoc >= 3.1 && < 3.2,- text >= 1.2 && < 2.1,+ text >= 1.2 && < 2.2, time >= 1.6 && < 1.13 Test-suite patat-tests@@ -153,8 +154,8 @@ base >= 4.8 && < 5, directory >= 1.2 && < 1.4, pandoc >= 3.1 && < 3.2,- tasty >= 1.2 && < 1.5,+ tasty >= 1.2 && < 1.6, tasty-hunit >= 0.10 && < 0.11, tasty-quickcheck >= 0.10 && < 0.11,- text >= 1.2 && < 2.1,+ text >= 1.2 && < 2.2, QuickCheck >= 2.8 && < 2.15