diff --git a/README.md b/README.md index f2d653f..d11b2bc 100644 --- a/README.md +++ b/README.md @@ -586,6 +586,8 @@ empty list `[]`. ### Images +#### Native Images support + `patat-0.8.0.0` and newer include images support for some terminal emulators. ```markdown @@ -624,6 +626,33 @@ patat: 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.: @@ -660,6 +689,7 @@ _evaluator_ by specifying this in the YAML metadata: command: irb --noecho --noverbose fragment: true # Optional replace: false # Optional + wrap: code # Optional ... Here is an example of a code block that is evaluated: @@ -681,6 +711,12 @@ Aside from the command, there are two more options: 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. diff --git a/lib/Patat/Eval.hs b/lib/Patat/Eval.hs index b0bf70a..ba639f3 100644 --- a/lib/Patat/Eval.hs +++ b/lib/Patat/Eval.hs @@ -15,6 +15,7 @@ import qualified Data.Text as T 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 @@ evalBlock settings orig@(Pandoc.CodeBlock attr@(_, classes, _) txt) 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 diff --git a/lib/Patat/Presentation/Display.hs b/lib/Patat/Presentation/Display.hs index de14013..69c8df6 100644 --- a/lib/Patat/Presentation/Display.hs +++ b/lib/Patat/Presentation/Display.hs @@ -352,10 +352,11 @@ prettyInline ds (Pandoc.Image _attrs text (target, _title)) = "![" <> 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 diff --git a/lib/Patat/Presentation/Settings.hs b/lib/Patat/Presentation/Settings.hs index d870142..ac86cb5 100644 --- a/lib/Patat/Presentation/Settings.hs +++ b/lib/Patat/Presentation/Settings.hs @@ -14,6 +14,7 @@ module Patat.Presentation.Settings , ImageSettings (..) , EvalSettingsMap + , EvalSettingsWrap (..) , EvalSettings (..) , SpeakerNotesSettings (..) @@ -23,18 +24,18 @@ module Patat.Presentation.Settings -------------------------------------------------------------------------------- -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.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) -------------------------------------------------------------------------------- @@ -195,11 +196,29 @@ instance A.FromJSON ImageSettings where type EvalSettingsMap = HMS.HashMap T.Text EvalSettings +-------------------------------------------------------------------------------- +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 +226,9 @@ data EvalSettings = EvalSettings 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 -------------------------------------------------------------------------------- diff --git a/tests/golden/inputs/eval06.md b/tests/golden/inputs/eval06.md new file mode 100644 index 0000000..bf6e9cb --- /dev/null +++ b/tests/golden/inputs/eval06.md @@ -0,0 +1,52 @@ +--- +patat: + eval: + shImplicit: + command: sh + wrap: code + replace: true + fragment: false + shCode: + command: sh + wrap: code + replace: true + fragment: false + shRaw: + command: sh + wrap: raw + replace: true + fragment: false + shInline: + command: sh + wrap: rawInline + replace: true + fragment: false +... + +# Implicit eval slide + +~~~{.shImplicit} +printf '\e[1;34m%-6s\e[m' "This is text" +~~~ + +# Code eval slide + +~~~{.shCode} +printf '\e[1;34m%-6s\e[m' "This is text" +~~~ + +# Raw eval slide + +~~~{.shRaw} +printf '\e[1;34m%-6s\e[m' "This is text" +~~~ + +Newline here... + +# Raw Inline eval slide + +~~~{.shInline} +printf '\e[1;34m%-6s\e[m' "This is text" +~~~ + +No newline here... diff --git a/tests/golden/outputs/eval06.md.dump b/tests/golden/outputs/eval06.md.dump new file mode 100644 index 0000000..d1e36f8 --- /dev/null +++ b/tests/golden/outputs/eval06.md.dump @@ -0,0 +1,41 @@ + eval06.md  + +# Implicit eval slide + +   +  This is text  +   + + 1 / 4  + +{slide} + eval06.md  + +# Code eval slide + +   +  This is text  +   + + 2 / 4  + +{slide} + eval06.md  + +# Raw eval slide + +This is text + +Newline here... + + 3 / 4  + +{slide} + eval06.md  + +# Raw Inline eval slide + +This is text +No newline here... + + 4 / 4