packages feed

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 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 @@     "![" <> themed ds themeImageText (prettyInlines ds text) <> "](" <>     themed ds themeImageTarget (PP.text target) <> ")" +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