@@ -70,9 +70,24 @@ and transform = function
70
70
let mrkdwn_of_md md =
71
71
let b = Buffer. create 128 in
72
72
let references : ref_container option ref = ref None in
73
- let rec f tl = function
74
- | X _ -> loop tl
75
- | Blockquote _q -> (* todo *) loop tl
73
+ let nl b = Buffer. add_char b '\n' in
74
+ let nl_if_needed_above b =
75
+ if Buffer. length b > 0 && (not @@ Char. equal '\n' (Buffer. nth b (Buffer. length b - 1 ))) then nl b
76
+ in
77
+ let add_spaces n =
78
+ for _i = 1 to n do
79
+ Buffer. add_char b ' '
80
+ done
81
+ in
82
+ let rec f ?(fst_p_in_li = true ) ?(is_in_list = false ) list_indent tl = function
83
+ (* [list_indent : int] is the indentation level in number of spaces.
84
+ [fst_p_in_li: bool] is used to apply different indentation to the first
85
+ paragraph in a list items.
86
+ [is_in_list: bool] is necessary to know if we are inside a paragraph
87
+ which is inside a list item because those need to be indented!
88
+ * )
89
+ | X _ -> loop list_indent tl
90
+ | Blockquote _q -> (* todo *) loop list_indent tl
76
91
| Ref (rc , _name , _text , fallback ) | Img_ref (rc , _name , _text , fallback ) ->
77
92
(* [rc] stores refs from whole document, so it's enough to record just the
78
93
first encounter
@@ -83,71 +98,110 @@ let mrkdwn_of_md md =
83
98
and
84
99
![<text>][<name>] for Img_ref, e.g., ![image of cat][1]
85
100
*)
86
- loop (Raw fallback#to_string :: tl)
87
- | Paragraph _md -> (* todo *) loop tl
88
- | Img (alt , src , title ) -> loop (Url (src, [ Text alt ], title) :: tl)
101
+ loop list_indent (Raw fallback#to_string :: tl)
102
+ | Paragraph [] -> loop list_indent tl
103
+ | Paragraph md ->
104
+ (* indent if inside a list (Olp or Ulp) *)
105
+ if is_in_list then if fst_p_in_li then add_spaces (list_indent - 2 ) else add_spaces list_indent;
106
+ (* paragraph body + skip line *)
107
+ loop ~fst_p_in_li: false list_indent md;
108
+ nl b;
109
+ nl b;
110
+ loop ~fst_p_in_li: false list_indent tl
111
+ | Img (alt , src , title ) -> loop list_indent (Url (src, [ Text alt ], title) :: tl)
89
112
| Text t ->
90
113
Buffer. add_string b @@ escape_mrkdwn t;
91
- loop tl
114
+ loop list_indent tl
92
115
| Raw s ->
93
116
Buffer. add_string b s;
94
- loop tl
117
+ loop list_indent tl
95
118
| Raw_block s ->
96
- Buffer. add_char b '\n' ;
119
+ nl b ;
97
120
Buffer. add_string b s;
98
- Buffer. add_char b '\n' ;
99
- loop tl
121
+ nl b ;
122
+ loop list_indent tl
100
123
| Emph md' ->
101
124
Buffer. add_string b " _" ;
102
- loop md';
125
+ loop list_indent md';
103
126
Buffer. add_string b " _" ;
104
- loop tl
127
+ loop list_indent tl
105
128
| Bold md' ->
106
129
Buffer. add_string b " *" ;
107
- loop md';
130
+ loop list_indent md';
108
131
Buffer. add_string b " *" ;
109
- loop tl
110
- | Ul _l -> (* todo *) loop tl
111
- | Ol _l -> (* todo *) loop tl
112
- | Ulp _l -> (* todo *) loop tl
113
- | Olp _l -> (* todo *) loop tl
114
- | Code_block (_lang , _c ) -> (* todo *) loop tl
132
+ loop list_indent tl
133
+ | Ul l ->
134
+ nl_if_needed_above b;
135
+ List. iter l ~f: (fun li ->
136
+ add_spaces list_indent;
137
+ Buffer. add_string b " - " ;
138
+ loop ~is_in_list: true (list_indent + 4 ) li;
139
+ nl_if_needed_above b);
140
+ if list_indent = 0 then nl b;
141
+ loop list_indent tl
142
+ | Ol l ->
143
+ nl_if_needed_above b;
144
+ List. iteri l ~f: (fun i li ->
145
+ add_spaces list_indent;
146
+ Printf. bprintf b " %d. " (i + 1 );
147
+ loop ~is_in_list: true (list_indent + 4 ) li;
148
+ nl_if_needed_above b);
149
+ if list_indent = 0 then nl b;
150
+ loop list_indent tl
151
+ | Ulp l ->
152
+ List. iter l ~f: (fun li ->
153
+ nl_if_needed_above b;
154
+ add_spaces list_indent;
155
+ Buffer. add_string b " - " ;
156
+ loop ~is_in_list: true (list_indent + 4 ) li (* Paragraphs => No need of '\n' *) );
157
+ loop list_indent tl
158
+ | Olp l ->
159
+ List. iteri l ~f: (fun i li ->
160
+ nl_if_needed_above b;
161
+ add_spaces list_indent;
162
+ Printf. bprintf b " %d. " i;
163
+ loop ~is_in_list: true (list_indent + 4 ) li (* Paragraphs => No need of '\n' *) );
164
+ loop list_indent tl
165
+ | Code_block (_lang , _c ) -> (* todo *) loop list_indent tl
115
166
| Code (_lang , c ) ->
116
167
Buffer. add_char b '`' ;
117
168
Buffer. add_string b (escape_mrkdwn c);
118
169
Buffer. add_char b '`' ;
119
- loop tl
170
+ loop list_indent tl
120
171
| Hr ->
121
172
Buffer. add_string b " * * *\n " ;
122
- loop tl
173
+ loop list_indent tl
123
174
| Html (tagname , _attrs , body ) ->
124
175
Printf. bprintf b " `<%s>" tagname;
125
176
Buffer. add_string b (escape_mrkdwn @@ to_html body);
126
177
Printf. bprintf b " </%s>`" tagname;
127
- loop tl
128
- | Html_block (_tagname , _attrs , _body ) -> (* todo *) loop tl
129
- | Html_comment _s -> loop tl
178
+ loop list_indent tl
179
+ | Html_block (_tagname , _attrs , _body ) -> (* todo *) loop list_indent tl
180
+ | Html_comment _s -> loop list_indent tl
130
181
| Url (href , s , title ) ->
131
182
Buffer. add_char b '<' ;
132
183
Buffer. add_string b href;
133
184
Buffer. add_char b '|' ;
134
185
if String. length title > 0 then Printf. bprintf b " %s - " @@ escape_mrkdwn title;
135
- loop s;
186
+ loop list_indent s;
136
187
Buffer. add_char b '>' ;
137
- loop tl
138
- | H1 md' | H2 md' | H3 md' | H4 md' | H5 md' | H6 md' -> loop (Paragraph (transform_list [ Bold md' ]) :: tl)
139
- | NL | Br ->
140
- (* the string "\n" renders NL
141
- the string "\\n" (backslash-newline) renders Br
142
- *)
143
- Buffer. add_char b '\n' ;
144
- loop tl
145
- and loop = function
146
- | hd :: tl -> f tl hd
188
+ loop list_indent tl
189
+ | H1 md' | H2 md' | H3 md' | H4 md' | H5 md' | H6 md' ->
190
+ loop list_indent (Paragraph (transform_list [ Bold md' ]) :: tl)
191
+ | Br ->
192
+ (* the string "\\n" (backslash-newline) or end of line double-space renders Br *)
193
+ nl b;
194
+ loop list_indent tl
195
+ | NL ->
196
+ (* the string "\n" renders NL *)
197
+ nl_if_needed_above b;
198
+ loop list_indent tl
199
+ and loop ?(fst_p_in_li = true ) ?(is_in_list = false ) list_indent = function
200
+ | hd :: tl -> f ~fst_p_in_li ~is_in_list list_indent tl hd
147
201
| [] -> ()
148
202
in
149
203
(* print the document *)
150
- loop md;
204
+ loop 0 md;
151
205
(* print any references *)
152
206
begin
153
207
match ! references with
@@ -157,7 +211,7 @@ let mrkdwn_of_md md =
157
211
if String. equal title " " then Printf. bprintf b " [%s]: %s \n " name url
158
212
else Printf. bprintf b " [%s]: %s \" %s\"\n " name url title
159
213
in
160
- Buffer. add_char b '\n' ;
214
+ nl b ;
161
215
List. iter ~f: print_ref r#get_all
162
216
end ;
163
217
Buffer. contents b
0 commit comments