2222//! // ... something using html
2323//! ```
2424
25+ use std:: cast;
2526use std:: fmt;
26- use std:: libc;
2727use std:: io;
28+ use std:: libc;
29+ use std:: str;
30+ use std:: unstable:: intrinsics;
2831use std:: vec;
2932
3033/// A unit struct which has the `fmt::Default` trait implemented. When
@@ -41,8 +44,10 @@ static MKDEXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
4144
4245type sd_markdown = libc:: c_void ; // this is opaque to us
4346
44- // this is a large struct of callbacks we don't use
45- type sd_callbacks = [ libc:: size_t , ..26 ] ;
47+ struct sd_callbacks {
48+ blockcode : extern "C" fn ( * buf , * buf , * buf , * libc:: c_void ) ,
49+ other : [ libc:: size_t , ..25 ] ,
50+ }
4651
4752struct html_toc_data {
4853 header_count : libc:: c_int ,
@@ -56,6 +61,11 @@ struct html_renderopt {
5661 link_attributes : Option < extern "C" fn ( * buf , * buf , * libc:: c_void ) > ,
5762}
5863
64+ struct my_opaque {
65+ opt : html_renderopt ,
66+ dfltblk : extern "C" fn ( * buf , * buf , * buf , * libc:: c_void ) ,
67+ }
68+
5969struct buf {
6070 data : * u8 ,
6171 size : libc:: size_t ,
@@ -84,7 +94,28 @@ extern {
8494
8595}
8696
87- fn render ( w : & mut io:: Writer , s : & str ) {
97+ pub fn render ( w : & mut io:: Writer , s : & str ) {
98+ extern fn block ( ob : * buf , text : * buf , lang : * buf , opaque : * libc:: c_void ) {
99+ unsafe {
100+ let my_opaque: & my_opaque = cast:: transmute ( opaque) ;
101+ vec:: raw:: buf_as_slice ( ( * text) . data , ( * text) . size as uint , |text| {
102+ let text = str:: from_utf8 ( text) ;
103+ let mut lines = text. lines ( ) . filter ( |l| {
104+ !l. trim ( ) . starts_with ( "#" )
105+ } ) ;
106+ let text = lines. to_owned_vec ( ) . connect ( "\n " ) ;
107+
108+ let buf = buf {
109+ data : text. as_bytes ( ) . as_ptr ( ) ,
110+ size : text. len ( ) as libc:: size_t ,
111+ asize : text. len ( ) as libc:: size_t ,
112+ unit : 0 ,
113+ } ;
114+ ( my_opaque. dfltblk ) ( ob, & buf, lang, opaque) ;
115+ } )
116+ }
117+ }
118+
88119 // This code is all lifted from examples/sundown.c in the sundown repo
89120 unsafe {
90121 let ob = bufnew ( OUTPUT_UNIT ) ;
@@ -100,11 +131,16 @@ fn render(w: &mut io::Writer, s: &str) {
100131 flags : 0 ,
101132 link_attributes : None ,
102133 } ;
103- let callbacks: sd_callbacks = [ 0 , .. 26 ] ;
134+ let mut callbacks: sd_callbacks = intrinsics :: init ( ) ;
104135
105136 sdhtml_renderer ( & callbacks, & options, 0 ) ;
137+ let opaque = my_opaque {
138+ opt : options,
139+ dfltblk : callbacks. blockcode ,
140+ } ;
141+ callbacks. blockcode = block;
106142 let markdown = sd_markdown_new ( extensions, 16 , & callbacks,
107- & options as * html_renderopt as * libc:: c_void ) ;
143+ & opaque as * my_opaque as * libc:: c_void ) ;
108144
109145
110146 sd_markdown_render ( ob, s. as_ptr ( ) , s. len ( ) as libc:: size_t , markdown) ;
@@ -118,6 +154,48 @@ fn render(w: &mut io::Writer, s: &str) {
118154 }
119155}
120156
157+ pub fn find_testable_code ( doc : & str , tests : & mut :: test:: Collector ) {
158+ extern fn block ( _ob : * buf , text : * buf , lang : * buf , opaque : * libc:: c_void ) {
159+ unsafe {
160+ if text. is_null ( ) || lang. is_null ( ) { return }
161+ let ( test, shouldfail, ignore) =
162+ vec:: raw:: buf_as_slice ( ( * lang) . data ,
163+ ( * lang) . size as uint , |lang| {
164+ let s = str:: from_utf8 ( lang) ;
165+ ( s. contains ( "rust" ) , s. contains ( "should_fail" ) ,
166+ s. contains ( "ignore" ) )
167+ } ) ;
168+ if !test { return }
169+ vec:: raw:: buf_as_slice ( ( * text) . data , ( * text) . size as uint , |text| {
170+ let tests: & mut :: test:: Collector = intrinsics:: transmute ( opaque) ;
171+ let text = str:: from_utf8 ( text) ;
172+ let mut lines = text. lines ( ) . map ( |l| l. trim_chars ( & '#' ) ) ;
173+ let text = lines. to_owned_vec ( ) . connect ( "\n " ) ;
174+ tests. add_test ( text, ignore, shouldfail) ;
175+ } )
176+ }
177+ }
178+
179+ unsafe {
180+ let ob = bufnew ( OUTPUT_UNIT ) ;
181+ let extensions = MKDEXT_NO_INTRA_EMPHASIS | MKDEXT_TABLES |
182+ MKDEXT_FENCED_CODE | MKDEXT_AUTOLINK |
183+ MKDEXT_STRIKETHROUGH ;
184+ let callbacks = sd_callbacks {
185+ blockcode : block,
186+ other : intrinsics:: init ( )
187+ } ;
188+
189+ let tests = tests as * mut :: test:: Collector as * libc:: c_void ;
190+ let markdown = sd_markdown_new ( extensions, 16 , & callbacks, tests) ;
191+
192+ sd_markdown_render ( ob, doc. as_ptr ( ) , doc. len ( ) as libc:: size_t ,
193+ markdown) ;
194+ sd_markdown_free ( markdown) ;
195+ bufrelease ( ob) ;
196+ }
197+ }
198+
121199impl < ' a > fmt:: Default for Markdown < ' a > {
122200 fn fmt ( md : & Markdown < ' a > , fmt : & mut fmt:: Formatter ) {
123201 // This is actually common enough to special-case
0 commit comments