From 575340fbf3fb1a8a95f2612b5726787c6fd68ef5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Thu, 24 Oct 2019 14:49:38 +0200
Subject: [PATCH] [markdown] smart constructors

---
 src/libraries/utils/markdown.ml             | 106 +++++++++-----
 src/libraries/utils/markdown.mli            | 145 +++++++++++++++-----
 src/plugins/markdown-report/eva_coverage.ml |   8 +-
 src/plugins/markdown-report/md_gen.ml       |  81 +++++------
 src/plugins/markdown-report/sarif_gen.ml    |   4 +-
 src/plugins/server/doc.ml                   |   2 +-
 src/plugins/server/request.ml               |   4 +-
 src/plugins/server/syntax.ml                |  45 +++---
 src/plugins/server/syntax.mli               |   2 +-
 9 files changed, 241 insertions(+), 156 deletions(-)

diff --git a/src/libraries/utils/markdown.ml b/src/libraries/utils/markdown.ml
index 612c40a9019..2f9e3555411 100644
--- a/src/libraries/utils/markdown.ml
+++ b/src/libraries/utils/markdown.ml
@@ -72,26 +72,65 @@ type pandoc_markdown =
     elements: elements
   }
 
-let plain s = [ Plain s]
+let glue ?sep ls =
+  match sep , ls with
+  | (None | Some []) , _ -> List.concat ls
+  | _ , [] -> []
+  | _ , [l] -> l
+  | Some s , ls -> (* tailrec *)
+    let rec aux w s = function
+      | [] -> List.rev w
+      | [e] -> List.rev_append w e
+      | e::el -> aux s (List.rev_append s (List.rev_append e w)) el
+    in aux s [] ls
+
+(* -------------------------------------------------------------------------- *)
+(* --- Formatting                                                         --- *)
+(* -------------------------------------------------------------------------- *)
+
+let plain s = [ Plain s ]
+let emph s = [ Emph s ]
+let bold s = [ Bold s ]
+let code s = [ Inline_code s ]
+
+let format txt = Format.kasprintf plain txt
+
+let image ~alt ~file = [Image(alt,file)]
+
+let mklink ?text href =
+  let txt =
+    match text with Some txt -> txt | None ->
+      let tt = match href with URL u -> u | Page p -> p | Section(_,s) -> s in
+      [Inline_code tt]
+  in [Link(txt, href)]
+
+let url ?text href = mklink ?text (URL href)
+
+let link ?text ?page ?name () =
+  mklink ?text @@ match page, name with
+  | None, None -> Page ""
+  | Some p, None -> Page p
+  | None, Some a -> Section("",a)
+  | Some p, Some a -> Section(p,a)
+
+let codeblock lang pp code =
+  let s = Format.asprintf "@[%a@]" pp code in
+  let lines = String.split_on_char '\n' s in
+  [Code_block (lang, lines)]
 
-let plain_format txt = Format.kasprintf plain txt
+let text text = [Text text]
+let list items = [UL items]
+let enum items = [OL items]
+let description items = [DL items]
 
-let link_current_page sec = Section("", sec)
+let block b = [Block b]
+let par text = [Block [Text text]]
 
-let plain_link h =
-  let s = match h with
-    | URL url -> url
-    | Page p -> p
-    | Section (_,s) -> s
-  in
-  Link ([Inline_code s], h)
+(* -------------------------------------------------------------------------- *)
+(* --- Sectioning                                                         --- *)
+(* -------------------------------------------------------------------------- *)
 
-let codelines lang pp code =
-  let s = Format.asprintf "@[%a@]" pp code in
-  let lines = String.split_on_char '\n' s in
-  Code_block (lang, lines)
-
-let raw_markdown filename =
+let rawfile filename =
   let chan = open_in filename in
   let res = ref [] in
   try
@@ -101,17 +140,9 @@ let raw_markdown filename =
     assert false
   with End_of_file ->
     close_in chan;
-    Raw (List.rev !res)
-
-let glue ?(sep=[]) texts =
-  let rec aux = function
-    | [] -> []
-    | [t] -> t
-    | hd::tl -> hd @ sep @ aux tl
-  in
-  aux texts
+    [Raw (List.rev !res)]
 
-let id m =
+let label m =
   let buffer = Buffer.create (String.length m) in
   let lowercase = Char.lowercase_ascii in
   let dash = ref false in
