Cmarkit_renderer
Renderer 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 -> string
doc_to_string r d
renders document d
to a string using renderer r
.
val buffer_add_doc : t -> Stdlib.Buffer.t -> Cmarkit.Doc.t -> unit
buffer_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 -> bool
The 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 -> bool
The 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 -> bool
The 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 ->
t
make ?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 -> unit
init_context r
is the context initalization function for r
.
module Context : sig ... end
Rendering 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.renderer
type 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 doc
The custom_html_of_doc
function performs your extended renderings.