1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Markdown formatting for rustdoc
13 //! This module implements markdown formatting through the sundown C-library
14 //! (bundled into the rust runtime). This module self-contains the C bindings
15 //! and necessary legwork to render markdown, and exposes all of the
16 //! functionality through a unit-struct, `Markdown`, which has an implementation
17 //! of `fmt::Default`. Example usage:
20 //! let s = "My *markdown* _text_";
21 //! let html = format!("{}", Markdown(s));
22 //! // ... something using html
30 /// A unit struct which has the `fmt::Default` trait implemented. When
31 /// formatted, this struct will emit the HTML corresponding to the rendered
32 /// version of the contained markdown string.
33 pub struct Markdown<'self>(&'self str);
35 static OUTPUT_UNIT: libc::size_t = 64;
36 static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
37 static MKDEXT_TABLES: libc::c_uint = 1 << 1;
38 static MKDEXT_FENCED_CODE: libc::c_uint = 1 << 2;
39 static MKDEXT_AUTOLINK: libc::c_uint = 1 << 3;
40 static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
41 static MKDEXT_SPACE_HEADERS: libc::c_uint = 1 << 6;
42 static MKDEXT_SUPERSCRIPT: libc::c_uint = 1 << 7;
43 static MKDEXT_LAX_SPACING: libc::c_uint = 1 << 8;
45 type sd_markdown = libc::c_void; // this is opaque to us
47 // this is a large struct of callbacks we don't use
48 type sd_callbacks = [libc::size_t, ..26];
50 struct html_toc_data {
51 header_count: libc::c_int,
52 current_level: libc::c_int,
53 level_offset: libc::c_int,
56 struct html_renderopt {
57 toc_data: html_toc_data,
59 link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
70 #[link(name = "sundown", kind = "static")]
72 fn sdhtml_renderer(callbacks: *sd_callbacks,
73 options_ptr: *html_renderopt,
74 render_flags: libc::c_uint);
75 fn sd_markdown_new(extensions: libc::c_uint,
76 max_nesting: libc::size_t,
77 callbacks: *sd_callbacks,
78 opaque: *libc::c_void) -> *sd_markdown;
79 fn sd_markdown_render(ob: *buf,
81 doc_size: libc::size_t,
83 fn sd_markdown_free(md: *sd_markdown);
85 fn bufnew(unit: libc::size_t) -> *buf;
86 fn bufrelease(b: *buf);
90 fn render(w: &mut io::Writer, s: &str) {
91 // This code is all lifted from examples/sundown.c in the sundown repo
93 let ob = bufnew(OUTPUT_UNIT);
94 let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
95 MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
97 let options = html_renderopt {
98 toc_data: html_toc_data {
104 link_attributes: None,
106 let callbacks: sd_callbacks = [0, ..26];
108 sdhtml_renderer(&callbacks, &options, 0);
109 let markdown = sd_markdown_new(extensions, 16, &callbacks,
110 &options as *html_renderopt as *libc::c_void);
112 s.as_imm_buf(|data, len| {
113 sd_markdown_render(ob, data, len as libc::size_t, markdown);
115 sd_markdown_free(markdown);
117 vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
125 impl<'self> fmt::Default for Markdown<'self> {
126 fn fmt(md: &Markdown<'self>, fmt: &mut fmt::Formatter) {
127 // This is actually common enough to special-case
128 if md.len() == 0 { return; }
129 render(fmt.buf, md.as_slice());