@@ -129,12 +160,8 @@ let id m =
   Buffer.contents buffer
 
 let section ?name ~title elements =
-  let anchor =
-    match name with
-    | None -> id title
-    | Some n -> n
-  in
-  (H1 (plain title, Some anchor)) :: elements
+  let anchor = label @@ match name with Some n -> n | None -> title in
+  (H1 ([Plain title], Some anchor)) :: elements
 
 let subsections header body =
   let body =
@@ -151,11 +178,11 @@ let subsections header body =
 
 let mk_date () =
   let tm = Unix.gmtime (Unix.time()) in
-  plain
-    (Printf.sprintf "%d-%02d-%02d"
-       (1900 + tm.Unix.tm_year) (1 + tm.Unix.tm_mon) tm.Unix.tm_mday)
+  format "%d-%02d-%02d"
+    (1900 + tm.Unix.tm_year)
+    (1 + tm.Unix.tm_mon) tm.Unix.tm_mday
 
-let pandoc ?(title=plain "") ?(authors=[]) ?(date=mk_date()) elements =
+let pandoc ?(title=[Plain ""]) ?(authors=[]) ?(date=mk_date()) elements =
   { title; authors; date; elements }
 
 let relativize page target =
@@ -182,7 +209,7 @@ let relativize page target =
 let pp_href ?(page="") fmt = function
   | URL s -> Format.pp_print_string fmt s
   | Page s -> Format.pp_print_string fmt (relativize page s)
-  | Section (p,s) -> Format.fprintf fmt "%s#%s" (relativize page p) (id s)
+  | Section (p,s) -> Format.fprintf fmt "%s#%s" (relativize page p) (label s)
 
 let rec pp_inline ?page fmt =
   function
@@ -200,7 +227,10 @@ and pp_text ?page fmt l =
   | [] -> ()
   | [ elt ] -> pp_inline ?page fmt elt
   | elt :: text ->
-    Format.fprintf fmt "%a@ %a" (pp_inline ?page) elt (pp_text ?page) text
+    (* tailrec *)
+    pp_inline ?page fmt elt ;
+    Format.pp_print_space fmt () ;
+    pp_text ?page fmt text
 
 let pp_lab fmt = function
   | None -> ()
diff --git a/src/libraries/utils/markdown.mli b/src/libraries/utils/markdown.mli
index 71ba39525a2..afa491d9302 100644
--- a/src/libraries/utils/markdown.mli
+++ b/src/libraries/utils/markdown.mli
@@ -20,10 +20,17 @@
 (*                                                                        *)
 (**************************************************************************)
 
+(** {2 Markdown Document}
+    Structured representation of Markdown content. *)
+
+(** Table columns alignment *)
 type align = Left | Center | Right
 
+(** Local refs and URLs *)
 type href =
-  | URL of string (** uninterpreted URL *)
+  | URL of string
+  (** URL href is printed as it is. *)
+
   | Page of string
   (** URL relative to a common root.
       During pretty-printing, if given the path of the current
@@ -31,20 +38,22 @@ type href =
       when writing to [foo/bar.md], [Page "foo/bla.md"] will be output as
       [(bla.md)].
   *)
-  | Section of string * string (** URL of an anchor within a [Page] *)
+
+  | Section of string * string
+  (** URL of an anchor within a [Page], see above. *)
 
 type inline =
-  | Plain of string
-  | Emph of string
-  | Bold of string
-  | Inline_code of string
-  | Link of text * href
-  | Image of string * string (** [Image(alt,location)] *)
+  | Plain of string (** Printed as it is *)
+  | Emph of string (** Printed as ["_……_"] *)
+  | Bold of string (** Printed as ["**……**"] *)
+  | Inline_code of string (** Printed as ["`……`"] *)
+  | Link of text * href (** Hyperlink with text and URL *)
+  | Image of string * string (** [Image(alt,path)] with alternative text and image file *)
 
-and text = inline list
+and text = inline list (** Inline elements separated by spaces *)
 
 type block_element =
-  | Text of text (** single paragraph of text. *)
+  | Text of text (** Single paragraph of text. *)
   | Block_quote of element list
   | UL of block list
   | OL of block list
@@ -78,34 +87,92 @@ type pandoc_markdown =
     elements: elements
   }
 
