Skip to content

Commit

Permalink
Add eval.wrap option
Browse files Browse the repository at this point in the history
This adds a new `wrap` section to the `eval` configuration.

By default, the output is wrapped in a code block again with the original syntax
highlighting.  You can customize this behaviour by setting `wrap` to:

 *  `code`: the default setting.
 *  `raw`: no formatting applied.
 *  `rawInline`: no formatting applied and no trailing newline.

You can use `rawInline` to draw graphics.  In order to do that, for example,
we could configure `kitten` code snippets to evaluate using [Kitty]'s command
`icat`.  This uses the `rawInline` code setting to ensure that the resulting
output is not wrapped in a code block, and the `fragment` and `replace` settings
immediately replace the snippet:

    ---
    patat:
      eval:
        kitten:
          command: sed 's/^/kitten /' | bash
          replace: true
          fragment: false
          wrap: rawInline
    ...

    See, for example:

    ```kitten
    icat --align left dank-meme.jpg
    ```
  • Loading branch information
jaspervdj committed Nov 25, 2023
1 parent d83e06a commit c5443c3
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 17 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.:
Expand Down Expand Up @@ -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:
Expand All @@ -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.
Expand Down
14 changes: 10 additions & 4 deletions lib/Patat/Eval.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion lib/Patat/Presentation/Display.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 32 additions & 12 deletions lib/Patat/Presentation/Settings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module Patat.Presentation.Settings
, ImageSettings (..)

, EvalSettingsMap
, EvalSettingsWrap (..)
, EvalSettings (..)

, SpeakerNotesSettings (..)
Expand All @@ -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)


--------------------------------------------------------------------------------
Expand Down Expand Up @@ -195,20 +196,39 @@ 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)


--------------------------------------------------------------------------------
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


--------------------------------------------------------------------------------
Expand Down
52 changes: 52 additions & 0 deletions tests/golden/inputs/eval06.md
Original file line number Diff line number Diff line change
@@ -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...
41 changes: 41 additions & 0 deletions tests/golden/outputs/eval06.md.dump
Original file line number Diff line number Diff line change
@@ -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 

0 comments on commit c5443c3

Please sign in to comment.