packages feed

patat 0.8.9.0 → 0.9.0.0

raw patch · 16 files changed

+946/−525 lines, 16 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Patat.Presentation.Internal: getActiveFragment :: Presentation -> Maybe ActiveFragment
+ Patat.Presentation: [pSyntaxMap] :: Presentation -> !SyntaxMap
+ Patat.Presentation: [psSpeakerNotes] :: PresentationSettings -> !Maybe Settings
+ Patat.Presentation: [psSyntaxDefinitions] :: PresentationSettings -> !Maybe [FilePath]
+ Patat.Presentation: activeSpeakerNotes :: Presentation -> SpeakerNotes
+ Patat.Presentation.Display.Internal: DisplaySettings :: !Theme -> !SyntaxMap -> DisplaySettings
+ Patat.Presentation.Display.Internal: [dsSyntaxMap] :: DisplaySettings -> !SyntaxMap
+ Patat.Presentation.Display.Internal: [dsTheme] :: DisplaySettings -> !Theme
+ Patat.Presentation.Display.Internal: data DisplaySettings
+ Patat.Presentation.Display.Internal: themed :: DisplaySettings -> (Theme -> Maybe Style) -> Doc -> Doc
+ Patat.Presentation.Internal: Slide :: !SpeakerNotes -> !SlideContent -> Slide
+ Patat.Presentation.Internal: [pSyntaxMap] :: Presentation -> !SyntaxMap
+ Patat.Presentation.Internal: [psSpeakerNotes] :: PresentationSettings -> !Maybe Settings
+ Patat.Presentation.Internal: [psSyntaxDefinitions] :: PresentationSettings -> !Maybe [FilePath]
+ Patat.Presentation.Internal: [slideContent] :: Slide -> !SlideContent
+ Patat.Presentation.Internal: [slideSpeakerNotes] :: Slide -> !SpeakerNotes
+ Patat.Presentation.Internal: activeFragment :: Presentation -> Maybe ActiveFragment
+ Patat.Presentation.Internal: activeSpeakerNotes :: Presentation -> SpeakerNotes
+ Patat.Presentation.Internal: data SlideContent
+ Patat.Presentation.Internal: instance GHC.Show.Show Patat.Presentation.Internal.SlideContent
+ Patat.Presentation.Read: detectSlideLevel :: Pandoc -> Int
+ Patat.Presentation.SpeakerNotes: data Handle
+ Patat.Presentation.SpeakerNotes: data Settings
+ Patat.Presentation.SpeakerNotes: data SpeakerNotes
+ Patat.Presentation.SpeakerNotes: instance Data.Aeson.Types.FromJSON.FromJSON Patat.Presentation.SpeakerNotes.Settings
+ Patat.Presentation.SpeakerNotes: instance GHC.Base.Monoid Patat.Presentation.SpeakerNotes.SpeakerNotes
+ Patat.Presentation.SpeakerNotes: instance GHC.Base.Semigroup Patat.Presentation.SpeakerNotes.SpeakerNotes
+ Patat.Presentation.SpeakerNotes: instance GHC.Classes.Eq Patat.Presentation.SpeakerNotes.SpeakerNotes
+ Patat.Presentation.SpeakerNotes: instance GHC.Show.Show Patat.Presentation.SpeakerNotes.Settings
+ Patat.Presentation.SpeakerNotes: instance GHC.Show.Show Patat.Presentation.SpeakerNotes.SpeakerNotes
+ Patat.Presentation.SpeakerNotes: parse :: Block -> Maybe SpeakerNotes
+ Patat.Presentation.SpeakerNotes: partition :: [Block] -> (SpeakerNotes, [Block])
+ Patat.Presentation.SpeakerNotes: remove :: [Block] -> [Block]
+ Patat.Presentation.SpeakerNotes: split :: [Block] -> (SpeakerNotes, [Block])
+ Patat.Presentation.SpeakerNotes: toText :: SpeakerNotes -> Text
+ Patat.Presentation.SpeakerNotes: with :: Settings -> (Handle -> IO a) -> IO a
+ Patat.Presentation.SpeakerNotes: write :: Handle -> SpeakerNotes -> IO ()
- Patat.Presentation: Presentation :: !FilePath -> ![Inline] -> ![Inline] -> !PresentationSettings -> [Slide] -> [Breadcrumbs] -> !Index -> Presentation
+ Patat.Presentation: Presentation :: !FilePath -> ![Inline] -> ![Inline] -> !PresentationSettings -> !Seq Slide -> !Seq Breadcrumbs -> !Index -> !SyntaxMap -> Presentation
- Patat.Presentation: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe Margins -> !Maybe Bool -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> PresentationSettings
+ Patat.Presentation: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe Margins -> !Maybe Bool -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe Settings -> PresentationSettings
- Patat.Presentation: [pBreadcrumbs] :: Presentation -> [Breadcrumbs]
+ Patat.Presentation: [pBreadcrumbs] :: Presentation -> !Seq Breadcrumbs
- Patat.Presentation: [pSlides] :: Presentation -> [Slide]
+ Patat.Presentation: [pSlides] :: Presentation -> !Seq Slide
- Patat.Presentation.Display.CodeBlock: prettyCodeBlock :: Theme -> [Text] -> Text -> Doc
+ Patat.Presentation.Display.CodeBlock: prettyCodeBlock :: DisplaySettings -> [Text] -> Text -> Doc
- Patat.Presentation.Display.Table: prettyTable :: Theme -> Table -> Doc
+ Patat.Presentation.Display.Table: prettyTable :: DisplaySettings -> Table -> Doc
- Patat.Presentation.Display.Table: themed :: Maybe Style -> Doc -> Doc
+ Patat.Presentation.Display.Table: themed :: DisplaySettings -> (Theme -> Maybe Style) -> Doc -> Doc
- Patat.Presentation.Internal: ContentSlide :: Instructions Block -> Slide
+ Patat.Presentation.Internal: ContentSlide :: Instructions Block -> SlideContent
- Patat.Presentation.Internal: Presentation :: !FilePath -> ![Inline] -> ![Inline] -> !PresentationSettings -> [Slide] -> [Breadcrumbs] -> !Index -> Presentation
+ Patat.Presentation.Internal: Presentation :: !FilePath -> ![Inline] -> ![Inline] -> !PresentationSettings -> !Seq Slide -> !Seq Breadcrumbs -> !Index -> !SyntaxMap -> Presentation
- Patat.Presentation.Internal: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe Margins -> !Maybe Bool -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> PresentationSettings
+ Patat.Presentation.Internal: PresentationSettings :: !Maybe (FlexibleNum Int) -> !Maybe (FlexibleNum Int) -> !Maybe Margins -> !Maybe Bool -> !Maybe Theme -> !Maybe Bool -> !Maybe (FlexibleNum Int) -> !Maybe Int -> !Maybe ExtensionList -> !Maybe ImageSettings -> !Maybe Bool -> !Maybe EvalSettingsMap -> !Maybe Bool -> !Maybe [FilePath] -> !Maybe Settings -> PresentationSettings
- Patat.Presentation.Internal: TitleSlide :: Int -> [Inline] -> Slide
+ Patat.Presentation.Internal: TitleSlide :: Int -> [Inline] -> SlideContent
- Patat.Presentation.Internal: [pBreadcrumbs] :: Presentation -> [Breadcrumbs]
+ Patat.Presentation.Internal: [pBreadcrumbs] :: Presentation -> !Seq Breadcrumbs
- Patat.Presentation.Internal: [pSlides] :: Presentation -> [Slide]
+ Patat.Presentation.Internal: [pSlides] :: Presentation -> !Seq Slide

Files