-(** creates a document from a list of elements and optional metadatas.
-    Defaults are:
-    - title: empty
-    - authors: empty list
-    - date: current day, in ISO format
-*)
-val pandoc:
-  ?title:text -> ?authors: text list -> ?date: text -> elements ->
-  pandoc_markdown
+(** {2 Formatting Utilities}
 
-(** get the content of a file as raw markdown.
-    @raise Sys_error if there's no such file.
+    Remark: [text] values are list of [inline] values, hence
+    you may combined with the [(@)] operator or with the [glue ?sep] utility
+    function (see below).
 *)
-val raw_markdown: string -> element
 
+(** Plain markdown *)
 val plain: string -> text
 
-val plain_format: ('a, Format.formatter, unit, text) format4 -> 'a
+(** Emph text *)
+val emph: string -> text
+
+(** Bold text *)
+val bold: string -> text
+
+(** Inline code *)
+val code: string -> text
+
+(** Image *)
+val image: alt:string -> file:string -> text
+
+(** Local links *)
+val link: ?text:text -> ?page:string -> ?name:string -> unit -> text
+
+(** URL links *)
+val url: ?text:text -> string -> text
+
+(** Plain markdown content of the formatted string *)
+val format: ('a, Format.formatter, unit, text) format4 -> 'a
+
+(** {2 Blocks Utilities}
+
+    Remark: [block] values are list of [block_element] values, hence
+    you may combined with the [(@)] operator or with the [glue ?sep] utility
+    function (see below).
+*)
+
+(** Text Block *)
+val text : text -> block
+
+(** Itemized list *)
+val list : block list -> block
+
+(** Enumerated list *)
+val enum : block list -> block
 
-(** glue text fragments. *)
-val glue: ?sep: text -> text list -> text
+(** Description list *)
+val description : (text * text) list -> block
 
-(** transforms a string into an anchor name, roughly following
-    pandoc's conventions.
+(** [codeblock lang pp code] returns a [Code_block] for [code],
+    written in [lang], as pretty-printed by [pp]. *)
+val codeblock:
+  string -> (Format.formatter -> 'a -> unit) -> 'a -> block
+
+(** {2 Document Elements}
+
+    Remark: [elements] values are list of [element] values, hence
+    you may combined with the [(@)] operator or with the [glue ?sep] utility
+    function (see below).
 *)
-val id: string -> string
 
-(** adds a [H1] header with the given [title] on top of the given elements.
+(** Single Paragraph element *)
+val par : text -> elements
+
+(** Block element *)
+val block : block -> elements
+
+(** Get the content of a file as raw markdown.
+    @raise Sys_error if there's no such file.
+*)
+val rawfile: string -> elements
+
+(** {2 Document Structure} *)
+
+(** Creates a document from a list of elements and optional metadatas.
+    Defaults are:
+    - title: empty
+    - authors: empty list
+    - date: current day, in ISO format
+*)
+val pandoc:
+  ?title:text -> ?authors: text list -> ?date: text -> elements ->
+  pandoc_markdown
+
+(** Adds a [H1] header with the given [title] on top of the given elements.
     If name is not explicitly provided,
     the header will have as associated anchor [id title]
 *)
@@ -117,16 +184,20 @@ val section: ?name:string -> title:string -> elements -> elements
 *)
 val subsections: elements -> elements list -> elements
 
-(** returns an internal link relative to the current page *)
-val link_current_page: string -> href
+(** {2 Other Utilities} *)
+
+(** Glue fragments, typically used for combining [text], [block]
+    and [elements].
+    Default separator is empty. The function is tail-recursive. *)
+val glue: ?sep:'a list -> 'a list list -> 'a list
 
-(** gives a link whose text is the URL itself. *)
-val plain_link: href -> inline
+(** Transforms a string into an anchor name, roughly following
+    pandoc's conventions. This function is automatically used
+    by pretty-printers and smart constructors to normalize section names
+    and local links. *)
+val label: string -> string
 
-(** [codelines lang pp code] returns a [Code_block] for [code], written
-    in [lang], as pretty-printed by [pp]. *)
-val codelines:
-  string -> (Format.formatter -> 'a -> unit) -> 'a -> block_element
+(** {2 Pretty-printers} *)
 
 val pp_inline: ?page:string -> Format.formatter -> inline -> unit
 
diff --git a/src/plugins/markdown-report/eva_coverage.ml b/src/plugins/markdown-report/eva_coverage.ml
index 56b55d11303..d60250838fc 100644
--- a/src/plugins/markdown-report/eva_coverage.ml
+++ b/src/plugins/markdown-report/eva_coverage.ml
@@ -190,7 +190,7 @@ let md_gen () =
   let vis = new eva_coverage_vis ~from_entry_point:false in
   let stats = vis#compute () in
   let summary_whole =
-    Markdown.plain_format
+    Markdown.format
       "There are %d function definitions that are not stubbed. They represent \
        %d statements, of which %d are potentially reachable through EVA, \
        resulting in a **statement coverage of %.1f%%** with respect to the \
@@ -203,7 +203,7 @@ let md_gen () =
   let vis = new eva_coverage_vis ~from_entry_point:true in
   let stats = vis#compute () in
   let summary =
-    Markdown.plain_format
+    Markdown.format
       "There were potentially %d functions syntactically reachable from %s."
       stats.syntactic_calls main
   in
@@ -211,14 +211,14 @@ let md_gen () =
     if stats.indirect_calls = 0 then summary
     else
       summary @
-      Markdown.plain_format
+      Markdown.format
         "In addition, %d were found potentially reachable through \
          indirect calls."
         stats.indirect_calls
   in
   let summary =
     summary @
-    Markdown.plain_format
+    Markdown.format
       "These functions contain %d statements, \
        of which %d are potentially reachable according to EVA, resulting in \
        a **statement coverage of %.1f%%** with respect to the perimeter set \
diff --git a/src/plugins/markdown-report/md_gen.ml b/src/plugins/markdown-report/md_gen.ml
index 538ff9f2eb2..7976815caac 100644
--- a/src/plugins/markdown-report/md_gen.ml
+++ b/src/plugins/markdown-report/md_gen.ml
@@ -131,15 +131,12 @@ let section_stubs env =
          let anchor = sanitize_anchor s in
          let content =
            if env.is_draft then insert_marks env anchor
-           else begin
-             let comment = insert_remark env anchor in
-             Block
-               [ Text
-                   [Inline_code s; Plain "has the following specification"];
-                 codelines
-                   "acsl" Printer.pp_funspec (Annotations.funspec kf)]
-             :: comment
-           end
+           else
+             let intro = Markdown.text @@ Markdown.format
+                 "`%s` has the following specification" s in
+             let funspec = Markdown.codeblock "acsl"
+                 Printer.pp_funspec (Annotations.funspec kf) in
+             Block ( intro @ funspec ) :: insert_remark env anchor
          in
          H4 ([Inline_code s], Some anchor) :: content)
       l
@@ -151,16 +148,12 @@ let section_stubs env =
     let content =
       if env.is_draft then insert_marks env anchor
       else
-        (Block
-           [ Text
-               (Inline_code name ::
-                plain_format
-                  "@[<h>is defined at %a@]" Cil_datatype.Location.pretty loc);
-             codelines "c"
-               Printer.pp_global
-               (GFun (Kernel_function.get_definition kf,loc))
-           ])
-        :: insert_remark env anchor
+        let intro = Markdown.text @@ Markdown.format
+            "`%s` @[<h>is defined at %a@]"
+            name Cil_datatype.Location.pretty loc in
+        let fundecl = Markdown.codeblock "c"
+            Printer.pp_global (GFun (Kernel_function.get_definition kf,loc)) in
+        Block ( intro @ fundecl ) :: insert_remark env anchor
     in
     H4 ([Inline_code name], Some anchor) :: content
   in
@@ -449,12 +442,11 @@ let gen_section_warnings env =
               Plain "They might put additional assumptions on the relevance";
               Plain "of the analysis results and must be reviewed carefully";
             ];
-            Text [
-              Plain "Note that this does not take into account emitted alarms:";
-              Plain "they are reported in";
-              Link (plain "the next section",
-                    Markdown.link_current_page "alarms")
-            ]
+            Text (
+              plain "Note that this does not take into account emitted alarms:"@
+              plain "they are reported in"@
+              Markdown.link ~text:(plain "the next section") ~name:"alarms" ()
+            )
           ];
           make_warnings_table warnings
         ]
@@ -467,33 +459,29 @@ let gen_section_warnings env =
 
 let gen_section_alarms env =
   let treat_alarm e kf s ~rank:_ alarm annot (i, sec, content) =
-    let kind = plain (Alarms.get_name alarm) in
+    let kind = Alarms.get_name alarm in
     let label = "Alarm-" ^ string_of_int i in
-    let link = [Link (plain_format "%d" i, link_current_page label)] in
+    let link = link ~text:(format "%d" i) ~name:label () in
     let func = plain (Kernel_function.get_name kf) in
     let loc = string_of_loc (Cil_datatype.Stmt.loc s) in
     let loc_text = plain loc in
     let emitter = plain (Emitter.get_name e) in
-    let descr = codelines "acsl" Printer.pp_code_annotation annot in
-    let sec_title = plain_format "Alarm %d at %s" i loc in
+    let descr = codeblock "acsl" Printer.pp_code_annotation annot in
+    let sec_title = format "Alarm %d at %s" i loc in
     let sec_content =
       if env.is_draft then
-        Block [ descr ] :: insert_marks env label
+        Block descr :: insert_marks env label
       else
         Block
-          [
-            Text
-              (plain
-                 "The following ACSL assertion must hold to avoid \
-                  an undefined behavior ("
-               @ kind @ plain ")");
-            descr
-          ]
+          ( (text @@ format
+               "The following ACSL assertion must hold to avoid \
+                an undefined behavior (%s)" kind)
+            @ descr )
         :: insert_remark env label
     in
     (i+1,
      sec @ H2 (sec_title, Some label) :: sec_content,
-     [ link; kind; emitter; func; loc_text ] :: content)
+     [ link; plain kind; emitter; func; loc_text ] :: content)
   in
   let _,sections, content = Alarms.fold treat_alarm (0,[],[]) in
   let content = List.rev content in
@@ -563,14 +551,13 @@ let gen_section_callgraph env =
            callstacks whose analysis is the most costly."
         :: insert_marks env anchor
       else
-        Block [
-          Text [
-            Plain "The image below shows the flamegraph (";
-            plain_link (URL "http://www.brendangregg.com/flamegraphs.html");
-            Plain ") for the chosen entry point."
-          ]]
-        :: Block [ Text [Image ("Flamegraph visualization.", f)] ]
-        :: insert_remark env anchor
+        par (
+          plain "The image below shows the flamegraph (" @
+          url "http://www.brendangregg.com/flamegraphs.html" @
+          plain ") for the chosen entry point."
+        )
+        @ par (image ~alt:"Flamegraph visualization." ~file:f)
+        @ insert_remark env anchor
     in
     H1 (plain "Flamegraph", Some anchor) :: content
   end
diff --git a/src/plugins/markdown-report/sarif_gen.ml b/src/plugins/markdown-report/sarif_gen.ml
index 011fb79325a..5efe92ff894 100644
--- a/src/plugins/markdown-report/sarif_gen.ml
+++ b/src/plugins/markdown-report/sarif_gen.ml
@@ -87,8 +87,8 @@ let make_message alarm annot remark =
   let name = Alarms.get_name alarm in
   let text = name ^ "." in
   let kind = plain (name ^ ":") in
-  let descr = codelines "acsl" Printer.pp_code_annotation annot in
-  let summary = Block [Text kind; descr] in
+  let descr = codeblock "acsl" Printer.pp_code_annotation annot in
+  let summary = Block (Text kind :: descr) in
   let markdown =
     match remark with
     | [] -> summary :: gen_remark alarm
diff --git a/src/plugins/server/doc.ml b/src/plugins/server/doc.ml
index b484beb24bc..5db96f030f9 100644
--- a/src/plugins/server/doc.ml
+++ b/src/plugins/server/doc.ml
@@ -74,7 +74,7 @@ let page chapter ~title ~filename =
         Printf.sprintf "%s/%s/server/%s" Config.datadir name filename in
     let intro =
       if Sys.file_exists intro
-      then [Markdown.raw_markdown intro]
+      then Markdown.rawfile intro
       else Markdown.(section ~title []) in
     let order = incr order ; !order in
     let page = { order ; rootdir ; path ;
diff --git a/src/plugins/server/request.ml b/src/plugins/server/request.ml
index 69daa664bdc..0b1ef3b62f6 100644
--- a/src/plugins/server/request.ml
+++ b/src/plugins/server/request.ml
@@ -312,8 +312,8 @@ let register_sig (type a b) (s : (a,b) signature) (process : rq -> a -> b) =
   let caption = Some s.descr in
   let header = [ plain "Input", Center; plain "Output", Center] in
   let content =
-    [[ Syntax.format @@ sy_input s.input ;
-       Syntax.format @@ sy_output s.output ]]
+    [[ Syntax.text @@ sy_input s.input ;
+       Syntax.text @@ sy_output s.output ]]
   in
   let synopsis = Table { caption; header; content } in
   let content =
diff --git a/src/plugins/server/syntax.ml b/src/plugins/server/syntax.ml
index fc97bc44c6f..3f69008114a 100644
--- a/src/plugins/server/syntax.ml
+++ b/src/plugins/server/syntax.ml
@@ -55,8 +55,8 @@ type t = { atomic:bool ; text:Markdown.text }
 
 let atom md = { atomic=true ; text=md }
 let flow md = { atomic=false ; text=md }
+let text { text } = text
 
-let format { text } = text
 let protect a =
   if a.atomic then a.text else Markdown.((Plain "(") :: a.text @ [Plain ")"])
 
@@ -66,24 +66,22 @@ let publish ~page ~name ~descr ~synopsis ?(details = []) () =
   let id = Printf.sprintf "data-%s" name in
   let title = Printf.sprintf "`DATA` %s" name in
   let href = Doc.href page id in
-  let link_title = Printf.sprintf "_%s_" name in
-  let link = Markdown.(Link (plain link_title, href)) in
-  let syntax =
-    Markdown.(
-      Text
-        (Plain ">" :: link :: Plain "::=" :: synopsis.text))
-  in
+  let link_title = Markdown.emph name in
+  let data_link = Markdown.Link(link_title, href) in
+  let syntax = Markdown.(Text (
+      Plain "<" :: data_link :: Plain ">" :: Plain ":=" :: synopsis.text
+    )) in
   let content = Markdown.((Block [Text descr; syntax]) :: details) in
   let _href = Doc.publish ~page ~name:id ~title ~index:[name] content [] in
-  atom @@ [link]
+  atom [data_link]
 
-let unit = atom @@ [Markdown.Plain "-"]
-let any = atom @@ [Markdown.Emph "any"]
-let int = atom @@ [Markdown.Emph "int"]
-let ident = atom @@ [Markdown.Emph "ident"]
-let string = atom @@ [Markdown.Emph "string"]
-let number = atom @@ [Markdown.Emph "number"]
-let boolean = atom @@ [Markdown.Emph "boolean"]
+let unit = atom [Markdown.Plain "-"]
+let any = atom [Markdown.Emph "any"]
+let int = atom [Markdown.Emph "int"]
+let ident = atom [Markdown.Emph "ident"]
+let string = atom [Markdown.Emph "string"]
+let number = atom [Markdown.Emph "number"]
+let boolean = atom [Markdown.Emph "boolean"]
 
 let escaped name =
   Markdown.Inline_code (Printf.sprintf "'%s'" @@ String.escaped name)
@@ -121,13 +119,12 @@ type field = {
 let fields ~title (fds : field list) =
   let open Markdown in
   let caption = Some (plain "Fields description") in
-  let header =
-    [plain title, Left; plain "Format", Center; plain "Description", Left]
-  in
-  let content =
-    List.map
-      (fun f -> [[Markdown.Inline_code f.name]; format f.syntax ; f.descr]) fds
-  in
-  Markdown.Table { caption; header; content }
+  let header = [
+    plain title, Left;
+    plain "Format", Center;
+    plain "Description", Left
+  ] in
+  let field f = [[Inline_code f.name]; f.syntax.text ; f.descr] in
+  Markdown.Table { caption; header; content = List.map field fds }
 
 (* -------------------------------------------------------------------------- *)
diff --git a/src/plugins/server/syntax.mli b/src/plugins/server/syntax.mli
index c56312909ed..33ae244e8f3 100644
--- a/src/plugins/server/syntax.mli
+++ b/src/plugins/server/syntax.mli
@@ -26,7 +26,7 @@
 
 type t
 
-val format : t -> Markdown.text
+val text : t -> Markdown.text
 
 (** The provided synopsis must be very short, to fit in one line.
     Extended definition, like record fields and such, must be detailed in
-- 
GitLab