1 // Copyright 2012-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.
31 pub type Writer = ~fn(v: WriteInstr);
32 pub type WriterFactory = ~fn(page: doc::Page) -> Writer;
34 pub trait WriterUtils {
35 fn put_str(&self, str: ~str);
36 fn put_line(&self, str: ~str);
40 impl WriterUtils for Writer {
41 fn put_str(&self, str: ~str) {
45 fn put_line(&self, str: ~str) {
46 self.put_str(str + "\n");
54 pub fn make_writer_factory(config: config::Config) -> WriterFactory {
55 match config.output_format {
57 markdown_writer_factory(config)
59 config::PandocHtml => {
60 pandoc_writer_factory(config)
65 fn markdown_writer_factory(config: config::Config) -> WriterFactory {
66 let result: ~fn(page: doc::Page) -> Writer = |page| {
67 markdown_writer(&config, page)
72 fn pandoc_writer_factory(config: config::Config) -> WriterFactory {
73 let result: ~fn(doc::Page) -> Writer = |page| {
74 pandoc_writer(&config, page)
80 config: &config::Config,
83 let filename = make_local_filename(config, page);
84 do generic_writer |markdown| {
85 write_file(&filename, markdown);
90 config: &config::Config,
93 assert!(config.pandoc_cmd.is_some());
94 let pandoc_cmd = (*config.pandoc_cmd.get_ref()).clone();
95 let filename = make_local_filename(config, page);
103 ~"--output=" + filename.to_str()
106 do generic_writer |markdown| {
107 use std::io::WriterUtil;
109 debug!("pandoc cmd: %s", pandoc_cmd);
110 debug!("pandoc args: %s", pandoc_args.connect(" "));
112 let mut proc = run::Process::new(pandoc_cmd, pandoc_args, run::ProcessOptions::new());
114 proc.input().write_str(markdown);
115 let output = proc.finish_with_output();
117 debug!("pandoc result: %i", output.status);
118 if output.status != 0 {
119 error!("pandoc-out: %s", str::from_bytes(output.output));
120 error!("pandoc-err: %s", str::from_bytes(output.error));
121 fail!("pandoc failed");
126 fn generic_writer(process: ~fn(markdown: ~str)) -> Writer {
127 let (po, ch) = stream::<WriteInstr>();
129 let mut markdown = ~"";
130 let mut keep_going = true;
133 Write(s) => markdown.push_str(s),
134 Done => keep_going = false
139 let result: ~fn(instr: WriteInstr) = |instr| ch.send(instr);
143 pub fn make_local_filename(
144 config: &config::Config,
147 let filename = make_filename(config, page);
148 config.output_dir.push_rel(&filename)
151 pub fn make_filename(
152 config: &config::Config,
157 doc::CratePage(doc) => {
158 if config.output_format == config::PandocHtml &&
159 config.output_style == config::DocPerMod {
162 assert!(doc.topmod.name_() != ~"");
166 doc::ItemPage(doc) => {
167 (doc.path() + &[doc.name_()]).connect("_")
171 let ext = match config.output_format {
172 config::Markdown => ~"md",
173 config::PandocHtml => ~"html"
176 Path(filename).with_filetype(ext)
179 fn write_file(path: &Path, s: ~str) {
180 use std::io::WriterUtil;
182 match io::file_writer(path, [io::Create, io::Truncate]) {
183 result::Ok(writer) => {
186 result::Err(e) => fail!(e)
190 pub fn future_writer_factory(
191 ) -> (WriterFactory, Port<(doc::Page, ~str)>) {
192 let (markdown_po, markdown_ch) = stream();
193 let markdown_ch = SharedChan::new(markdown_ch);
194 let writer_factory: WriterFactory = |page| {
195 let (writer_po, writer_ch) = comm::stream();
196 let markdown_ch = markdown_ch.clone();
198 let (writer, future) = future_writer();
199 let mut future = future;
200 writer_ch.send(writer);
201 let s = future.get();
202 markdown_ch.send((page.clone(), s));
207 (writer_factory, markdown_po)
210 fn future_writer() -> (Writer, future::Future<~str>) {
211 let (port, chan) = comm::stream();
212 let writer: ~fn(instr: WriteInstr) = |instr| chan.send(instr.clone());
213 let future = do future::from_fn || {
217 Write(s) => res.push_str(s),
234 use super::make_local_filename;
236 fn mk_doc(name: ~str, source: ~str) -> doc::Doc {
237 do astsrv::from_str(source) |srv| {
238 let doc = extract::from_srv(srv.clone(), name.clone());
239 let doc = (path_pass::mk_pass().f)(srv.clone(), doc);
245 fn should_use_markdown_file_name_based_off_crate() {
246 let config = config::Config {
247 output_dir: Path("output/dir"),
248 output_format: config::Markdown,
249 output_style: config::DocPerCrate,
250 .. config::default_config(&Path("input/test.rc"))
252 let doc = mk_doc(~"test", ~"");
253 let page = doc::CratePage(doc.CrateDoc());
254 let filename = make_local_filename(&config, page);
255 assert_eq!(filename.to_str(), ~"output/dir/test.md");
259 fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
260 let config = config::Config {
261 output_dir: Path("output/dir"),
262 output_format: config::PandocHtml,
263 output_style: config::DocPerMod,
264 .. config::default_config(&Path("input/test.rc"))
266 let doc = mk_doc(~"", ~"");
267 let page = doc::CratePage(doc.CrateDoc());
268 let filename = make_local_filename(&config, page);
269 assert_eq!(filename.to_str(), ~"output/dir/index.html");
273 fn should_name_mod_file_names_by_path() {
274 let config = config::Config {
275 output_dir: Path("output/dir"),
276 output_format: config::PandocHtml,
277 output_style: config::DocPerMod,
278 .. config::default_config(&Path("input/test.rc"))
280 let doc = mk_doc(~"", ~"mod a { mod b { } }");
281 // hidden __std_macros module at the start.
282 let modb = doc.cratemod().mods()[1].mods()[0].clone();
283 let page = doc::ItemPage(doc::ModTag(modb));
284 let filename = make_local_filename(&config, page);
285 assert_eq!(filename, Path("output/dir/a_b.html"));