Cmarkit_rendererRenderer abstraction.
Stateful renderer abstraction to render documents in Stdlib.Buffer.t values.
Note. This is a low-level interface. For quick and standard renderings see Cmarkit_html.of_doc, Cmarkit_latex.of_doc and Cmarkit_commonmark.of_doc. If you want to extend them, see this example.
val doc_to_string : t -> Cmarkit.Doc.t -> stringdoc_to_string r d renders document d to a string using renderer r.
val buffer_add_doc : t -> Stdlib.Buffer.t -> Cmarkit.Doc.t -> unitbuffer_add_doc r b d renders document d on buffer b using renderer r.
The type for rendering contexts, holds a renderer, a Stdlib.Buffer.t value to act on and rendering state.
type inline = context -> Cmarkit.Inline.t -> boolThe type for inline renderers.
Return false if you are not interested in rendering the given inline. Use Context.inline and Context.block on the given context if you need to invoke the renderer recursively.
type block = context -> Cmarkit.Block.t -> boolThe type for block renderers.
Return false if you are not interested in rendering the given block. Use Context.inline and Context.block with the given context if you need to invoke the renderer recursively.
type doc = context -> Cmarkit.Doc.t -> boolThe type for document renderers.
Return false if you are not interested in rendering the given document. Use Context.inline, Context.block and Context.doc with the given context if you need to invoke the renderer recursively.
val make :
?init_context:(context -> Cmarkit.Doc.t -> unit) ->
?inline:inline ->
?block:block ->
?doc:doc ->
unit ->
tmake ?init_context ?inline ?block ?doc () is a renderer using inline, block, doc to render documents. They all default to (fun _ _ -> false), which means that by default they defer to next renderer (see compose).
init_context is used to initialize the context for the renderer before a document render. It defaults to fun _ _ -> ().
compose g f renders first with f and if a renderer returns false, falls back on its counterpart in g.
The init_context of the result calls g's initialization context function first, followed by the one of f. This means f's initialization function can assume the context is already setup for g.
Normally you should not need these but you may want to peek into other renderers.
val init_context : t -> context -> Cmarkit.Doc.t -> unitinit_context r is the context initalization function for r.
module Context : sig ... endRendering contexts.
This example extends the Cmarkit_html.renderer but it applies mutatis mutandis to the other backend document renderers.
Let's assume you want to:
Doc block which allows to splice documents in another one (note that splicing is already built-in via the Cmarkit.Block.Blocks block case).Cmarkit.Inline.Image inlines to render HTML video or audio elements depending on the link's destination suffix.Cmarkit_html.renderer renderer as it exists.This boils down to:
custom_html renderer which treats Cmarkit.Inline.Image and the new Doc case the way we see it fit and return false otherwise to use the built-in renderer.compose custom_html with Cmarkit_html.renderertype Cmarkit.Block.t += Doc of Cmarkit.Doc.t (* 1 *)
let media_link c l =
let has_ext s ext = String.ends_with ~suffix:ext s in
let is_video s = List.exists (has_ext s) [".mp4"; ".webm"] in
let is_audio s = List.exists (has_ext s) [".mp3"; ".flac"] in
let defs = Cmarkit_renderer.Context.get_defs c in
match Cmarkit.Inline.Link.reference_definition defs l with
| Some Cmarkit.Link_definition.Def (ld, _) ->
let start_tag = match Cmarkit.Link_definition.dest ld with
| Some (src, _) when is_video src -> Some ("<video", src)
| Some (src, _) when is_audio src -> Some ("<audio", src)
| None | Some _ -> None
in
begin match start_tag with
| None -> false (* let the default HTML renderer handle that *)
| Some (start_tag, src) ->
(* More could be done with the reference title and link text *)
Cmarkit_renderer.Context.string c start_tag;
Cmarkit_renderer.Context.string c {| src="|};
Cmarkit_html.pct_encoded_string c src;
Cmarkit_renderer.Context.string c {|" />|};
true
end
| None | Some _ -> false (* let the default HTML renderer that *)
let custom_html =
let inline c = function
| Cmarkit.Inline.Image (l, _) -> media_link c l
| _ -> false (* let the default HTML renderer handle that *)
in
let block c = function
| Doc d ->
(* It's important to recurse via Cmarkit_renderer.Context.block *)
Cmarkit_renderer.Context.block c (Cmarkit.Doc.block d); true
| _ -> false (* let the default HTML renderer handle that *)
in
Cmarkit_renderer.make ~inline ~block () (* 2 *)
let custom_html_of_doc ~safe doc =
let default = Cmarkit_html.renderer ~safe () in
let r = Cmarkit_renderer.compose default custom_html in (* 3 *)
Cmarkit_renderer.doc_to_string r docThe custom_html_of_doc function performs your extended renderings.