Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
mrkdwn.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
open ExtLib open Printf (** Mrkdwn formatting https://api.slack.com/reference/surfaces/formatting#basics *) let escape_mrkdwn = String.replace_chars (function | '<' -> "<" | '>' -> ">" | '&' -> "&" | c -> String.make 1 c ) let escaped_mrkdwn_re = Re2.create_exn {|(?P<escaped><|>|&)|} let unescape_mrkdwn str = try Re2.replace_exn escaped_mrkdwn_re str ~f:(fun m -> match Re2.Match.get_exn m ~sub:(`Name "escaped") with | "<" -> "<" | ">" -> ">" | "&" -> "&" | e -> Common.slack_lib_fail "impossible re2 mrkdwn unescape match: %s" e ) with Re2.Exceptions.Regex_match_failed _ -> str let link ~url ?text () = match text with | Some text -> sprintf "<%s|%s>" url text | None -> sprintf "<%s>" url let bold = sprintf "*%s*" let italicize = sprintf "_%s_" let strike = sprintf "~%s~" let line_break = sprintf "%s\n" let blk_quote = sprintf ">%s" let inline_code = sprintf "`%s`" let multiline_code = sprintf "```%s```" let list l = sprintf "- %s" (String.concat "\n- " l) (* https://api.slack.com/reference/surfaces/formatting#mentioning-users *) let mention_user member_id = sprintf "<@%s>" member_id (* https://api.slack.com/reference/surfaces/formatting#mentioning-groups *) let mention_usergroup group_id = sprintf "<!subteam^%s>" group_id let mention_re = Re2.create_exn {|\B@[a-zA-Z0-9][a-zA-Z0-9._-]*|} let highlight_mentions get_id_by_slack_name s = let subst s = String.lchop s |> get_id_by_slack_name |> Option.map (function | `User u -> mention_user u | `Group g -> mention_usergroup g ) |> Option.default s in Re2.replace_exn mention_re s ~f:(fun m -> subst (Re2.Match.get_exn ~sub:(`Index 0) m)) module Cmarkit_slack = struct let renderer = (* https://www.markdownguide.org/tools/slack/#slack-markdown-support-in-posts *) (* https://slack.com/intl/en-gb/help/articles/202288908-Format-your-messages *) let inline c inline = let open Cmarkit in let module C = Cmarkit_renderer.Context in let strong_emphasis c e = let i = Inline.Emphasis.inline e in C.byte c '*'; C.inline c i; C.byte c '*' in let emphasis c e = let i = Inline.Emphasis.inline e in C.byte c '_'; C.inline c i; C.byte c '_' in let strikethrough c s = let i = Inline.Strikethrough.inline s in C.byte c '~'; C.inline c i; C.byte c '~' in let link c l = match Inline.Link.reference l with | `Inline (ld, _) -> begin match Link_definition.dest ld with | None -> C.inline c (Inline.Link.text l) | Some (dest, _) -> C.byte c '<'; C.string c dest; C.byte c '|'; C.inline c (Inline.Link.text l); C.byte c '>' end; true | _ -> false in match inline with | Inline.Strong_emphasis (e, _) -> strong_emphasis c e; true | Inline.Emphasis (e, _) -> emphasis c e; true | Inline.Ext_strikethrough (s, _) -> strikethrough c s; true | Inline.Link (l, _) -> link c l | _ -> false (* let the default renderer handle that *) in let block c block = let open Cmarkit in let module C = Cmarkit_renderer.Context in match block with | Block.Heading (heading, _) -> let inline = Block.Heading.inline heading in C.byte c '*'; C.inline c inline; C.byte c '*'; C.byte c '\n'; true | _ -> false in let default_renderer = Cmarkit_commonmark.renderer () in let renderer = Cmarkit_renderer.make ~inline ~block () in Cmarkit_renderer.compose default_renderer renderer end let of_doc = Cmarkit_renderer.doc_to_string Cmarkit_slack.renderer