Skip to content

Conversation

@brandonchinn178
Copy link

This allows hooking into the rendering of Html. So to use ghc-syntax-highlighting on Haskell code blocks:

let mods =
      mempty
        { onCodeBlock = \origImpl info t ->
            let lang = T.takeWhile (not . isSpace) info in
            if lang `elem` ["haskell", "hs"]
              then htmlRaw $ myRenderFunction $ tokenizeHaskell t
              else origImpl info t
        }
runHtmlMod mods <$> commonmark fp text :: Either ParseError (Html ())

@jgm
Copy link
Owner

jgm commented Feb 3, 2023

I have an idea for a lighter-weight solution to the problem.

PR #102 adds a function transform that will apply a transformation to an HTML tree.

So for this application you'd just need something like

highlightHaskell :: Html a -> Html a
highlightHaskell = transform f
 where
  f (HtmlElement BlockElement "pre" [("class", "language-haskell")]
      (Just (HtmlElement InlineElement "code" codeAttr
       (Just (HtmlText t)))))
       = HtmlRaw (myRenderFunction $ tokenizeHaskell t)
  f x = x

I prefer this to adding a new module, a new type, and the need to add instances of the new type for extensions. That's a lot of additional complexity. What do you think?

@brandonchinn178
Copy link
Author

brandonchinn178 commented Feb 3, 2023

I was just thinking the same. It's good as a quick fix, but it does require you to know the internal details of how Html implements the IsBlock interface.

What do you think about having an intermediate representation

type Nodes = [Nodes]

data Node
  = NodeParagraph Nodes
  | NodeImage Text Text Nodes
  | ...

? That way one could transform the Markdown AST however they want, then run a nodesToHtml :: Nodes -> Text function to render HTML text? Or even fromNodes :: IsBlock il b => Nodes -> b.

I'm asking this because I'm also hitting a second thing where I'd like to do other, more complex transformations, like converting one code block depending on a previous code block

@jgm
Copy link
Owner

jgm commented Feb 3, 2023

That amounts to defining an AST and adding IsBlock and IsInline instances for it, plus a renderer from that AST type to Html. The architecture of commonmark-hs is meant to enable this, but I didn't use an AST in core for two reasons:

  • performance is likely better going direct to HTML and not constructing the intermediate structure
  • difficult to see how to make the AST extensible to handle extensions

@jgm
Copy link
Owner

jgm commented Feb 3, 2023

If you don't mind depending on pandoc for rendering, you could just use commonmark-pandoc.

@jgm
Copy link
Owner

jgm commented Feb 3, 2023

Or use commonmark-pandoc (which only depends on pandoc-types) but write your own custom HTML renderer for Pandoc so you don't need to depend on pandoc.

@brandonchinn178
Copy link
Author

It wouldnt change existing behavior, so current uses of commonmark ... :: Html () would still go direct Text -> Html. It would just optionally enable someone to do Text -> Nodes -> Html, if someone wants to inspect or transform the AST in the middle.

I have an idea for handling extensions well; will put up a new PR when I finish

@jgm
Copy link
Owner

jgm commented Feb 4, 2023

New idea: what if we generalize transform (from PR #102):

transformM :: Monad m => (Html a -> m (Html a)) -> Html a -> m (Html a)

This would be trivial. Then you could use a State monad to keep track of what you've done in the previous code block, for example.

@brandonchinn178
Copy link
Author

Sure, but it still seems a bit too level. Also the biggest issue is that none of the Html constructors are exported, which is what started all of this

@jgm
Copy link
Owner

jgm commented Feb 4, 2023

Yes, if we did this we'd need to export the constructors too. Not sure what you mean by "too level."

I'm open to suggestions, but I am interested in keeping the core library simple, and adding an AST type plus a renderer from the AST to HTML, which would have to be kept in sync with the direct path to HTML, does add quite a bit of complexity. I'm curious about the idea for extensible AST.

@brandonchinn178
Copy link
Author

Sorry, I meant "too low level". My idea does get a bit complex, so I don't have any expectations of getting it merged, but I'll put it up for educational purposes 😛

@brandonchinn178 brandonchinn178 deleted the html-mod branch February 4, 2023 19:46
@jgm
Copy link
Owner

jgm commented Feb 4, 2023

I updated my PR to export transformM and the constructors.
Still not sure about merging it.
I'll have a look at your alternative when I have a chance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants