Skip to content

Commit 316d015

Browse files
committed
mrkdwn: handle blockquotes and code blocks
1 parent 056bf57 commit 316d015

File tree

1 file changed

+48
-10
lines changed

1 file changed

+48
-10
lines changed

lib/mrkdwn.ml

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ and transform = function
6767
from omd 1.3.1 source.
6868
https://github.com/ocaml/omd/blob/1.3.1/src/omd_backend.ml#L872
6969
*)
70-
let mrkdwn_of_md md =
70+
let rec mrkdwn_of_md md =
7171
let b = Buffer.create 128 in
7272
let references : ref_container option ref = ref None in
7373
let nl b = Buffer.add_char b '\n' in
@@ -87,9 +87,31 @@ let mrkdwn_of_md md =
8787
which is inside a list item because those need to be indented!
8888
*)
8989
| X _ -> loop list_indent tl
90-
| Blockquote _q -> (* todo *) loop list_indent tl
90+
| Blockquote q ->
91+
(* mrkdwn doesn't support nested quotes, but output '>' chars anyway*)
92+
let quote s =
93+
let b = Buffer.create (String.length s) in
94+
let l = String.length s in
95+
let rec loop is_nl i =
96+
if i < l then begin
97+
if is_nl && i < l - 1 then Buffer.add_string b "> ";
98+
match s.[i] with
99+
| '\n' ->
100+
nl b;
101+
loop true (i + 1)
102+
| c ->
103+
Buffer.add_char b c;
104+
loop false (i + 1)
105+
end
106+
else Buffer.contents b
107+
in
108+
loop true 0
109+
in
110+
Buffer.add_string b (quote @@ mrkdwn_of_md q);
111+
if not @@ List.is_empty tl then nl_if_needed_above b;
112+
loop list_indent tl
91113
| Ref (rc, _name, _text, fallback) | Img_ref (rc, _name, _text, fallback) ->
92-
(* [rc] stores refs from whole document, so it's enough to record just the
114+
(* [rc] stores all refs from document, so it's enough to record just the
93115
first encounter
94116
*)
95117
if Option.is_empty !references then references := Some rc;
@@ -162,21 +184,37 @@ let mrkdwn_of_md md =
162184
Printf.bprintf b "%d. " i;
163185
loop ~is_in_list:true (list_indent + 4) li (* Paragraphs => No need of '\n' *));
164186
loop list_indent tl
165-
| Code_block (_lang, _c) -> (* todo *) loop list_indent tl
187+
| Code_block (_lang, c) ->
188+
(* unlike commonmark, can't have code block inside lists, so print code block with
189+
zero indent, but continue rest of the list at correct indent after
190+
191+
note: sometimes indentation intended as list item paragraph is wrongly
192+
interpreted as code block - an issue with Omd.of_string
193+
e.g., both should be parsed the second way, but aren't:
194+
# of_string " - foo\n\n bar";;
195+
- : t = [Ul [[Text "foo"]]; NL; NL; Code_block ("", "bar")]
196+
# of_string "- foo\n\n bar";;
197+
- : t = [Ulp [[Paragraph [Text "foo"]; Paragraph [Text "bar"]]]]
198+
*)
199+
nl_if_needed_above b;
200+
Buffer.add_string b "```\n";
201+
Buffer.add_string b (escape_mrkdwn c);
202+
nl_if_needed_above b;
203+
Buffer.add_string b "```\n";
204+
loop list_indent tl
166205
| Code (_lang, c) ->
206+
(* sadly, slack mrkdwn has no way to escape backticks within in-line code,
207+
so broken markup is unavoidable
208+
*)
167209
Buffer.add_char b '`';
168210
Buffer.add_string b (escape_mrkdwn c);
169211
Buffer.add_char b '`';
170212
loop list_indent tl
171213
| Hr ->
172214
Buffer.add_string b "* * *\n";
173215
loop list_indent tl
174-
| Html (tagname, _attrs, body) ->
175-
Printf.bprintf b "`&lt;%s&gt;" tagname;
176-
Buffer.add_string b (escape_mrkdwn @@ to_html body);
177-
Printf.bprintf b "&lt;/%s&gt;`" tagname;
178-
loop list_indent tl
179-
| Html_block (_tagname, _attrs, _body) -> (* todo *) loop list_indent tl
216+
| Html (_tagname, _attrs, _body) as html -> loop list_indent (Code ("", to_html [ html ]) :: tl)
217+
| Html_block (_tagname, _attrs, _body) as html -> loop list_indent (Code_block ("", to_html [ html ]) :: tl)
180218
| Html_comment _s -> loop list_indent tl
181219
| Url (href, s, title) ->
182220
Buffer.add_char b '<';

0 commit comments

Comments
 (0)