hoedown/renderer/
html.rs

1//! Contains the html renderer and utilities
2use libc::c_void;
3
4use std::ptr;
5
6use buffer::Buffer;
7use ffi::{
8    hoedown_buffer,
9    hoedown_renderer,
10    hoedown_html_renderer_new,
11    hoedown_html_toc_renderer_new,
12    hoedown_html_smartypants,
13    hoedown_html_renderer_free
14};
15
16use super::Render;
17
18/// Performs "smartypants" processing of the provided buffer.
19///
20/// This turns, for example, straight quotes `"test"` into curly quotes `“test”`
21pub fn smartypants(content: &Buffer, output: &mut Buffer) {
22    let content: &hoedown_buffer = content.as_ref();
23
24    unsafe {
25        hoedown_html_smartypants(
26            output.as_mut(),
27            content.data,
28            content.size);
29    }
30}
31
32/// Flags to control the behavior of the html renderer
33bitflags! {
34    /// Information about a list item
35    pub flags Flags: u32 {
36        /// Ignore raw html
37        const SKIP_HTML = 1 << 0,
38
39        /// Ignore raw html blocks and escape html spans
40        const ESCAPE    = 1 << 1,
41
42        /// Insert breaks inside paragraphs for every newline
43        const HARD_WRAP = 1 << 2,
44
45        /// Output XHTML
46        const USE_XHTML = 1 << 3,
47    }
48}
49
50/// HTML renderer
51///
52/// This can be used to render markdown documents to HTML. This
53/// type can also be leveraged to create custom renderers that delegate
54/// to the HTML renderer in certain cases, as shown in the `Render` trait
55/// documentation example.
56///
57///``` rust
58///# use hoedown::renderer::html::{Html, Flags};
59///# use hoedown::{Buffer, Render};
60///let input = Buffer::from("EMPHASIZE");
61///let mut output = Buffer::new(64usize);
62///let mut html_renderer = Html::new(Flags::empty(), 0);
63///
64///html_renderer.emphasis(&mut output, Some(&input));
65///
66///assert_eq!(output.to_str().unwrap(), "<em>EMPHASIZE</em>");
67///```
68pub struct Html {
69    renderer: *mut hoedown_renderer,
70}
71
72impl Html {
73    /// Construct a new html renderer given the provided html flags
74    /// and table of contents nesting level.
75    ///
76    /// The `toc` method can be used to construct a table of contents renderer
77    /// which renders _only_ the table of contents. The `nesting_level` on this
78    /// method determines the maximum depth of headers to associate with the
79    /// table of contents.
80    ///
81    /// For this reason, if a table of contents is going to be rendered, this
82    /// method's `nesting_level` argument should be the same as the one passed
83    /// to the `toc` method.
84    pub fn new(flags: Flags, nesting_level: i32) -> Html {
85        let renderer = unsafe {
86            hoedown_html_renderer_new(flags.bits(), nesting_level)
87        };
88
89        Html {
90            renderer: renderer,
91        }
92    }
93
94    /// Construct a table of contents renderer.
95    ///
96    /// This renderer will _only_ render the table of contents.
97    /// If you want to have the headers of the document specify `id` attributes
98    /// so that the table of contents items link to the correct header, you should
99    /// render the document with the renderer returned by the `new` method with the
100    /// same value for the `nesting_level` parameter.
101    pub fn toc(nesting_level: i32) -> Html {
102        let renderer = unsafe {
103           hoedown_html_toc_renderer_new(nesting_level)
104        };
105
106        Html {
107            renderer: renderer,
108        }
109    }
110
111    // TODO: replace with AsRef/AsMut
112    /// Get a reference to the underlying hoedown renderer
113    pub fn get(&self) -> &hoedown_renderer {
114        unsafe { &*self.renderer }
115    }
116
117    /// Get a mutable reference to the underlying hoedown renderer
118    pub fn as_mut(&mut self) -> &mut hoedown_renderer {
119        unsafe { &mut *self.renderer }
120    }
121}
122
123impl Render for Html {
124    unsafe fn to_hoedown(&mut self) -> hoedown_renderer {
125        *self.renderer
126    }
127
128    fn code_block(&mut self, ob: &mut Buffer, text: Option<&Buffer>, lang: Option<&Buffer>) {
129        let data = self.renderer as *mut c_void;
130
131        if let Some(func) = unsafe { (*self.renderer).blockcode } {
132            func(ob.as_mut(),
133                 text.map_or(ptr::null(), |t| t.as_ref()),
134                 lang.map_or(ptr::null(), |l| l.as_ref()), data)
135        }
136    }
137
138    fn quote_block(&mut self, ob: &mut Buffer, content: Option<&Buffer>) {
139        let data = self.renderer as *mut c_void;
140
141        if let Some(func) = unsafe { (*self.renderer).blockquote } {
142            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data)
143        }
144    }
145
146    fn header(&mut self, ob: &mut Buffer, content: Option<&Buffer>, level: i32) {
147        let data = self.renderer as *mut c_void;
148
149        if let Some(func) = unsafe { (*self.renderer).header } {
150            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), level, data)
151        }
152    }
153
154    fn horizontal_rule(&mut self, ob: &mut Buffer) {
155        let data = self.renderer as *mut c_void;
156
157        if let Some(func) = unsafe { (*self.renderer).hrule } {
158            func(ob.as_mut(), data)
159        }
160    }
161
162    fn list(&mut self, ob: &mut Buffer, content: Option<&Buffer>, flags: ::renderer::list::List) {
163        let data = self.renderer as *mut c_void;
164
165        if let Some(func) = unsafe { (*self.renderer).list } {
166            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), flags.bits(), data)
167        }
168    }
169
170    fn list_item(&mut self, ob: &mut Buffer, content: Option<&Buffer>, flags: ::renderer::list::List) {
171        let data = self.renderer as *mut c_void;
172
173        if let Some(func) = unsafe { (*self.renderer).listitem } {
174            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), flags.bits(), data)
175        }
176    }
177
178    fn paragraph(&mut self, ob: &mut Buffer, content: Option<&Buffer>) {
179        let data = self.renderer as *mut c_void;
180
181        if let Some(func) = unsafe { (*self.renderer).paragraph } {
182            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data)
183        }
184    }
185
186    fn table(&mut self, ob: &mut Buffer, content: Option<&Buffer>) {
187        let data = self.renderer as *mut c_void;
188
189        if let Some(func) = unsafe { (*self.renderer).table } {
190            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data)
191        }
192    }
193
194    fn table_header(&mut self, ob: &mut Buffer, content: Option<&Buffer>) {
195        let data = self.renderer as *mut c_void;
196
197        if let Some(func) = unsafe { (*self.renderer).table_header } {
198            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data)
199        }
200    }
201
202    fn table_body(&mut self, ob: &mut Buffer, content: Option<&Buffer>) {
203        let data = self.renderer as *mut c_void;
204
205        if let Some(func) = unsafe { (*self.renderer).table_body } {
206            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data)
207        }
208    }
209
210    fn table_row(&mut self, ob: &mut Buffer, content: Option<&Buffer>) {
211        let data = self.renderer as *mut c_void;
212
213        if let Some(func) = unsafe { (*self.renderer).table_row } {
214            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data)
215        }
216    }
217
218    fn table_cell(&mut self, ob: &mut Buffer, content: Option<&Buffer>, flags: ::renderer::Table) {
219        let data = self.renderer as *mut c_void;
220
221        if let Some(func) = unsafe { (*self.renderer).table_cell } {
222            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), flags, data)
223        }
224    }
225
226    fn footnotes(&mut self, ob: &mut Buffer, content: Option<&Buffer>) {
227        let data = self.renderer as *mut c_void;
228
229        if let Some(func) = unsafe { (*self.renderer).footnotes } {
230            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data)
231        }
232    }
233
234    fn footnote_definition(&mut self, ob: &mut Buffer, content: Option<&Buffer>, num: u32) {
235        let data = self.renderer as *mut c_void;
236
237        if let Some(func) = unsafe { (*self.renderer).footnote_def } {
238            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), num, data)
239        }
240    }
241
242    fn html_block(&mut self, ob: &mut Buffer, text: Option<&Buffer>) {
243        let data = self.renderer as *mut c_void;
244
245        if let Some(func) = unsafe { (*self.renderer).blockhtml } {
246            func(ob.as_mut(), text.map_or(ptr::null(), |b| b.as_ref()), data)
247        }
248    }
249
250    fn autolink(&mut self, ob: &mut Buffer, link: Option<&Buffer>, ty: ::renderer::AutoLink) -> bool {
251        let data = self.renderer as *mut c_void;
252
253        if let Some(func) = unsafe { (*self.renderer).autolink } {
254            func(ob.as_mut(), link.map_or(ptr::null(), |b| b.as_ref()), ty, data) != 0
255        } else {
256            false
257        }
258    }
259
260    fn code_span(&mut self, ob: &mut Buffer, text: Option<&Buffer>) -> bool {
261        let data = self.renderer as *mut c_void;
262
263        if let Some(func) = unsafe { (*self.renderer).codespan } {
264            func(ob.as_mut(), text.map_or(ptr::null(), |b| b.as_ref()), data) != 0
265        } else {
266            false
267        }
268    }
269
270    fn double_emphasis(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
271        let data = self.renderer as *mut c_void;
272
273        if let Some(func) = unsafe { (*self.renderer).double_emphasis } {
274            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
275        } else {
276            false
277        }
278    }
279
280    fn emphasis(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
281        let data = self.renderer as *mut c_void;
282
283        if let Some(func) = unsafe { (*self.renderer).emphasis } {
284            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
285        } else {
286            false
287        }
288    }
289
290    fn underline(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
291        let data = self.renderer as *mut c_void;
292
293        if let Some(func) = unsafe { (*self.renderer).underline } {
294            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
295        } else {
296            false
297        }
298    }
299
300    fn highlight(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
301        let data = self.renderer as *mut c_void;
302
303        if let Some(func) = unsafe { (*self.renderer).highlight } {
304            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
305        } else {
306            false
307        }
308    }
309
310    fn quote_span(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
311        let data = self.renderer as *mut c_void;
312
313        if let Some(func) = unsafe { (*self.renderer).quote } {
314            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
315        } else {
316            false
317        }
318    }
319
320    fn image(&mut self, ob: &mut Buffer, link: Option<&Buffer>, title: Option<&Buffer>, alt: Option<&Buffer>) -> bool {
321        let data = self.renderer as *mut c_void;
322
323        if let Some(func) = unsafe { (*self.renderer).image } {
324            func(ob.as_mut(),
325                 link.map_or(ptr::null(), |b| b.as_ref()),
326                 title.map_or(ptr::null(), |b| b.as_ref()),
327                 alt.map_or(ptr::null(), |b| b.as_ref()),
328                 data) != 0
329        } else {
330            false
331        }
332    }
333
334    fn line_break(&mut self, ob: &mut Buffer) -> bool {
335        let data = self.renderer as *mut c_void;
336
337        if let Some(func) = unsafe { (*self.renderer).linebreak } {
338            func(ob.as_mut(), data) != 0
339        } else {
340            false
341        }
342    }
343
344    fn link(&mut self, ob: &mut Buffer, content: Option<&Buffer>, link: Option<&Buffer>, title: Option<&Buffer>) -> bool {
345        let data = self.renderer as *mut c_void;
346
347        if let Some(func) = unsafe { (*self.renderer).link } {
348            func(ob.as_mut(),
349                 content.map_or(ptr::null(), |b| b.as_ref()),
350                 link.map_or(ptr::null(), |b| b.as_ref()),
351                 title.map_or(ptr::null(), |b| b.as_ref()),
352                 data) != 0
353        } else {
354            false
355        }
356    }
357
358    fn triple_emphasis(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
359        let data = self.renderer as *mut c_void;
360
361        if let Some(func) = unsafe { (*self.renderer).triple_emphasis } {
362            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
363        } else {
364            false
365        }
366    }
367
368    fn strikethrough(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
369        let data = self.renderer as *mut c_void;
370
371        if let Some(func) = unsafe { (*self.renderer).strikethrough } {
372            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
373        } else {
374            false
375        }
376    }
377
378    fn superscript(&mut self, ob: &mut Buffer, content: Option<&Buffer>) -> bool {
379        let data = self.renderer as *mut c_void;
380
381        if let Some(func) = unsafe { (*self.renderer).superscript } {
382            func(ob.as_mut(), content.map_or(ptr::null(), |b| b.as_ref()), data) != 0
383        } else {
384            false
385        }
386    }
387
388    fn footnote_reference(&mut self, ob: &mut Buffer, num: u32) -> bool {
389        let data = self.renderer as *mut c_void;
390
391        if let Some(func) = unsafe { (*self.renderer).footnote_ref } {
392            func(ob.as_mut(), num, data) != 0
393        } else {
394            false
395        }
396    }
397
398    fn math(&mut self, ob: &mut Buffer, text: Option<&Buffer>, displaymode: i32) -> bool {
399        let data = self.renderer as *mut c_void;
400
401        if let Some(func) = unsafe { (*self.renderer).math } {
402            func(ob.as_mut(), text.map_or(ptr::null(), |b| b.as_ref()), displaymode, data) != 0
403        } else {
404            false
405        }
406    }
407
408    fn html_span(&mut self, ob: &mut Buffer, text: Option<&Buffer>) -> bool {
409        let data = self.renderer as *mut c_void;
410
411        if let Some(func) = unsafe { (*self.renderer).raw_html } {
412            func(ob.as_mut(), text.map_or(ptr::null(), |b| b.as_ref()), data) != 0
413        } else {
414            false
415        }
416    }
417
418    fn entity(&mut self, ob: &mut Buffer, text: Option<&Buffer>) {
419        let data = self.renderer as *mut c_void;
420
421        if let Some(func) = unsafe { (*self.renderer).entity } {
422            func(ob.as_mut(), text.map_or(ptr::null(), |b| b.as_ref()), data)
423        } else {
424            text.map(|t| ob.pipe(t));
425        }
426    }
427
428    fn normal_text(&mut self, ob: &mut Buffer, text: Option<&Buffer>) {
429        let data = self.renderer as *mut c_void;
430
431        if let Some(func) = unsafe { (*self.renderer).normal_text } {
432            func(ob.as_mut(), text.map_or(ptr::null(), |b| b.as_ref()), data)
433        } else {
434            text.map(|t| ob.pipe(t));
435        }
436    }
437
438    fn before_render(&mut self, ob: &mut Buffer, inline_render: bool) {
439        let data = self.renderer as *mut c_void;
440
441        if let Some(func) = unsafe { (*self.renderer).doc_header } {
442            func(ob.as_mut(), inline_render as i32, data)
443        }
444    }
445
446    fn after_render(&mut self, ob: &mut Buffer, inline_render: bool) {
447        let data = self.renderer as *mut c_void;
448
449        if let Some(func) = unsafe { (*self.renderer).doc_footer } {
450            func(ob.as_mut(), inline_render as i32, data)
451        }
452    }
453}
454
455impl Drop for Html {
456    fn drop(&mut self) {
457        unsafe { hoedown_html_renderer_free(self.renderer); }
458    }
459}
460