]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/markdown.rs
Add generation of static libraries to rustc
[rust.git] / src / librustdoc / html / markdown.rs
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.
4 //
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.
10
11 //! Markdown formatting for rustdoc
12 //!
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:
18 //!
19 //! ```rust
20 //! let s = "My *markdown* _text_";
21 //! let html = format!("{}", Markdown(s));
22 //! // ... something using html
23 //! ```
24
25 use std::fmt;
26 use std::libc;
27 use std::io;
28 use std::vec;
29
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);
34
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;
44
45 type sd_markdown = libc::c_void;  // this is opaque to us
46
47 // this is a large struct of callbacks we don't use
48 type sd_callbacks = [libc::size_t, ..26];
49
50 struct html_toc_data {
51     header_count: libc::c_int,
52     current_level: libc::c_int,
53     level_offset: libc::c_int,
54 }
55
56 struct html_renderopt {
57     toc_data: html_toc_data,
58     flags: libc::c_uint,
59     link_attributes: Option<extern "C" fn(*buf, *buf, *libc::c_void)>,
60 }
61
62 struct buf {
63     data: *u8,
64     size: libc::size_t,
65     asize: libc::size_t,
66     unit: libc::size_t,
67 }
68
69 // sundown FFI
70 #[link(name = "sundown", kind = "static")]
71 extern {
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,
80                           document: *u8,
81                           doc_size: libc::size_t,
82                           md: *sd_markdown);
83     fn sd_markdown_free(md: *sd_markdown);
84
85     fn bufnew(unit: libc::size_t) -> *buf;
86     fn bufrelease(b: *buf);
87
88 }
89
90 fn render(w: &mut io::Writer, s: &str) {
91     // This code is all lifted from examples/sundown.c in the sundown repo
92     unsafe {
93         let ob = bufnew(OUTPUT_UNIT);
94         let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
95                          MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
96                          MKDEXT_STRIKETHROUGH;
97         let options = html_renderopt {
98             toc_data: html_toc_data {
99                 header_count: 0,
100                 current_level: 0,
101                 level_offset: 0,
102             },
103             flags: 0,
104             link_attributes: None,
105         };
106         let callbacks: sd_callbacks = [0, ..26];
107
108         sdhtml_renderer(&callbacks, &options, 0);
109         let markdown = sd_markdown_new(extensions, 16, &callbacks,
110                                        &options as *html_renderopt as *libc::c_void);
111
112         s.as_imm_buf(|data, len| {
113             sd_markdown_render(ob, data, len as libc::size_t, markdown);
114         });
115         sd_markdown_free(markdown);
116
117         vec::raw::buf_as_slice((*ob).data, (*ob).size as uint, |buf| {
118             w.write(buf);
119         });
120
121         bufrelease(ob);
122     }
123 }
124
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());
130     }
131 }