0
0
mirror of https://github.com/rust-lang/rust.git synced 2024-12-01 13:18:54 +01:00
rust/src/librustdoc/sectionalize_pass.rs

270 lines
6.2 KiB
Rust
Raw Normal View History

// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Breaks rustdocs into sections according to their headers
2012-03-09 20:47:31 +01:00
use core::prelude::*;
use astsrv;
use attr_pass;
2012-09-19 01:48:40 +02:00
use doc::ItemUtils;
use doc;
use extract;
use fold::Fold;
use fold;
use pass::Pass;
use core::str;
use core::vec;
use std::par;
2012-11-20 03:00:12 +01:00
pub fn mk_pass() -> Pass {
Pass {
name: ~"sectionalize",
2012-03-09 20:47:31 +01:00
f: run
}
}
pub fn run(_srv: astsrv::Srv, +doc: doc::Doc) -> doc::Doc {
let fold = Fold {
2012-03-09 20:47:31 +01:00
fold_item: fold_item,
fold_trait: fold_trait,
2012-09-04 22:29:32 +02:00
fold_impl: fold_impl,
.. fold::default_any_fold(())
};
(fold.fold_doc)(&fold, doc)
2012-03-09 20:47:31 +01:00
}
2012-11-20 03:48:46 +01:00
fn fold_item(fold: &fold::Fold<()>, +doc: doc::ItemDoc) -> doc::ItemDoc {
2012-03-09 20:47:31 +01:00
let doc = fold::default_seq_fold_item(fold, doc);
2013-01-31 03:52:31 +01:00
let (desc, sections) = sectionalize(copy doc.desc);
2012-03-09 20:47:31 +01:00
doc::ItemDoc {
2012-03-09 20:47:31 +01:00
desc: desc,
2012-09-04 22:29:32 +02:00
sections: sections,
.. doc
2012-03-09 20:47:31 +01:00
}
}
2012-11-20 03:48:46 +01:00
fn fold_trait(fold: &fold::Fold<()>, +doc: doc::TraitDoc) -> doc::TraitDoc {
let doc = fold::default_seq_fold_trait(fold, doc);
2012-03-09 20:47:31 +01:00
doc::TraitDoc {
methods: do par::map(doc.methods) |method| {
2013-01-31 03:52:31 +01:00
let (desc, sections) = sectionalize(copy method.desc);
2012-03-09 20:47:31 +01:00
doc::MethodDoc {
2012-03-09 20:47:31 +01:00
desc: desc,
2012-09-04 22:29:32 +02:00
sections: sections,
2013-01-30 22:14:35 +01:00
.. copy *method
2012-03-09 20:47:31 +01:00
}
2012-09-04 22:29:32 +02:00
},
.. doc
2012-03-09 20:47:31 +01:00
}
}
2012-11-20 03:48:46 +01:00
fn fold_impl(fold: &fold::Fold<()>, +doc: doc::ImplDoc) -> doc::ImplDoc {
2012-03-09 20:47:31 +01:00
let doc = fold::default_seq_fold_impl(fold, doc);
doc::ImplDoc {
methods: do par::map(doc.methods) |method| {
2013-01-31 03:52:31 +01:00
let (desc, sections) = sectionalize(copy method.desc);
2012-03-09 20:47:31 +01:00
doc::MethodDoc {
2012-03-09 20:47:31 +01:00
desc: desc,
2012-09-04 22:29:32 +02:00
sections: sections,
2013-01-30 22:14:35 +01:00
.. copy *method
2012-03-09 20:47:31 +01:00
}
2012-09-04 22:29:32 +02:00
},
.. doc
2012-03-09 20:47:31 +01:00
}
}
2013-01-31 03:52:31 +01:00
fn sectionalize(+desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) {
2012-03-09 20:47:31 +01:00
/*!
* Take a description of the form
*
* General text
*
* # Section header
*
* Section text
*
* # Section header
*
* Section text
*
* and remove each header and accompanying text into section records.
*/
2012-03-09 20:47:31 +01:00
2012-09-22 04:37:57 +02:00
if desc.is_none() {
2012-08-20 21:23:37 +02:00
return (None, ~[]);
2012-03-09 20:47:31 +01:00
}
2013-01-30 22:14:35 +01:00
let lines = str::lines((copy desc).get());
2012-03-09 20:47:31 +01:00
2012-08-20 21:23:37 +02:00
let mut new_desc = None::<~str>;
let mut current_section = None;
let mut sections = ~[];
2012-03-09 20:47:31 +01:00
2012-07-01 01:19:07 +02:00
for lines.each |line| {
2013-01-30 22:14:35 +01:00
match parse_header(copy *line) {
2012-08-20 21:23:37 +02:00
Some(header) => {
2012-09-22 04:37:57 +02:00
if current_section.is_some() {
2013-01-30 22:14:35 +01:00
sections += ~[(&current_section).get()];
2012-03-09 20:47:31 +01:00
}
current_section = Some(doc::Section {
2012-03-09 20:47:31 +01:00
header: header,
body: ~""
2012-03-09 20:47:31 +01:00
});
}
2012-08-20 21:23:37 +02:00
None => {
2012-08-06 21:34:08 +02:00
match copy current_section {
2012-08-20 21:23:37 +02:00
Some(section) => {
current_section = Some(doc::Section {
body: section.body + ~"\n" + *line,
2012-09-04 22:29:32 +02:00
.. section
2012-03-09 20:47:31 +01:00
});
}
2012-08-20 21:23:37 +02:00
None => {
2013-01-30 22:14:35 +01:00
new_desc = match copy new_desc {
2012-08-20 21:23:37 +02:00
Some(desc) => {
Some(desc + ~"\n" + *line)
2012-03-09 20:47:31 +01:00
}
2012-08-20 21:23:37 +02:00
None => {
2013-01-30 22:14:35 +01:00
Some(copy *line)
2012-03-09 20:47:31 +01:00
}
};
2012-03-09 20:47:31 +01:00
}
}
}
}
}
2012-09-22 04:37:57 +02:00
if current_section.is_some() {
sections += ~[current_section.get()];
2012-03-09 20:47:31 +01:00
}
(new_desc, sections)
}
2013-01-31 03:52:31 +01:00
fn parse_header(+line: ~str) -> Option<~str> {
if str::starts_with(line, ~"# ") {
2012-08-20 21:23:37 +02:00
Some(str::slice(line, 2u, str::len(line)))
2012-03-09 20:47:31 +01:00
} else {
2012-08-20 21:23:37 +02:00
None
2012-03-09 20:47:31 +01:00
}
}
#[test]
fn should_create_section_headers() {
let doc = test::mk_doc(
~"#[doc = \"\
2012-03-09 20:47:31 +01:00
# Header\n\
Body\"]\
mod a {
}");
2012-03-09 20:47:31 +01:00
assert str::contains(
doc.cratemod().mods()[0].item.sections[0].header,
~"Header");
2012-03-09 20:47:31 +01:00
}
#[test]
fn should_create_section_bodies() {
let doc = test::mk_doc(
~"#[doc = \"\
2012-03-09 20:47:31 +01:00
# Header\n\
Body\"]\
mod a {
}");
2012-03-09 20:47:31 +01:00
assert str::contains(
doc.cratemod().mods()[0].item.sections[0].body,
~"Body");
2012-03-09 20:47:31 +01:00
}
#[test]
fn should_not_create_sections_from_indented_headers() {
let doc = test::mk_doc(
~"#[doc = \"\n\
2012-03-09 20:47:31 +01:00
Text\n # Header\n\
Body\"]\
mod a {
}");
2012-03-09 20:47:31 +01:00
assert vec::is_empty(doc.cratemod().mods()[0].item.sections);
}
#[test]
fn should_remove_section_text_from_main_desc() {
let doc = test::mk_doc(
~"#[doc = \"\
2012-03-09 20:47:31 +01:00
Description\n\n\
# Header\n\
Body\"]\
mod a {
}");
2012-03-09 20:47:31 +01:00
assert !str::contains(
2012-09-22 04:37:57 +02:00
doc.cratemod().mods()[0].desc().get(),
~"Header");
2012-03-09 20:47:31 +01:00
assert !str::contains(
2012-09-22 04:37:57 +02:00
doc.cratemod().mods()[0].desc().get(),
~"Body");
2012-03-09 20:47:31 +01:00
}
#[test]
fn should_eliminate_desc_if_it_is_just_whitespace() {
let doc = test::mk_doc(
~"#[doc = \"\
2012-03-09 20:47:31 +01:00
# Header\n\
Body\"]\
mod a {
}");
2012-08-20 21:23:37 +02:00
assert doc.cratemod().mods()[0].desc() == None;
2012-03-09 20:47:31 +01:00
}
#[test]
fn should_sectionalize_trait_methods() {
2012-03-09 20:47:31 +01:00
let doc = test::mk_doc(
~"trait i {
2012-03-09 20:47:31 +01:00
#[doc = \"\
# Header\n\
Body\"]\
fn a(); }");
assert doc.cratemod().traits()[0].methods[0].sections.len() == 1u;
2012-03-09 20:47:31 +01:00
}
#[test]
fn should_sectionalize_impl_methods() {
let doc = test::mk_doc(
2012-08-09 02:19:06 +02:00
~"impl bool {
2012-03-09 20:47:31 +01:00
#[doc = \"\
# Header\n\
Body\"]\
fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].sections.len() == 1u;
}
#[cfg(test)]
pub mod test {
2012-12-30 06:17:06 +01:00
use astsrv;
use attr_pass;
use doc;
use extract;
use sectionalize_pass::run;
2012-12-30 06:17:06 +01:00
2013-01-31 03:52:31 +01:00
pub fn mk_doc(+source: ~str) -> doc::Doc {
2013-01-30 22:14:35 +01:00
do astsrv::from_str(copy source) |srv| {
let doc = extract::from_srv(srv, ~"");
let doc = (attr_pass::mk_pass().f)(srv, doc);
2012-03-09 20:47:31 +01:00
run(srv, doc)
}
}
}