CHANGELOG.md view
@@ -1,238 +1,333 @@ # Changelog -- 0.8.9.0 (2023-06-27)-    * Apply block quote theming to entire block (#119) (#111)-    * Fix table header theming (#128)-    * Dependency updates:-        - `aeson` to 2.1-        - `optparse-applicative` to 0.18-        - `pandoc` to 3.1-        - `pandoc-types` to 1.23-        - `text` to 2.0-        - `time` to 1.12+## 0.9.0.0 (2023-09-13) -- 0.8.8.0 (2022-10-26)-    * Allow hiding slide number (contribution by Paweł Dybiec)-    * Support additional markdown extensions (contribution by Spreadcat)-    * Dependency updates:-        - `aeson` to 2.0-        - `ansi-terminal` to 0.11-        - `base64-bytestring` to 1.2-        - `bytestring` to 0.11-        - `optparse-applicative` to 1.16-        - `pandoc` to 2.19-        - `skylighting` to 0.13+ *  Add proper support for speaker notes (#142) -- 0.8.7.0 (2021-03-12)-    * Fix alignment and display of CJK characters in presentation title, author-      and tables-    * Add support for showing images in Kitty terminal-    * Search in `$PATH` for `w3mimgdisplay`-    * Bump `pandoc` dependency to 2.11-    * Refactor `Patat.Presentation.Display` module to make it pure+    You can configure `patat` to write the speaker notes for the current slide+    to a file whenever the slide changes: -- 0.8.6.1 (2020-09-18)-    * Fix issue with laziness for evaluted code blocks, they should only be-      evaluated when we actually want to show them-    * Bump stack resolver to `lts-16.9`+        patat:+          speakerNotes:+            file: /tmp/notes.txt -- 0.8.6.0 (2020-09-11)-    * Allow evaluating code blocks (see README for more info)-    * Refactor implementation of fragments-    * Add breadcrumbs to title based on headers-    * Error out when YAML parsing fails+    Then, you can display these in a second terminal (presumably on a second+    monitor) by just displaying this file whenever it changes.  [entr] is one+    way to do that: -- 0.8.5.0 (2020-06-29)-    * Bump `pandoc` dependency to 2.9-    * Switch to `goldplate` for testing+        echo /tmp/notes.txt | entr -s 'clear; cat /tmp/notes.txt' -- 0.8.4.3 (2020-01-21)-    * Fix Haddock syntax in some comments (contribution by Asad Saeeduddin)+    [entr]: http://eradman.com/entrproject/ -- 0.8.4.2 (2020-01-18)-    * Add builds for Mac OS-    * Refactor CircleCI config & Makefile+    Alternatively, just use a second `patat` instance with `--watch` enabled: -- 0.8.4.1 (2019-10-29)-    * Bump CircleCI configuration-    * Bump release script-    * Add slide seeking to `--help` output+        patat -w /tmp/notes.txt -- 0.8.4.0 (2019-10-09)-    * Add slide seeking (enter slide number + `enter`)-    * Fix turning tty echo off/on during presentation-    * Run `w3mimgdisplay` cleanup action, fixing image issues on some terminals+ *  Add support for showing plain text files (#141) -- 0.8.3.0 (2019-09-07)-    * Fix test failure again, and ensure that it works for multiple pandoc-      versions by slightly modifying test input-    * Include pandoc version info in `patat --version`+    This isn't super useful on its own, it's meant to support speaker notes. -- 0.8.2.5 (2019-08-12)-    * Fix test failure caused by slightly different pandoc output for lists+ *  Add syntaxDefinitions to settings (#140) -- 0.8.2.4 (2019-08-12)-    * Bump `optparse-applicative` upper bound to 0.16-    * Bump `skylighting` upper bound to 0.9+    This allows users to add custom kate highlighting XML files in the settings: -- 0.8.2.3 (2019-06-25)-    * Bump upper `pandoc` dependency to 2.8+        ---+        patat:+          syntaxDefinitions:+          - 'impurescript.xml'+        ... -- 0.8.2.2 (2019-02-04)-    * Bump lower `base` dependency to 4.8+        Here is some *im*purescript: -- 0.8.2.1 (2019-02-03)-    * Bump `pandoc` to 2.6-    * Bump `ansi-terminal` to 0.10+        ```impurescript+        ...+        ``` -- 0.8.2.0 (2019-01-24)-    * GHC 7.8 compatibility+## 0.8.9.0 (2023-06-27) -- 0.8.1.3 (2019-01-24)-    * Bump `pandoc` to 2.4-    * Bump `yaml` to 0.11+* Apply block quote theming to entire block (#119) (#111)+* Fix table header theming (#128)+* Dependency updates:+    - `aeson` to 2.1+    - `optparse-applicative` to 0.18+    - `pandoc` to 3.1+    - `pandoc-types` to 1.23+    - `text` to 2.0+    - `time` to 1.12 -- 0.8.1.2 (2018-10-29)-    * Work around test failure caused by slightly different syntax highlighting-      in different pandoc versions+## 0.8.8.0 (2022-10-26) -- 0.8.1.1 (2018-10-26)-    * Tickle CircleCI cache+* Allow hiding slide number (contribution by Paweł Dybiec)+* Support additional markdown extensions (contribution by Spreadcat)+* Dependency updates:+    - `aeson` to 2.0+    - `ansi-terminal` to 0.11+    - `base64-bytestring` to 1.2+    - `bytestring` to 0.11+    - `optparse-applicative` to 1.16+    - `pandoc` to 2.19+    - `skylighting` to 0.13 -- 0.8.1.0 (2018-10-26)-    * Add support for italic ansi code in themes-    * Fix centered titles not being centered (contribution by Hamza Haiken)+## 0.8.7.0 (2021-03-12) -- 0.8.0.0 (2018-08-31)-    * Themed border rendering improvements (contribution by Hamza Haiken)-    * Add support for margins (contribution by Hamza Haiken)-    * Add RGB colour support for themes (contribution by Hamza Haiken)-    * Add experimental images support-    * Add images support for iTerm2 (contribution by @2mol)+* Fix alignment and display of CJK characters in presentation title, author+  and tables+* Add support for showing images in Kitty terminal+* Search in `$PATH` for `w3mimgdisplay`+* Bump `pandoc` dependency to 2.11+* Refactor `Patat.Presentation.Display` module to make it pure -- 0.7.2.0 (2018-05-08)-    * GHC 8.4 compatibility+## 0.8.6.1 (2020-09-18) -- 0.7.1.0 (2018-05-08)-    * GHC 8.4 compatibility+* Fix issue with laziness for evaluted code blocks, they should only be+  evaluated when we actually want to show them+* Bump stack resolver to `lts-16.9` -- 0.7.0.0 (2018-05-04)-    * Support HTML-style comments+## 0.8.6.0 (2020-09-11) -- 0.6.1.2 (2018-04-30)-    * Bump `pandoc` to 2.2+* Allow evaluating code blocks (see README for more info)+* Refactor implementation of fragments+* Add breadcrumbs to title based on headers+* Error out when YAML parsing fails -- 0.6.1.1 (2018-04-27)-    * Bump `aeson` to 1.3-    * Bump `skylighting` to 0.7-    * Bump `time` to 1.9-    * Bump `ansi-terminal` to 0.8+## 0.8.5.0 (2020-06-29) -- 0.6.1.0 (2018-01-28)-    * Bump `skylighting` to 0.6-    * Bump `pandoc` to 2.1-    * Bump `ansi-terminal` to 0.7+* Bump `pandoc` dependency to 2.9+* Switch to `goldplate` for testing -- 0.6.0.1 (2017-12-24)-    * Automatically upload linux binary to GitHub+## 0.8.4.3 (2020-01-21) -- 0.6.0.0 (2017-12-19)-    * Make pandoc extensions customizable in the configuration-    * Bump `pandoc` to 2.0+* Fix Haddock syntax in some comments (contribution by Asad Saeeduddin) -- 0.5.2.2 (2017-06-14)-    * Add `network-uri` dependency to fix travis build+## 0.8.4.2 (2020-01-18) -- 0.5.2.1 (2017-06-14)-    * Bump `optparse-applicative-0.14` dependency+* Add builds for Mac OS+* Refactor CircleCI config & Makefile -- 0.5.2.0 (2017-05-16)-    * Add navigation using `PageUp` and `PageDown`.-    * Use `skylighting` instead of deprecated `highlighting-kate` for syntax-      highlighting.+## 0.8.4.1 (2019-10-29) -- 0.5.1.2 (2017-04-26)-    * Make build reproducible even if timezone changes (patch by Félix Sipma)+* Bump CircleCI configuration+* Bump release script+* Add slide seeking to `--help` output -- 0.5.1.1 (2017-04-23)-    * Include `README` in `Extra-source-files` so it gets displayed on Hackage+## 0.8.4.0 (2019-10-09) -- 0.5.1.0 (2017-04-23)-    * Bump `aeson-1.2` dependency-    * Fix vertical alignment of title slides-    * Fix wrapping issue with inline code at end of line-    * Add bash-completion script generation to Makefile+* Add slide seeking (enter slide number + `enter`)+* Fix turning tty echo off/on during presentation+* Run `w3mimgdisplay` cleanup action, fixing image issues on some terminals -- 0.5.0.0 (2017-02-06)-    * Add a `slideLevel` option & autodetect it.  This changes the way `patat`-      splits slides.  For more information, see the `README` or the `man` page.-      If you just want to get the old behavior back, just add:+## 0.8.3.0 (2019-09-07) -            ----            patat:-              slideLevel: 1-            ...+* Fix test failure again, and ensure that it works for multiple pandoc+  versions by slightly modifying test input+* Include pandoc version info in `patat --version` -        To the top of your presentation.+## 0.8.2.5 (2019-08-12) -    * Clear the screen when finished with the presentation.+* Fix test failure caused by slightly different pandoc output for lists -- 0.4.7.1 (2017-01-22)-    * Bump `directory-1.3` dependency-    * Bump `time-1.7` dependency+## 0.8.2.4 (2019-08-12) -- 0.4.7.0 (2017-01-20)-    * Bump `aeson-1.1` dependency-    * Parse YAML for settings using `yaml` instead of pandoc-    * Clarify watch & autoAdvance combination in documentation.+* Bump `optparse-applicative` upper bound to 0.16+* Bump `skylighting` upper bound to 0.9 -- 0.4.6.0 (2016-12-28)-    * Redraw the screen on unknown commands to prevent accidental typing from-      showing up.-    * Make the cursor invisible during the presentation.-    * Move the footer down one more line to gain some screen real estate.+## 0.8.2.3 (2019-06-25) -- 0.4.5.0 (2016-12-05)-    * Render the date in a locale-independent manner (patch by Daniel-      Shahaf).+* Bump upper `pandoc` dependency to 2.8 -- 0.4.4.0 (2016-12-03)-    * Force the use of UTF-8 when generating the man page.+## 0.8.2.2 (2019-02-04) -- 0.4.3.0 (2016-12-02)-    * Use `SOURCE_DATE_EPOCH` if it is present instead of getting the date from-      `git log`.+* Bump lower `base` dependency to 4.8 -- 0.4.2.0 (2016-12-01)-    * Fix issues with man page generation on Travis.+## 0.8.2.1 (2019-02-03) -- 0.4.1.0 (2016-12-01)-    * Fix compatibility with `pandoc-1.18` and `pandoc-1.19`.-    * Add a man page.+* Bump `pandoc` to 2.6+* Bump `ansi-terminal` to 0.10 -- 0.4.0.0 (2016-11-15)-    * Add configurable auto advancing.-    * Support fragmented slides.+## 0.8.2.0 (2019-01-24) -- 0.3.3.0 (2016-10-31)-    * Add a `--version` flag.-    * Add support for `pandoc-1.18` which includes a new `LineBlock` element.+* GHC 7.8 compatibility -- 0.3.2.0 (2016-10-20)-    * Keep running even if errors are encountered during reload.+## 0.8.1.3 (2019-01-24) -- 0.3.1.0 (2016-10-18)-    * Fix compilation with `lts-6.22`.+* Bump `pandoc` to 2.4+* Bump `yaml` to 0.11 -- 0.3.0.0 (2016-10-17)-    * Add syntax highlighting support.-    * Fixed slide clipping after reload.+## 0.8.1.2 (2018-10-29) -- 0.2.0.0 (2016-10-13)-    * Add theming support.-    * Fix links display.-    * Add support for wrapping.-    * Allow org mode as input format.+* Work around test failure caused by slightly different syntax highlighting+  in different pandoc versions -- 0.1.0.0 (2016-10-02)-    * Upload first version from hotel wifi in Kalaw.+## 0.8.1.1 (2018-10-26)++* Tickle CircleCI cache++## 0.8.1.0 (2018-10-26)++* Add support for italic ansi code in themes+* Fix centered titles not being centered (contribution by Hamza Haiken)++## 0.8.0.0 (2018-08-31)++* Themed border rendering improvements (contribution by Hamza Haiken)+* Add support for margins (contribution by Hamza Haiken)+* Add RGB colour support for themes (contribution by Hamza Haiken)+* Add experimental images support+* Add images support for iTerm2 (contribution by @2mol)++## 0.7.2.0 (2018-05-08)++* GHC 8.4 compatibility++## 0.7.1.0 (2018-05-08)++* GHC 8.4 compatibility++## 0.7.0.0 (2018-05-04)++* Support HTML-style comments++## 0.6.1.2 (2018-04-30)++* Bump `pandoc` to 2.2++## 0.6.1.1 (2018-04-27)++* Bump `aeson` to 1.3+* Bump `skylighting` to 0.7+* Bump `time` to 1.9+* Bump `ansi-terminal` to 0.8++## 0.6.1.0 (2018-01-28)++* Bump `skylighting` to 0.6+* Bump `pandoc` to 2.1+* Bump `ansi-terminal` to 0.7++## 0.6.0.1 (2017-12-24)++* Automatically upload linux binary to GitHub++## 0.6.0.0 (2017-12-19)++* Make pandoc extensions customizable in the configuration+* Bump `pandoc` to 2.0++## 0.5.2.2 (2017-06-14)++* Add `network-uri` dependency to fix travis build++## 0.5.2.1 (2017-06-14)++* Bump `optparse-applicative-0.14` dependency++## 0.5.2.0 (2017-05-16)++* Add navigation using `PageUp` and `PageDown`.+* Use `skylighting` instead of deprecated `highlighting-kate` for syntax+  highlighting.++## 0.5.1.2 (2017-04-26)++* Make build reproducible even if timezone changes (patch by Félix Sipma)++## 0.5.1.1 (2017-04-23)++* Include `README` in `Extra-source-files` so it gets displayed on Hackage++## 0.5.1.0 (2017-04-23)++* Bump `aeson-1.2` dependency+* Fix vertical alignment of title slides+* Fix wrapping issue with inline code at end of line+* Add bash-completion script generation to Makefile++## 0.5.0.0 (2017-02-06)++* Add a `slideLevel` option & autodetect it.  This changes the way `patat`+  splits slides.  For more information, see the `README` or the `man` page.+  If you just want to get the old behavior back, just add:++        ---+        patat:+          slideLevel: 1+        ...++    To the top of your presentation.++* Clear the screen when finished with the presentation.++## 0.4.7.1 (2017-01-22)++* Bump `directory-1.3` dependency+* Bump `time-1.7` dependency++## 0.4.7.0 (2017-01-20)++* Bump `aeson-1.1` dependency+* Parse YAML for settings using `yaml` instead of pandoc+* Clarify watch & autoAdvance combination in documentation.++## 0.4.6.0 (2016-12-28)++* Redraw the screen on unknown commands to prevent accidental typing from+  showing up.+* Make the cursor invisible during the presentation.+* Move the footer down one more line to gain some screen real estate.++## 0.4.5.0 (2016-12-05)++* Render the date in a locale-independent manner (patch by Daniel+  Shahaf).++## 0.4.4.0 (2016-12-03)++* Force the use of UTF-8 when generating the man page.++## 0.4.3.0 (2016-12-02)++* Use `SOURCE_DATE_EPOCH` if it is present instead of getting the date from+  `git log`.++## 0.4.2.0 (2016-12-01)++* Fix issues with man page generation on Travis.++## 0.4.1.0 (2016-12-01)++* Fix compatibility with `pandoc-1.18` and `pandoc-1.19`.+* Add a man page.++## 0.4.0.0 (2016-11-15)++* Add configurable auto advancing.+* Support fragmented slides.++## 0.3.3.0 (2016-10-31)++* Add a `--version` flag.+* Add support for `pandoc-1.18` which includes a new `LineBlock` element.++## 0.3.2.0 (2016-10-20)++* Keep running even if errors are encountered during reload.++## 0.3.1.0 (2016-10-18)++* Fix compilation with `lts-6.22`.++## 0.3.0.0 (2016-10-17)++* Add syntax highlighting support.+* Fixed slide clipping after reload.++## 0.2.0.0 (2016-10-13)++* Add theming support.+* Fix links display.+* Add support for wrapping.+* Allow org mode as input format.++## 0.1.0.0 (2016-10-02)++* Upload first version from hotel wifi in Kalaw.
README.md view
@@ -14,17 +14,18 @@ - Supports [smart slide splitting](#input-format). - Slides can be split up into [multiple fragments](#fragmented-slides) - There is a [live reload](#running) mode.-- [Theming](#theming) support including 24-bit RGB.+- Supports [evaluating code snippets and showing the result](#evaluating-code).+- Display [speaker notes](#speaker-notes) in a second window or monitor. - [Auto advancing](#auto-advancing) with configurable delay.+- Experimental [images](#images) support. - Optionally [re-wrapping](#line-wrapping) text to terminal width with proper   indentation. - Syntax highlighting for nearly one hundred languages generated from [Kate]   syntax files.-- Experimental [images](#images) support.-- Supports [evaluating code snippets and showing the result](#evaluating-code).+- [Theming](#theming) support including 24-bit RGB. - Written in [Haskell]. -![screenshot](extra/screenshot.png?raw=true)+![screenshot](extra/demo.gif?raw=true)  [Kate]: https://kate-editor.org/ [Haskell]: http://haskell.org/@@ -53,6 +54,7 @@     -   [Images](#images)     -   [Breadcrumbs](#breadcrumbs)     -   [Evaluating code](#evaluating-code)+    -   [Speaker notes](#speaker-notes) -   [Trivia](#trivia)  Installation@@ -241,26 +243,6 @@  For more information, see [Advanced slide splitting](#advanced-slide-splitting). -Patat supports comments which can be used as speaker notes.--```markdown-----title: This is my presentation-author: Jane Doe-...--# Chapter 1--<!---Note: I should not bore the audience with my thoughts on powerpoint but-just get straight to the point.--->--Slide contents.  Yay.--<!-- TODO: Finish the rest of the presentation. -->-```- Configuration ------------- @@ -489,6 +471,20 @@  ### Syntax Highlighting +`patat` uses [Kate] Syntax Highlighting files.  `patat` ships with support for+nearly one hundred languages thanks to Pandoc.  However, if your language is+not yet available, you can add the highlighting XML file in the settings:++```markdown+---+patat:+  syntaxDefinitions:+  - 'impurescript.xml'+...++...+```+ As part of theming, syntax highlighting is also configurable.  This can be configured like this: @@ -677,6 +673,53 @@ 2.  Write the contents of the code block to the `stdin` of the process 3.  Wait for the process to exit 4.  Render the `stdout` of the process++### Speaker Notes++`patat` supports comments which can be used as speaker notes.++```markdown+---+title: This is my presentation+author: Jane Doe+...++# Chapter 1++<!--+Note: I should not bore the audience with my thoughts on powerpoint but+just get straight to the point.+-->++Slide contents.  Yay.++<!-- TODO: Finish the rest of the presentation. -->+```++You can also configure `patat` to write the speaker notes for the current slide+to a file whenever the slide changes:++```yaml+patat:+  speakerNotes:+    file: /tmp/notes.txt+```++Then, you can display these in a second terminal (presumably on a second+monitor) by just displaying this file whenever it changes.  [entr] is one+way to do that:++[entr]: http://eradman.com/entrproject/++```bash+echo /tmp/notes.txt | entr -s 'clear; cat /tmp/notes.txt'+```++Alternatively, just use a second `patat` instance with `--watch` enabled:++```bash+patat -w /tmp/notes.txt+```  Trivia ------
+ lib/Data/Sequence/Extended.hs view
@@ -0,0 +1,16 @@+module Data.Sequence.Extended+    ( module Data.Sequence+    , cons+    , safeIndex+    ) where++import Data.Sequence++cons :: a -> Seq a -> Seq a+cons x xs = singleton x <> xs++safeIndex :: Seq a -> Int -> Maybe a+safeIndex s n+    | n < 0                       = Nothing+    | n >= Data.Sequence.length s = Nothing+    | otherwise                   = Just $ index s n
lib/Patat/Eval.hs view
@@ -10,13 +10,13 @@ import qualified Control.Concurrent.Async       as Async import           Control.Exception              (finally) import qualified Data.HashMap.Strict            as HMS+import           Data.Maybe                     (maybeToList) import qualified Data.Text                      as T import qualified Data.Text.IO                   as T import           Patat.Presentation.Instruction import           Patat.Presentation.Internal import           System.Exit                    (ExitCode (..)) import qualified System.IO                      as IO-import Data.Maybe (maybeToList) import           System.IO.Unsafe               (unsafeInterleaveIO) import qualified System.Process                 as Process import qualified Text.Pandoc.Definition         as Pandoc@@ -40,10 +40,11 @@  -------------------------------------------------------------------------------- evalSlide :: EvalSettingsMap -> Slide -> IO Slide-evalSlide settings slide = case slide of+evalSlide settings slide = case slideContent slide of     TitleSlide _ _ -> pure slide-    ContentSlide instrs -> ContentSlide . fromList . concat <$>-        traverse (evalInstruction settings) (toList instrs)+    ContentSlide instrs0 -> do+        instrs1 <- traverse (evalInstruction settings) (toList instrs0)+        pure slide {slideContent = ContentSlide . fromList $ concat instrs1}   --------------------------------------------------------------------------------
lib/Patat/Main.hs view
@@ -15,6 +15,7 @@ import           Control.Exception               (bracket) import           Control.Monad                   (forever, unless, when) import qualified Data.Aeson.Extended             as A+import           Data.Foldable                   (for_) import           Data.Functor                    (($>)) import           Data.Time                       (UTCTime) import           Data.Version                    (showVersion)@@ -23,6 +24,7 @@ import           Patat.AutoAdvance import qualified Patat.Images                    as Images import           Patat.Presentation+import qualified Patat.Presentation.SpeakerNotes as SpeakerNotes import qualified Patat.PrettyPrint               as PP import qualified Paths_patat import           Prelude@@ -137,14 +139,20 @@     unless (oForce options) assertAnsiFeatures      -- (Maybe) initialize images backend.-    images <- traverse Images.new (psImages $ pSettings pres)+    images <- traverse Images.new $ psImages $ pSettings pres -    if oDump options-        then dumpPresentation pres-        else interactiveLoop options images pres+    -- (Maybe) initialize speaker notes.+    withMaybeHandle SpeakerNotes.with+        (psSpeakerNotes $ pSettings pres) $ \speakerNotes ->++        if oDump options+            then dumpPresentation pres+            else interactiveLoop options images speakerNotes pres   where-    interactiveLoop :: Options -> Maybe Images.Handle -> Presentation -> IO ()-    interactiveLoop options images pres0 =+    interactiveLoop+        :: Options -> Maybe Images.Handle -> Maybe SpeakerNotes.Handle+        -> Presentation -> IO ()+    interactiveLoop options images speakerNotes pres0 =         interactively readPresentationCommand $ \commandChan0 -> do          -- If an auto delay is set, use 'autoAdvance' to create a new one.@@ -160,6 +168,9 @@          let loop :: Presentation -> Maybe String -> IO ()             loop pres mbError = do+                for_ speakerNotes $ \sn ->+                    SpeakerNotes.write sn $ activeSpeakerNotes pres+                 size <- getDisplaySize pres                 let display = case mbError of                         Nothing  -> displayPresentation size pres@@ -236,3 +247,14 @@     when (mtime1 > mtime0) $ Chan.writeChan chan Reload     threadDelay (200 * 1000)     watcher chan filePath mtime1+++--------------------------------------------------------------------------------+-- | Wrapper for optional handles.+withMaybeHandle+    :: (settings -> (handle -> IO a) -> IO a)+    -> Maybe settings+    -> (Maybe handle -> IO a)+    -> IO a+withMaybeHandle _    Nothing         f = f Nothing+withMaybeHandle impl (Just settings) f = impl settings (f . Just)
lib/Patat/Presentation.hs view
@@ -5,6 +5,8 @@     , Presentation (..)     , readPresentation +    , activeSpeakerNotes+     , Size     , getDisplaySize 
lib/Patat/Presentation/Display.hs view
@@ -13,17 +13,19 @@   ---------------------------------------------------------------------------------import           Control.Monad                        (mplus)+import           Control.Monad                        (guard, mplus) import qualified Data.Aeson.Extended                  as A import           Data.Char.WCWidth.Extended           (wcstrwidth) import           Data.Data.Extended                   (grecQ) import qualified Data.List                            as L-import           Data.Maybe                           (fromMaybe, listToMaybe,-                                                       maybeToList)+import           Data.Maybe                           (fromMaybe, maybeToList)+import qualified Data.Sequence.Extended               as Seq import qualified Data.Text                            as T import           Patat.Presentation.Display.CodeBlock+import           Patat.Presentation.Display.Internal import           Patat.Presentation.Display.Table import           Patat.Presentation.Internal+import qualified Patat.Presentation.SpeakerNotes      as SpeakerNotes import           Patat.PrettyPrint                    ((<$$>), (<+>)) import qualified Patat.PrettyPrint                    as PP import           Patat.Theme                          (Theme (..))@@ -59,7 +61,7 @@ -- | Display something within the presentation borders that draw the title and -- the active slide number and so on. displayWithBorders-    :: Size -> Presentation -> (Size -> Theme -> PP.Doc) -> PP.Doc+    :: Size -> Presentation -> (Size -> DisplaySettings -> PP.Doc) -> PP.Doc displayWithBorders (Size rows columns) Presentation {..} f =     (if null title         then mempty@@ -67,7 +69,7 @@             let titleRemainder = columns - titleWidth - titleOffset                 wrappedTitle = PP.spaces titleOffset <> PP.string title <> PP.spaces titleRemainder in         borders wrappedTitle <> PP.hardline <> PP.hardline) <>-    formatWith settings (f canvasSize theme) <> PP.hardline <>+    formatWith settings (f canvasSize ds) <> PP.hardline <>     PP.goToLine (rows - 2) <>     borders (PP.space <> PP.string author <> middleSpaces <> PP.string active <> PP.space) <>     PP.hardline@@ -75,14 +77,17 @@     -- Get terminal width/title     (sidx, _)   = pActiveFragment     settings    = pSettings {psColumns = Just $ A.FlexibleNum columns}-    theme       = fromMaybe Theme.defaultTheme (psTheme settings)+    ds          = DisplaySettings+        { dsTheme     = fromMaybe Theme.defaultTheme (psTheme settings)+        , dsSyntaxMap = pSyntaxMap+        }      -- Compute title.-    breadcrumbs = fromMaybe [] . listToMaybe $ drop sidx pBreadcrumbs-    plainTitle  = PP.toString $ prettyInlines theme pTitle+    breadcrumbs = fromMaybe [] $ Seq.safeIndex pBreadcrumbs sidx+    plainTitle  = PP.toString $ prettyInlines ds pTitle     breadTitle  = mappend plainTitle $ mconcat         [ s-        | b <- map (prettyInlines theme . snd) breadcrumbs+        | b <- map (prettyInlines ds . snd) breadcrumbs         , s <- [" > ", PP.toString b]         ]     title@@ -93,7 +98,7 @@     -- Dimensions of title.     titleWidth  = wcstrwidth title     titleOffset = (columns - titleWidth) `div` 2-    borders     = themed (themeBorders theme)+    borders     = themed ds themeBorders      -- Room left for content     canvasSize = Size (rows - 2) columns@@ -103,7 +108,7 @@         | fromMaybe True $ psSlideNumber settings = show (sidx + 1) ++ " / " ++ show (length pSlides)         | otherwise                               = ""     activeWidth  = wcstrwidth active-    author       = PP.toString (prettyInlines theme pAuthor)+    author       = PP.toString (prettyInlines ds pAuthor)     authorWidth  = wcstrwidth author     middleSpaces = PP.spaces $ columns - activeWidth - authorWidth - 2 @@ -111,7 +116,7 @@ -------------------------------------------------------------------------------- displayPresentation :: Size -> Presentation -> Display displayPresentation size pres@Presentation {..} =-     case getActiveFragment pres of+     case activeFragment pres of         Nothing -> DisplayDoc $ displayWithBorders size pres mempty         Just (ActiveContent fragment)                 | Just _ <- psImages pSettings@@ -135,10 +140,10 @@     -- Check if the fragment consists of "just a single image".  Discard     -- headers.     onlyImage (Fragment (Pandoc.Header{} : bs)) = onlyImage (Fragment bs)-    onlyImage (Fragment bs) = case filter isVisibleBlock bs of-        [Pandoc.Figure _ _ bs'] -> onlyImage (Fragment bs')+    onlyImage (Fragment bs) = case bs of+        [Pandoc.Figure _ _ bs']                      -> onlyImage (Fragment bs')         [Pandoc.Para [Pandoc.Image _ _ (target, _)]] -> Just target-        _ -> Nothing+        _                                            -> Nothing   --------------------------------------------------------------------------------@@ -146,8 +151,8 @@ -- want to display an error but keep the presentation running. displayPresentationError :: Size -> Presentation -> String -> PP.Doc displayPresentationError size pres err =-    displayWithBorders size pres $ \_ Theme {..} ->-        themed themeStrong "Error occurred in the presentation:" <$$>+    displayWithBorders size pres $ \_ ds ->+        themed ds themeStrong "Error occurred in the presentation:" <$$>         "" <$$>         (PP.string err) @@ -155,19 +160,35 @@ -------------------------------------------------------------------------------- dumpPresentation :: Presentation -> IO () dumpPresentation pres@Presentation {..} =-    let sRows = fromMaybe 24 $ A.unFlexibleNum <$> psRows pSettings-        sCols = fromMaybe 72 $ A.unFlexibleNum <$> psColumns pSettings-        size  = Size {..} in     PP.putDoc $ PP.removeControls $ formatWith pSettings $-    PP.vcat $ L.intersperse "----------" $ do-        i <- [0 .. length pSlides - 1]+    PP.vcat $ L.intercalate ["{slide}"] $+        map dumpSlide [0 .. length pSlides - 1]+  where+    dumpSlide :: Int -> [PP.Doc]+    dumpSlide i = do         slide <- maybeToList $ getSlide i pres-        j <- [0 .. numFragments slide - 1]-        case displayPresentation size pres {pActiveFragment = (i, j)} of-            DisplayDoc doc -> [doc]-            DisplayImage filepath -> [PP.string $ "image:" ++ filepath]+        dumpSpeakerNotes slide <> L.intercalate ["{fragment}"]+            [ dumpFragment (i, j)+            | j <- [0 .. numFragments slide - 1]+            ] +    dumpSpeakerNotes :: Slide -> [PP.Doc]+    dumpSpeakerNotes slide = do+        guard $ slideSpeakerNotes slide /= mempty+        pure $ PP.text $ "{speakerNotes: " <>+            SpeakerNotes.toText (slideSpeakerNotes slide) <> "}" +    dumpFragment :: Index -> [PP.Doc]+    dumpFragment idx =+        case displayPresentation size pres {pActiveFragment = idx} of+            DisplayDoc doc        -> [doc]+            DisplayImage filepath -> [PP.string $ "{image: " ++ filepath ++ "}"]++    sRows = fromMaybe 24 $ A.unFlexibleNum <$> psRows pSettings+    sCols = fromMaybe 72 $ A.unFlexibleNum <$> psColumns pSettings+    size  = Size {..}++ -------------------------------------------------------------------------------- formatWith :: PresentationSettings -> PP.Doc -> PP.Doc formatWith ps = wrap . indent@@ -181,34 +202,34 @@   ---------------------------------------------------------------------------------prettyFragment :: Theme -> Fragment -> PP.Doc-prettyFragment theme (Fragment blocks) =-    prettyBlocks theme blocks <>-    case prettyReferences theme blocks of+prettyFragment :: DisplaySettings -> Fragment -> PP.Doc+prettyFragment ds (Fragment blocks) =+    prettyBlocks ds blocks <>+    case prettyReferences ds blocks of         []   -> mempty         refs -> PP.hardline <> PP.vcat refs   ---------------------------------------------------------------------------------prettyBlock :: Theme -> Pandoc.Block -> PP.Doc+prettyBlock :: DisplaySettings -> Pandoc.Block -> PP.Doc -prettyBlock theme (Pandoc.Plain inlines) = prettyInlines theme inlines+prettyBlock ds (Pandoc.Plain inlines) = prettyInlines ds inlines -prettyBlock theme (Pandoc.Para inlines) =-    prettyInlines theme inlines <> PP.hardline+prettyBlock ds (Pandoc.Para inlines) =+    prettyInlines ds inlines <> PP.hardline -prettyBlock theme@Theme {..} (Pandoc.Header i _ inlines) =-    themed themeHeader (PP.string (replicate i '#') <+> prettyInlines theme inlines) <>+prettyBlock ds (Pandoc.Header i _ inlines) =+    themed ds themeHeader (PP.string (replicate i '#') <+> prettyInlines ds inlines) <>     PP.hardline -prettyBlock theme (Pandoc.CodeBlock (_, classes, _) txt) =-    prettyCodeBlock theme classes txt+prettyBlock ds (Pandoc.CodeBlock (_, classes, _) txt) =+    prettyCodeBlock ds classes txt -prettyBlock theme (Pandoc.BulletList bss) = PP.vcat+prettyBlock ds (Pandoc.BulletList bss) = PP.vcat     [ PP.indent-        (PP.NotTrimmable $ themed (themeBulletList theme) prefix)+        (PP.NotTrimmable $ themed ds themeBulletList prefix)         (PP.Trimmable "    ")-        (prettyBlocks theme' bs)+        (prettyBlocks ds' bs)     | bs <- bss     ] <> PP.hardline   where@@ -218,16 +239,18 @@         _            -> '-'      -- Cycle the markers.+    theme  = dsTheme ds     theme' = theme         { themeBulletListMarkers =             (\ls -> T.drop 1 ls <> T.take 1 ls) <$> themeBulletListMarkers theme         }+    ds'    = ds {dsTheme = theme'} -prettyBlock theme@Theme {..} (Pandoc.OrderedList _ bss) = PP.vcat+prettyBlock ds (Pandoc.OrderedList _ bss) = PP.vcat     [ PP.indent-        (PP.NotTrimmable $ themed themeOrderedList $ PP.string prefix)+        (PP.NotTrimmable $ themed ds themeOrderedList $ PP.string prefix)         (PP.Trimmable "    ")-        (prettyBlocks theme bs)+        (prettyBlocks ds bs)     | (prefix, bs) <- zip padded bss     ] <> PP.hardline   where@@ -237,34 +260,34 @@         | i <- [1 .. length bss]         ] -prettyBlock _theme (Pandoc.RawBlock _ t) = PP.text t <> PP.hardline+prettyBlock _ds (Pandoc.RawBlock _ t) = PP.text t <> PP.hardline -prettyBlock _theme Pandoc.HorizontalRule = "---"+prettyBlock _ds Pandoc.HorizontalRule = "---" -prettyBlock theme@Theme {..} (Pandoc.BlockQuote bs) =-    let quote = PP.NotTrimmable (themed themeBlockQuote "> ") in-    PP.indent quote quote (themed themeBlockQuote $ prettyBlocks theme bs)+prettyBlock ds (Pandoc.BlockQuote bs) =+    let quote = PP.NotTrimmable (themed ds themeBlockQuote "> ") in+    PP.indent quote quote (themed ds themeBlockQuote $ prettyBlocks ds bs) -prettyBlock theme@Theme {..} (Pandoc.DefinitionList terms) =+prettyBlock ds (Pandoc.DefinitionList terms) =     PP.vcat $ map prettyDefinition terms   where     prettyDefinition (term, definitions) =-        themed themeDefinitionTerm (prettyInlines theme term) <$$>+        themed ds themeDefinitionTerm (prettyInlines ds term) <$$>         PP.hardline <> PP.vcat         [ PP.indent-            (PP.NotTrimmable (themed themeDefinitionList ":   "))+            (PP.NotTrimmable (themed ds themeDefinitionList ":   "))             (PP.Trimmable "    ") $-            prettyBlocks theme (Pandoc.plainToPara definition)+            prettyBlocks ds (Pandoc.plainToPara definition)         | definition <- definitions         ] -prettyBlock theme (Pandoc.Table _ caption specs thead tbodies tfoot) =+prettyBlock ds (Pandoc.Table _ caption specs thead tbodies tfoot) =     PP.wrapAt Nothing $-    prettyTable theme Table-        { tCaption = prettyInlines theme caption'+    prettyTable ds Table+        { tCaption = prettyInlines ds caption'         , tAligns  = map align aligns-        , tHeaders = map (prettyBlocks theme) headers-        , tRows    = map (map (prettyBlocks theme)) rows+        , tHeaders = map (prettyBlocks ds) headers+        , tRows    = map (map (prettyBlocks ds)) rows         }   where     (caption', aligns, _, headers, rows) = Pandoc.toLegacyTable@@ -275,90 +298,91 @@     align Pandoc.AlignDefault = PP.AlignLeft     align Pandoc.AlignRight   = PP.AlignRight -prettyBlock theme (Pandoc.Div _attrs blocks) = prettyBlocks theme blocks+prettyBlock ds (Pandoc.Div _attrs blocks) = prettyBlocks ds blocks -prettyBlock theme@Theme {..} (Pandoc.LineBlock inliness) =-    let ind = PP.NotTrimmable (themed themeLineBlock "| ") in+prettyBlock ds (Pandoc.LineBlock inliness) =+    let ind = PP.NotTrimmable (themed ds themeLineBlock "| ") in     PP.wrapAt Nothing $     PP.indent ind ind $     PP.vcat $-    map (prettyInlines theme) inliness+    map (prettyInlines ds) inliness -prettyBlock theme (Pandoc.Figure _attr _caption blocks) =-    prettyBlocks theme blocks+prettyBlock ds (Pandoc.Figure _attr _caption blocks) =+    prettyBlocks ds blocks + ---------------------------------------------------------------------------------prettyBlocks :: Theme -> [Pandoc.Block] -> PP.Doc-prettyBlocks theme = PP.vcat . map (prettyBlock theme) . filter isVisibleBlock+prettyBlocks :: DisplaySettings -> [Pandoc.Block] -> PP.Doc+prettyBlocks ds = PP.vcat . map (prettyBlock ds)   ---------------------------------------------------------------------------------prettyInline :: Theme -> Pandoc.Inline -> PP.Doc+prettyInline :: DisplaySettings -> Pandoc.Inline -> PP.Doc -prettyInline _theme Pandoc.Space = PP.space+prettyInline _ds Pandoc.Space = PP.space -prettyInline _theme (Pandoc.Str str) = PP.text str+prettyInline _ds (Pandoc.Str str) = PP.text str -prettyInline theme@Theme {..} (Pandoc.Emph inlines) =-    themed themeEmph $-    prettyInlines theme inlines+prettyInline ds (Pandoc.Emph inlines) =+    themed ds themeEmph $+    prettyInlines ds inlines -prettyInline theme@Theme {..} (Pandoc.Strong inlines) =-    themed themeStrong $-    prettyInlines theme inlines+prettyInline ds (Pandoc.Strong inlines) =+    themed ds themeStrong $+    prettyInlines ds inlines -prettyInline theme@Theme {..} (Pandoc.Underline inlines) =-    themed themeUnderline $-    prettyInlines theme inlines+prettyInline ds (Pandoc.Underline inlines) =+    themed ds themeUnderline $+    prettyInlines ds inlines -prettyInline Theme {..} (Pandoc.Code _ txt) =-    themed themeCode $+prettyInline ds (Pandoc.Code _ txt) =+    themed ds themeCode $     PP.text (" " <> txt <> " ") -prettyInline theme@Theme {..} link@(Pandoc.Link _attrs text (target, _title))+prettyInline ds link@(Pandoc.Link _attrs text (target, _title))     | isReferenceLink link =-        "[" <> themed themeLinkText (prettyInlines theme text) <> "]"+        "[" <> themed ds themeLinkText (prettyInlines ds text) <> "]"     | otherwise =-        "<" <> themed themeLinkTarget (PP.text target) <> ">"+        "<" <> themed ds themeLinkTarget (PP.text target) <> ">" -prettyInline _theme Pandoc.SoftBreak = PP.softline+prettyInline _ds Pandoc.SoftBreak = PP.softline -prettyInline _theme Pandoc.LineBreak = PP.hardline+prettyInline _ds Pandoc.LineBreak = PP.hardline -prettyInline theme@Theme {..} (Pandoc.Strikeout t) =-    "~~" <> themed themeStrikeout (prettyInlines theme t) <> "~~"+prettyInline ds (Pandoc.Strikeout t) =+    "~~" <> themed ds themeStrikeout (prettyInlines ds t) <> "~~" -prettyInline theme@Theme {..} (Pandoc.Quoted Pandoc.SingleQuote t) =-    "'" <> themed themeQuoted (prettyInlines theme t) <> "'"-prettyInline theme@Theme {..} (Pandoc.Quoted Pandoc.DoubleQuote t) =-    "'" <> themed themeQuoted (prettyInlines theme t) <> "'"+prettyInline ds (Pandoc.Quoted Pandoc.SingleQuote t) =+    "'" <> themed ds themeQuoted (prettyInlines ds t) <> "'"+prettyInline ds (Pandoc.Quoted Pandoc.DoubleQuote t) =+    "'" <> themed ds themeQuoted (prettyInlines ds t) <> "'" -prettyInline Theme {..} (Pandoc.Math _ t) =-    themed themeMath (PP.text t)+prettyInline ds (Pandoc.Math _ t) =+    themed ds themeMath (PP.text t) -prettyInline theme@Theme {..} (Pandoc.Image _attrs text (target, _title)) =-    "![" <> themed themeImageText (prettyInlines theme text) <> "](" <>-    themed themeImageTarget (PP.text target) <> ")"+prettyInline ds (Pandoc.Image _attrs text (target, _title)) =+    "![" <> themed ds themeImageText (prettyInlines ds text) <> "](" <>+    themed ds themeImageTarget (PP.text target) <> ")"  -- These elements aren't really supported.-prettyInline theme  (Pandoc.Cite      _ t) = prettyInlines theme t-prettyInline theme  (Pandoc.Span      _ t) = prettyInlines theme t-prettyInline _theme (Pandoc.RawInline _ t) = PP.text t-prettyInline theme  (Pandoc.Note        t) = prettyBlocks  theme t-prettyInline theme  (Pandoc.Superscript t) = prettyInlines theme t-prettyInline theme  (Pandoc.Subscript   t) = prettyInlines theme t-prettyInline theme  (Pandoc.SmallCaps   t) = prettyInlines theme t+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+prettyInline ds  (Pandoc.SmallCaps   t) = prettyInlines ds t -- prettyInline unsupported = PP.ondullred $ PP.string $ show unsupported   ---------------------------------------------------------------------------------prettyInlines :: Theme -> [Pandoc.Inline] -> PP.Doc-prettyInlines theme = mconcat . map (prettyInline theme)+prettyInlines :: DisplaySettings -> [Pandoc.Inline] -> PP.Doc+prettyInlines ds = mconcat . map (prettyInline ds)   ---------------------------------------------------------------------------------prettyReferences :: Theme -> [Pandoc.Block] -> [PP.Doc]-prettyReferences theme@Theme {..} =+prettyReferences :: DisplaySettings -> [Pandoc.Block] -> [PP.Doc]+prettyReferences ds =     map prettyReference . getReferences   where     getReferences :: [Pandoc.Block] -> [Pandoc.Inline]@@ -367,9 +391,10 @@     prettyReference :: Pandoc.Inline -> PP.Doc     prettyReference (Pandoc.Link _attrs text (target, title)) =         "[" <>-        themed themeLinkText (prettyInlines theme $ Pandoc.newlineToSpace text) <>+        themed ds themeLinkText+            (prettyInlines ds $ Pandoc.newlineToSpace text) <>         "](" <>-        themed themeLinkTarget (PP.text target) <>+        themed ds themeLinkTarget (PP.text target) <>         (if T.null title             then mempty             else PP.space <> "\"" <> PP.text title <> "\"")@@ -382,10 +407,3 @@ isReferenceLink (Pandoc.Link _attrs text (target, _)) =     [Pandoc.Str target] /= text isReferenceLink _ = False------------------------------------------------------------------------------------isVisibleBlock :: Pandoc.Block -> Bool-isVisibleBlock (Pandoc.RawBlock (Pandoc.Format "html") t) =-    not ("<!--" `T.isPrefixOf` t && "-->" `T.isSuffixOf` t)-isVisibleBlock _ = True
lib/Patat/Presentation/Display/CodeBlock.hs view
@@ -1,30 +1,31 @@ -------------------------------------------------------------------------------- -- | Displaying code blocks, optionally with syntax highlighting. {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards   #-} module Patat.Presentation.Display.CodeBlock     ( prettyCodeBlock     ) where   ---------------------------------------------------------------------------------import           Data.Maybe                       (mapMaybe)-import qualified Data.Text                        as T-import           Patat.Presentation.Display.Table (themed)-import qualified Patat.PrettyPrint                as PP+import           Data.Maybe                          (mapMaybe)+import qualified Data.Text                           as T+import           Patat.Presentation.Display.Internal+import qualified Patat.PrettyPrint                   as PP import           Patat.Theme import           Prelude-import qualified Skylighting                      as Skylighting+import qualified Skylighting                         as Skylighting   ---------------------------------------------------------------------------------highlight :: [T.Text] -> T.Text -> [Skylighting.SourceLine]-highlight classes rawCodeBlock = case mapMaybe getSyntax classes of-    []        -> zeroHighlight rawCodeBlock-    (syn : _) ->-        case Skylighting.tokenize config syn rawCodeBlock of-            Left  _  -> zeroHighlight rawCodeBlock-            Right sl -> sl+highlight+    :: Skylighting.SyntaxMap -> [T.Text] -> T.Text -> [Skylighting.SourceLine]+highlight extraSyntaxMap classes rawCodeBlock =+    case mapMaybe getSyntax classes of+        []        -> zeroHighlight rawCodeBlock+        (syn : _) ->+            case Skylighting.tokenize config syn rawCodeBlock of+                Left  _  -> zeroHighlight rawCodeBlock+                Right sl -> sl   where     getSyntax :: T.Text -> Maybe Skylighting.Syntax     getSyntax c = Skylighting.lookupSyntax c syntaxMap@@ -36,7 +37,7 @@         }      syntaxMap :: Skylighting.SyntaxMap-    syntaxMap = Skylighting.defaultSyntaxMap+    syntaxMap = extraSyntaxMap <> Skylighting.defaultSyntaxMap   --------------------------------------------------------------------------------@@ -49,21 +50,22 @@   ---------------------------------------------------------------------------------prettyCodeBlock :: Theme -> [T.Text] -> T.Text -> PP.Doc-prettyCodeBlock theme@Theme {..} classes rawCodeBlock =-    PP.vcat (map blockified sourceLines) <>-    PP.hardline+prettyCodeBlock :: DisplaySettings -> [T.Text] -> T.Text -> PP.Doc+prettyCodeBlock ds classes rawCodeBlock =+    PP.vcat (map blockified sourceLines) <> PP.hardline   where     sourceLines :: [Skylighting.SourceLine]     sourceLines =-        [[]] ++ highlight classes rawCodeBlock ++ [[]]+        [[]] ++ highlight (dsSyntaxMap ds) classes rawCodeBlock ++ [[]]      prettySourceLine :: Skylighting.SourceLine -> PP.Doc     prettySourceLine = mconcat . map prettyToken      prettyToken :: Skylighting.Token -> PP.Doc-    prettyToken (tokenType, str) =-        themed (syntaxHighlight theme tokenType) (PP.string $ T.unpack str)+    prettyToken (tokenType, str) = themed+        ds+        (\theme -> syntaxHighlight theme tokenType)+        (PP.string $ T.unpack str)      sourceLineLength :: Skylighting.SourceLine -> Int     sourceLineLength line = sum [T.length str | (_, str) <- line]@@ -76,7 +78,7 @@         let len    = sourceLineLength line             indent = PP.NotTrimmable "   " in         PP.indent indent indent $-        themed themeCodeBlock $+        themed ds themeCodeBlock $             " " <>             prettySourceLine line <>             PP.string (replicate (blockWidth - len) ' ') <> " "
+ lib/Patat/Presentation/Display/Internal.hs view
@@ -0,0 +1,27 @@+--------------------------------------------------------------------------------+module Patat.Presentation.Display.Internal+    ( DisplaySettings (..)+    , themed+    ) where+++--------------------------------------------------------------------------------+import qualified Patat.PrettyPrint as PP+import qualified Patat.Theme       as Theme+import qualified Skylighting       as Skylighting+++--------------------------------------------------------------------------------+data DisplaySettings = DisplaySettings+    { dsTheme     :: !Theme.Theme+    , dsSyntaxMap :: !Skylighting.SyntaxMap+    }+++--------------------------------------------------------------------------------+themed+    :: DisplaySettings -> (Theme.Theme -> Maybe Theme.Style) -> PP.Doc -> PP.Doc+themed ds f = case f (dsTheme ds) of+    Nothing                  -> id+    Just (Theme.Style [])    -> id+    Just (Theme.Style codes) -> PP.ansi codes
lib/Patat/Presentation/Display/Table.hs view
@@ -10,11 +10,11 @@   ---------------------------------------------------------------------------------import           Data.List         (intersperse, transpose)-import           Patat.PrettyPrint ((<$$>))-import qualified Patat.PrettyPrint as PP-import           Patat.Theme       (Theme (..))-import qualified Patat.Theme       as Theme+import           Data.List                           (intersperse, transpose)+import           Patat.Presentation.Display.Internal+import           Patat.PrettyPrint                   ((<$$>))+import qualified Patat.PrettyPrint                   as PP+import           Patat.Theme                         (Theme (..)) import           Prelude  @@ -28,15 +28,15 @@   ---------------------------------------------------------------------------------prettyTable-    :: Theme -> Table -> PP.Doc-prettyTable theme@Theme {..} Table {..} =+prettyTable :: DisplaySettings -> Table -> PP.Doc+prettyTable ds Table {..} =     PP.indent (PP.Trimmable "  ") (PP.Trimmable "  ") $         lineIf (not isHeaderLess) (hcat2 headerHeight-            [ themed themeTableHeader (PP.align w a (vpad headerHeight header))+            [ themed ds themeTableHeader $+                PP.align w a (vpad headerHeight header)             | (w, a, header) <- zip3 columnWidths tAligns tHeaders             ]) <>-        dashedHeaderSeparator theme columnWidths <$$>+        dashedHeaderSeparator ds columnWidths <$$>         joinRows             [ hcat2 rowHeight                 [ PP.align w a (vpad rowHeight cell)@@ -44,7 +44,7 @@                 ]             | (rowHeight, row) <- zip rowHeights tRows             ] <$$>-        lineIf isHeaderLess (dashedHeaderSeparator theme columnWidths) <>+        lineIf isHeaderLess (dashedHeaderSeparator ds columnWidths) <>         lineIf             (not $ PP.null tCaption) (PP.hardline <> "Table: " <> tCaption)   where@@ -90,17 +90,9 @@   ---------------------------------------------------------------------------------dashedHeaderSeparator :: Theme -> [Int] -> PP.Doc-dashedHeaderSeparator Theme {..} columnWidths =+dashedHeaderSeparator :: DisplaySettings -> [Int] -> PP.Doc+dashedHeaderSeparator ds columnWidths =     mconcat $ intersperse (PP.string "  ")-        [ themed themeTableSeparator (PP.string (replicate w '-'))+        [ themed ds themeTableSeparator (PP.string (replicate w '-'))         | w <- columnWidths         ]-------------------------------------------------------------------------------------- | This does not really belong in the module.-themed :: Maybe Theme.Style -> PP.Doc -> PP.Doc-themed Nothing                    = id-themed (Just (Theme.Style []))    = id-themed (Just (Theme.Style codes)) = PP.ansi codes
lib/Patat/Presentation/Internal.hs view
@@ -20,6 +20,7 @@     , EvalSettings (..)      , Slide (..)+    , SlideContent (..)     , Instruction.Fragment (..)     , Index @@ -27,24 +28,30 @@     , numFragments      , ActiveFragment (..)-    , getActiveFragment+    , activeFragment+    , activeSpeakerNotes     ) where   ---------------------------------------------------------------------------------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 qualified Data.HashMap.Strict            as HMS-import           Data.List                      (intercalate)-import           Data.Maybe                     (fromMaybe, listToMaybe)-import qualified Data.Text                      as T-import qualified Patat.Presentation.Instruction as Instruction-import qualified Patat.Theme                    as Theme+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           Data.Maybe                      (fromMaybe)+import           Data.Sequence.Extended          (Seq)+import qualified Data.Sequence.Extended          as Seq+import qualified Data.Text                       as T+import qualified Patat.Presentation.Instruction  as Instruction+import qualified Patat.Presentation.SpeakerNotes as SpeakerNotes+import qualified Patat.Theme                     as Theme import           Prelude-import qualified Text.Pandoc                    as Pandoc-import           Text.Read                      (readMaybe)+import qualified Skylighting                     as Skylighting+import qualified Text.Pandoc                     as Pandoc+import           Text.Read                       (readMaybe)   --------------------------------------------------------------------------------@@ -57,9 +64,10 @@     , pTitle          :: ![Pandoc.Inline]     , pAuthor         :: ![Pandoc.Inline]     , pSettings       :: !PresentationSettings-    , pSlides         :: [Slide]-    , pBreadcrumbs    :: [Breadcrumbs]  -- One for each slide.+    , pSlides         :: !(Seq Slide)+    , pBreadcrumbs    :: !(Seq Breadcrumbs)  -- One for each slide.     , pActiveFragment :: !Index+    , pSyntaxMap      :: !Skylighting.SyntaxMap     } deriving (Show)  @@ -67,38 +75,42 @@ -- | These are patat-specific settings.  That is where they differ from more -- general metadata (author, title...) data PresentationSettings = PresentationSettings-    { psRows             :: !(Maybe (A.FlexibleNum Int))-    , psColumns          :: !(Maybe (A.FlexibleNum Int))-    , psMargins          :: !(Maybe Margins)-    , psWrap             :: !(Maybe Bool)-    , psTheme            :: !(Maybe Theme.Theme)-    , psIncrementalLists :: !(Maybe Bool)-    , psAutoAdvanceDelay :: !(Maybe (A.FlexibleNum Int))-    , psSlideLevel       :: !(Maybe Int)-    , psPandocExtensions :: !(Maybe ExtensionList)-    , psImages           :: !(Maybe ImageSettings)-    , psBreadcrumbs      :: !(Maybe Bool)-    , psEval             :: !(Maybe EvalSettingsMap)-    , psSlideNumber      :: !(Maybe Bool)+    { psRows              :: !(Maybe (A.FlexibleNum Int))+    , psColumns           :: !(Maybe (A.FlexibleNum Int))+    , psMargins           :: !(Maybe Margins)+    , psWrap              :: !(Maybe Bool)+    , psTheme             :: !(Maybe Theme.Theme)+    , psIncrementalLists  :: !(Maybe Bool)+    , psAutoAdvanceDelay  :: !(Maybe (A.FlexibleNum Int))+    , psSlideLevel        :: !(Maybe Int)+    , psPandocExtensions  :: !(Maybe ExtensionList)+    , psImages            :: !(Maybe ImageSettings)+    , psBreadcrumbs       :: !(Maybe Bool)+    , psEval              :: !(Maybe EvalSettingsMap)+    , psSlideNumber       :: !(Maybe Bool)+    , psSyntaxDefinitions :: !(Maybe [FilePath])+    , psSpeakerNotes      :: !(Maybe SpeakerNotes.Settings)     } deriving (Show)   -------------------------------------------------------------------------------- instance Semigroup PresentationSettings where     l <> r = PresentationSettings-        { psRows             = psRows             l `mplus` psRows             r-        , psColumns          = psColumns          l `mplus` psColumns          r-        , psMargins          = psMargins          l <>      psMargins          r-        , psWrap             = psWrap             l `mplus` psWrap             r-        , psTheme            = psTheme            l <>      psTheme            r-        , psIncrementalLists = psIncrementalLists l `mplus` psIncrementalLists r-        , psAutoAdvanceDelay = psAutoAdvanceDelay l `mplus` psAutoAdvanceDelay r-        , psSlideLevel       = psSlideLevel       l `mplus` psSlideLevel       r-        , psPandocExtensions = psPandocExtensions l `mplus` psPandocExtensions r-        , psImages           = psImages           l `mplus` psImages           r-        , psBreadcrumbs      = psBreadcrumbs      l `mplus` psBreadcrumbs      r-        , psEval             = psEval             l <>      psEval             r-        , psSlideNumber      = psSlideNumber      l `mplus` psSlideNumber      r+        { psRows              = on mplus psRows              l r+        , psColumns           = on mplus psColumns           l r+        , psMargins           = on (<>)  psMargins           l r+        , psWrap              = on mplus psWrap              l r+        , psTheme             = on (<>)  psTheme             l r+        , psIncrementalLists  = on mplus psIncrementalLists  l r+        , psAutoAdvanceDelay  = on mplus psAutoAdvanceDelay  l r+        , psSlideLevel        = on mplus psSlideLevel        l r+        , psPandocExtensions  = on mplus psPandocExtensions  l r+        , psImages            = on mplus psImages            l r+        , psBreadcrumbs       = on mplus psBreadcrumbs       l r+        , psEval              = on (<>)  psEval              l r+        , psSlideNumber       = on mplus psSlideNumber       l r+        , psSyntaxDefinitions = on (<>)  psSyntaxDefinitions l r+        , psSpeakerNotes      = on mplus psSpeakerNotes      l r         }  @@ -107,25 +119,15 @@     mappend = (<>)     mempty  = PresentationSettings                     Nothing Nothing Nothing Nothing Nothing Nothing Nothing-                    Nothing Nothing Nothing Nothing Nothing Nothing+                    Nothing Nothing Nothing Nothing Nothing Nothing Nothing+                    Nothing   -------------------------------------------------------------------------------- defaultPresentationSettings :: PresentationSettings-defaultPresentationSettings = PresentationSettings-    { psRows             = Nothing-    , psColumns          = Nothing-    , psMargins          = Just defaultMargins-    , psWrap             = Nothing+defaultPresentationSettings = mempty+    { psMargins          = Just defaultMargins     , psTheme            = Just Theme.defaultTheme-    , psIncrementalLists = Nothing-    , psAutoAdvanceDelay = Nothing-    , psSlideLevel       = Nothing-    , psPandocExtensions = Nothing-    , psImages           = Nothing-    , psBreadcrumbs      = Nothing-    , psEval             = Nothing-    , psSlideNumber      = Nothing     }  @@ -258,7 +260,14 @@   ---------------------------------------------------------------------------------data Slide+data Slide = Slide+    { slideSpeakerNotes :: !SpeakerNotes.SpeakerNotes+    , slideContent      :: !SlideContent+    } deriving (Show)+++--------------------------------------------------------------------------------+data SlideContent     = ContentSlide (Instruction.Instructions Pandoc.Block)     | TitleSlide   Int [Pandoc.Inline]     deriving (Show)@@ -271,13 +280,14 @@  -------------------------------------------------------------------------------- getSlide :: Int -> Presentation -> Maybe Slide-getSlide sidx = listToMaybe . drop sidx . pSlides+getSlide sidx = (`Seq.safeIndex` sidx) . pSlides   -------------------------------------------------------------------------------- numFragments :: Slide -> Int-numFragments (ContentSlide instrs) = Instruction.numFragments instrs-numFragments (TitleSlide _ _)      = 1+numFragments slide = case slideContent slide of+    ContentSlide instrs -> Instruction.numFragments instrs+    TitleSlide _ _      -> 1   --------------------------------------------------------------------------------@@ -288,15 +298,23 @@   ---------------------------------------------------------------------------------getActiveFragment :: Presentation -> Maybe ActiveFragment-getActiveFragment presentation = do+activeFragment :: Presentation -> Maybe ActiveFragment+activeFragment presentation = do     let (sidx, fidx) = pActiveFragment presentation     slide <- getSlide sidx presentation-    pure $ case slide of+    pure $ case slideContent slide of         TitleSlide lvl is -> ActiveTitle $             Pandoc.Header lvl Pandoc.nullAttr is         ContentSlide instrs -> ActiveContent $             Instruction.renderFragment fidx instrs+++--------------------------------------------------------------------------------+activeSpeakerNotes :: Presentation -> SpeakerNotes.SpeakerNotes+activeSpeakerNotes presentation = fromMaybe mempty $ do+    let (sidx, _) = pActiveFragment presentation+    slide <- getSlide sidx presentation+    pure $ slideSpeakerNotes slide   --------------------------------------------------------------------------------
lib/Patat/Presentation/Read.hs view
@@ -7,33 +7,38 @@     ( readPresentation        -- Exposed for testing mostly.+    , detectSlideLevel     , readMetaSettings     ) where   ---------------------------------------------------------------------------------import           Control.Monad.Except           (ExceptT (..), runExceptT,-                                                 throwError)-import           Control.Monad.Trans            (liftIO)-import qualified Data.Aeson                     as A-import qualified Data.Aeson.KeyMap              as AKM-import           Data.Bifunctor                 (first)-import           Data.Maybe                     (fromMaybe)-import qualified Data.Text                      as T-import qualified Data.Text.Encoding             as T-import qualified Data.Text.IO                   as T-import qualified Data.Yaml                      as Yaml-import           Patat.Eval                     (eval)+import           Control.Monad.Except            (ExceptT (..), runExceptT,+                                                  throwError)+import           Control.Monad.Trans             (liftIO)+import qualified Data.Aeson                      as A+import qualified Data.Aeson.KeyMap               as AKM+import           Data.Bifunctor                  (first)+import           Data.Maybe                      (fromMaybe)+import           Data.Sequence.Extended          (Seq)+import qualified Data.Sequence.Extended          as Seq+import qualified Data.Text                       as T+import qualified Data.Text.Encoding              as T+import qualified Data.Text.IO                    as T+import qualified Data.Yaml                       as Yaml+import           Patat.Eval                      (eval) import           Patat.Presentation.Fragment-import qualified Patat.Presentation.Instruction as Instruction+import qualified Patat.Presentation.Instruction  as Instruction import           Patat.Presentation.Internal+import qualified Patat.Presentation.SpeakerNotes as SpeakerNotes import           Prelude-import           System.Directory               (doesFileExist,-                                                 getHomeDirectory)-import           System.FilePath                (splitFileName, takeExtension,-                                                 (</>))-import qualified Text.Pandoc.Error              as Pandoc-import qualified Text.Pandoc.Extended           as Pandoc+import qualified Skylighting                     as Skylighting+import           System.Directory                (doesFileExist,+                                                  getHomeDirectory)+import           System.FilePath                 (splitFileName, takeExtension,+                                                  (</>))+import qualified Text.Pandoc.Error               as Pandoc+import qualified Text.Pandoc.Extended            as Pandoc   --------------------------------------------------------------------------------@@ -45,6 +50,8 @@     metaSettings <- ExceptT $ return $ readMetaSettings src     let settings = metaSettings <> homeSettings <> defaultPresentationSettings +    syntaxMap <- ExceptT $ readSyntaxMap $ fromMaybe [] $+        psSyntaxDefinitions settings     let pexts = fromMaybe defaultExtensionList (psPandocExtensions settings)     reader <- case readExtension pexts ext of         Nothing -> throwError $ "Unknown file extension: " ++ show ext@@ -53,29 +60,39 @@         Left  e -> throwError $ "Could not parse document: " ++ show e         Right x -> return x -    pres <- ExceptT $ pure $ pandocToPresentation filePath settings doc+    pres <- ExceptT $ pure $+        pandocToPresentation filePath settings syntaxMap doc     liftIO $ eval pres   where     ext = takeExtension filePath   --------------------------------------------------------------------------------+readSyntaxMap :: [FilePath] -> IO (Either String Skylighting.SyntaxMap)+readSyntaxMap =+    runExceptT .+    fmap (foldr Skylighting.addSyntaxDefinition mempty) .+    traverse (ExceptT . Skylighting.loadSyntaxFromFile)+++-------------------------------------------------------------------------------- readExtension     :: ExtensionList -> String     -> Maybe (T.Text -> Either Pandoc.PandocError Pandoc.Pandoc) readExtension (ExtensionList extensions) fileExt = case fileExt of-    ".markdown"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".md"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".mdown"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".mdtext"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".mdtxt"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".mdwn"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".mkd"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".mkdn"  -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".lhs" -> Just $ Pandoc.runPure . Pandoc.readMarkdown lhsOpts-    ""     -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts-    ".org" -> Just $ Pandoc.runPure . Pandoc.readOrg      readerOpts-    _      -> Nothing+    ".markdown" -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".md"       -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".mdown"    -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".mdtext"   -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".mdtxt"    -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".mdwn"     -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".mkd"      -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".mkdn"     -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".lhs"      -> Just $ Pandoc.runPure . Pandoc.readMarkdown lhsOpts+    ""          -> Just $ Pandoc.runPure . Pandoc.readMarkdown readerOpts+    ".org"      -> Just $ Pandoc.runPure . Pandoc.readOrg      readerOpts+    ".txt"      -> Just $ pure . Pandoc.readPlainText+    _           -> Nothing    where     readerOpts = Pandoc.def@@ -95,9 +112,11 @@  -------------------------------------------------------------------------------- pandocToPresentation-    :: FilePath -> PresentationSettings -> Pandoc.Pandoc+    :: FilePath -> PresentationSettings -> Skylighting.SyntaxMap+    -> Pandoc.Pandoc     -> Either String Presentation-pandocToPresentation pFilePath pSettings pandoc@(Pandoc.Pandoc meta _) = do+pandocToPresentation pFilePath pSettings pSyntaxMap+        pandoc@(Pandoc.Pandoc meta _) = do     let !pTitle          = case Pandoc.docTitle meta of             []    -> [Pandoc.Str . T.pack . snd $ splitFileName pFilePath]             title -> title@@ -155,19 +174,19 @@   ---------------------------------------------------------------------------------pandocToSlides :: PresentationSettings -> Pandoc.Pandoc -> [Slide]+pandocToSlides :: PresentationSettings -> Pandoc.Pandoc -> Seq.Seq Slide pandocToSlides settings pandoc =     let slideLevel   = fromMaybe (detectSlideLevel pandoc) (psSlideLevel settings)         unfragmented = splitSlides slideLevel pandoc-        fragmented   =-            [ case slide of-                TitleSlide   _ _        -> slide-                ContentSlide instrs0 -> ContentSlide $-                    fragmentInstructions fragmentSettings instrs0-            | slide <- unfragmented-            ] in-    fragmented+        fragmented   = map fragmentSlide unfragmented in+    Seq.fromList fragmented   where+    fragmentSlide slide = case slideContent slide of+        TitleSlide   _ _     -> slide+        ContentSlide instrs0 ->+            let instrs1 = fragmentInstructions fragmentSettings instrs0 in+            slide {slideContent = ContentSlide instrs1}+     fragmentSettings = FragmentSettings         { fsIncrementalLists = fromMaybe False (psIncrementalLists settings)         }@@ -178,16 +197,16 @@ -- header that occurs before a non-header in the blocks. detectSlideLevel :: Pandoc.Pandoc -> Int detectSlideLevel (Pandoc.Pandoc _meta blocks0) =-    go 6 blocks0+    go 6 $ SpeakerNotes.remove blocks0   where     go level (Pandoc.Header n _ _ : x : xs)-        | n < level && nonHeader x = go n xs-        | otherwise                = go level (x:xs)-    go level (_ : xs)              = go level xs-    go level []                    = level+        | n < level && not (isHeader x) = go n xs+        | otherwise                     = go level (x:xs)+    go level (_ : xs)                   = go level xs+    go level []                         = level -    nonHeader (Pandoc.Header _ _ _) = False-    nonHeader _                     = True+    isHeader (Pandoc.Header _ _ _) = True+    isHeader _                     = False   --------------------------------------------------------------------------------@@ -201,9 +220,10 @@     | otherwise                              = splitAtHeaders [] blocks0   where     mkContentSlide :: [Pandoc.Block] -> [Slide]-    mkContentSlide [] = []  -- Never create empty slides-    mkContentSlide bs =-        [ContentSlide $ Instruction.fromList [Instruction.Append bs]]+    mkContentSlide bs0 = case SpeakerNotes.partition bs0 of+        (_,  [])  -> [] -- Never create empty slides+        (sn, bs1) -> pure . Slide sn . ContentSlide $+            Instruction.fromList [Instruction.Append bs1]      splitAtRules blocks = case break (== Pandoc.HorizontalRule) blocks of         (xs, [])           -> mkContentSlide xs@@ -211,22 +231,27 @@      splitAtHeaders acc [] =         mkContentSlide (reverse acc)-    splitAtHeaders acc (b@(Pandoc.Header i _ txt) : bs)-        | i > slideLevel  = splitAtHeaders (b : acc) bs+    splitAtHeaders acc (b@(Pandoc.Header i _ txt) : bs0)+        | i > slideLevel  = splitAtHeaders (b : acc) bs0         | i == slideLevel =-            mkContentSlide (reverse acc) ++ splitAtHeaders [b] bs+            mkContentSlide (reverse acc) ++ splitAtHeaders [b] bs0         | otherwise       =-            mkContentSlide (reverse acc) ++ [TitleSlide i txt] ++-            splitAtHeaders [] bs+            let (sn, bs1) = SpeakerNotes.split bs0 in+            mkContentSlide (reverse acc) +++            [Slide sn $ TitleSlide i txt] +++            splitAtHeaders [] bs1     splitAtHeaders acc (b : bs) =         splitAtHeaders (b : acc) bs -collectBreadcrumbs :: [Slide] -> [Breadcrumbs]-collectBreadcrumbs = go []++--------------------------------------------------------------------------------+collectBreadcrumbs :: Seq Slide -> Seq Breadcrumbs+collectBreadcrumbs = go [] . fmap slideContent   where-    go breadcrumbs = \case-        [] -> []-        ContentSlide _ : slides -> breadcrumbs : go breadcrumbs slides-        TitleSlide lvl inlines : slides ->+    go breadcrumbs slides0 = case Seq.viewl slides0 of+        Seq.EmptyL -> Seq.empty+        ContentSlide _ Seq.:< slides ->+            breadcrumbs `Seq.cons` go breadcrumbs slides+        TitleSlide lvl inlines Seq.:< slides ->             let parent = filter ((< lvl) . fst) breadcrumbs in-            parent : go (parent ++ [(lvl, inlines)]) slides+            parent `Seq.cons` go (parent ++ [(lvl, inlines)]) slides
+ lib/Patat/Presentation/SpeakerNotes.hs view
@@ -0,0 +1,105 @@+--------------------------------------------------------------------------------+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE TemplateHaskell            #-}+module Patat.Presentation.SpeakerNotes+    ( SpeakerNotes+    , parse+    , toText+    , remove+    , split+    , partition++    , Settings+    , Handle+    , with+    , write+    ) where+++--------------------------------------------------------------------------------+import           Control.Exception      (bracket)+import           Control.Monad          (when)+import qualified Data.Aeson.TH.Extended as A+import qualified Data.IORef             as IORef+import           Data.List              (intersperse)+import qualified Data.Text              as T+import qualified Data.Text.IO           as T+import           System.Directory       (removeFile)+import qualified Text.Pandoc            as Pandoc+++--------------------------------------------------------------------------------+newtype SpeakerNotes = SpeakerNotes [T.Text]+    deriving (Eq, Monoid, Semigroup, Show)+++--------------------------------------------------------------------------------+parse :: Pandoc.Block -> Maybe SpeakerNotes+parse (Pandoc.RawBlock "html" t0) = do+    t1 <- T.stripPrefix "<!--" t0+    t2 <- T.stripSuffix "-->" t1+    pure $ SpeakerNotes [T.strip t2]+parse _ = Nothing+++--------------------------------------------------------------------------------+toText :: SpeakerNotes -> T.Text+toText (SpeakerNotes sn) = T.unlines $ intersperse mempty sn+++--------------------------------------------------------------------------------+remove :: [Pandoc.Block] -> [Pandoc.Block]+remove = snd . partition+++--------------------------------------------------------------------------------+-- | Take all speaker notes from the front of the list.  Return those and the+-- remaining blocks.+split :: [Pandoc.Block] -> (SpeakerNotes, [Pandoc.Block])+split = go []+  where+    go sn []                           = (mconcat (reverse sn), [])+    go sn (x : xs) | Just s <- parse x = go (s : sn) xs+    go sn xs                           = (mconcat (reverse sn), xs)+++--------------------------------------------------------------------------------+-- | Partition the list into speaker notes and other blocks.+partition :: [Pandoc.Block] -> (SpeakerNotes, [Pandoc.Block])+partition = go [] []+  where+    go sn bs []                           = (mconcat (reverse sn), reverse bs)+    go sn bs (x : xs) | Just s <- parse x = go (s : sn) bs xs+    go sn bs (x : xs)                     = go sn (x : bs) xs+++--------------------------------------------------------------------------------+data Settings = Settings+    { sFile :: !FilePath+    } deriving (Show)+++--------------------------------------------------------------------------------+data Handle = Handle+    { hSettings :: !Settings+    , hActive   :: !(IORef.IORef SpeakerNotes)+    }+++--------------------------------------------------------------------------------+with :: Settings -> (Handle -> IO a) -> IO a+with settings = bracket+    (Handle settings <$> IORef.newIORef mempty)+    (\_ -> removeFile (sFile settings))+++--------------------------------------------------------------------------------+write :: Handle -> SpeakerNotes -> IO ()+write h sn = do+    change <- IORef.atomicModifyIORef' (hActive h) $ \old -> (sn, old /= sn)+    when change $ T.writeFile (sFile $ hSettings h) $ toText sn+++--------------------------------------------------------------------------------+$(A.deriveFromJSON A.dropPrefixOptions ''Settings)
lib/Text/Pandoc/Extended.hs view
@@ -1,18 +1,21 @@ ---------------------------------------------------------------------------------{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE LambdaCase   #-}+{-# LANGUAGE LambdaCase #-} module Text.Pandoc.Extended     ( module Text.Pandoc      , plainToPara     , newlineToSpace++    , readPlainText     ) where   --------------------------------------------------------------------------------+import           Data.Char          (isSpace) import           Data.Data.Extended (grecT)-import           Text.Pandoc+import qualified Data.Text          as T import           Prelude+import           Text.Pandoc   --------------------------------------------------------------------------------@@ -28,3 +31,18 @@     SoftBreak -> Space     LineBreak -> Space     inline    -> inline+++--------------------------------------------------------------------------------+-- | A plain-text reader.  Always returns empty metadata.+readPlainText :: T.Text -> Pandoc+readPlainText = Pandoc mempty . pure . Plain . go+  where+    go txt0 = case T.uncons txt0 of+        Nothing           -> []+        Just (' ',  txt1) -> Space : go txt1+        Just ('\r', txt1) -> go txt1+        Just ('\n', txt1) -> SoftBreak : go txt1+        Just (c,    txt1) ->+            let (pre, post) = T.break isSpace txt1 in+            Str (T.cons c pre) : go post
patat.cabal view
@@ -1,5 +1,5 @@ Name:                patat-Version:             0.8.9.0+Version:             0.9.0.0 Synopsis:            Terminal-based presentations using Pandoc Description:         Terminal-based presentations using Pandoc. License:             GPL-2@@ -76,12 +76,14 @@     Patat.Presentation     Patat.Presentation.Display     Patat.Presentation.Display.CodeBlock+    Patat.Presentation.Display.Internal     Patat.Presentation.Display.Table     Patat.Presentation.Fragment     Patat.Presentation.Instruction     Patat.Presentation.Interactive     Patat.Presentation.Internal     Patat.Presentation.Read+    Patat.Presentation.SpeakerNotes     Patat.PrettyPrint     Patat.Theme @@ -90,6 +92,7 @@     Data.Aeson.TH.Extended     Data.Char.WCWidth.Extended     Data.Data.Extended+    Data.Sequence.Extended     Paths_patat     Text.Pandoc.Extended @@ -135,6 +138,7 @@     patat,     base             >= 4.8  && < 5,     directory        >= 1.2  && < 1.4,+    pandoc           >= 3.1  && < 3.2,     tasty            >= 1.2  && < 1.5,     tasty-hunit      >= 0.10 && < 0.11,     tasty-quickcheck >= 0.10 && < 0.11,
tests/haskell/Patat/Presentation/Read/Tests.hs view
@@ -3,31 +3,64 @@     ( tests     ) where -import qualified Data.Text               as T++-------------------------------------------------------------------------------- import           Patat.Presentation.Read import qualified Test.Tasty              as Tasty import qualified Test.Tasty.HUnit        as Tasty+import qualified Text.Pandoc             as Pandoc ++-------------------------------------------------------------------------------- tests :: Tasty.TestTree tests = Tasty.testGroup "Patat.Presentation.Read.Tests"-    [ Tasty.testCase "readMetaSettings" $+    [ testReadMetaSettings+    , testDetectSlideLevel+    ]+++--------------------------------------------------------------------------------+testReadMetaSettings :: Tasty.TestTree+testReadMetaSettings = Tasty.testCase "readMetaSettings" $         case readMetaSettings invalidMetadata of             Left _  -> pure ()             Right _ -> Tasty.assertFailure "expecting invalid metadata"-    ]+  where+    invalidMetadata =+        "---\n\+        \title: mixing tabs and spaces bad\n\+        \author: thoastbrot\n\+        \patat:\n\+        \    images:\n\+        \            backend: 'w3m'\n\+        \            path: '/usr/lib/w3m/w3mimgdisplay'\n\+        \    theme:\n\+        \\theader: [vividBlue,onDullBlack]\n\+        \        emph: [dullBlue,italic]\n\+        \...\n\+        \\n\+        \Hi!" -invalidMetadata :: T.Text-invalidMetadata =-    "---\n\-    \title: mixing tabs and spaces bad\n\-    \author: thoastbrot\n\-    \patat:\n\-    \    images:\n\-    \            backend: 'w3m'\n\-    \            path: '/usr/lib/w3m/w3mimgdisplay'\n\-    \    theme:\n\-    \\theader: [vividBlue,onDullBlack]\n\-    \        emph: [dullBlue,italic]\n\-    \...\n\-    \\n\-    \Hi!"++--------------------------------------------------------------------------------+testDetectSlideLevel :: Tasty.TestTree+testDetectSlideLevel = Tasty.testGroup "detectSlideLevel"+    [ Tasty.testCase "01" $+        (Tasty.@=?) 1 $ detectSlideLevel $ Pandoc.Pandoc mempty+            [ Pandoc.Header 1 mempty [Pandoc.Str "Intro"]+            , Pandoc.Para [Pandoc.Str "Hi"]+            ]+    , Tasty.testCase "02" $+        (Tasty.@=?) 2 $ detectSlideLevel $ Pandoc.Pandoc mempty+            [ Pandoc.Header 1 mempty [Pandoc.Str "Intro"]+            , Pandoc.Header 2 mempty [Pandoc.Str "Detail"]+            , Pandoc.Para [Pandoc.Str "Hi"]+            ]+    , Tasty.testCase "03" $+        (Tasty.@=?) 2 $ detectSlideLevel $ Pandoc.Pandoc mempty+            [ Pandoc.Header 1 mempty [Pandoc.Str "Intro"]+            , Pandoc.RawBlock "html" "<!-- Some speaker notes -->"+            , Pandoc.Header 2 mempty [Pandoc.Str "Detail"]+            , Pandoc.Para [Pandoc.Str "Hi"]+            ]+    ]