/*! Divides the document tree into pages. Each page corresponds is a logical section. There may be pages for individual modules, pages for the crate, indexes, etc. */ use doc::{ItemUtils, PageUtils}; use syntax::ast; export mk_pass; fn mk_pass(output_style: config::OutputStyle) -> Pass { { name: ~"page", f: fn~(srv: astsrv::Srv, doc: doc::Doc) -> doc::Doc { run(srv, doc, output_style) } } } fn run( _srv: astsrv::Srv, doc: doc::Doc, output_style: config::OutputStyle ) -> doc::Doc { if output_style == config::DocPerCrate { return doc; } let (result_port, page_chan) = do task::spawn_conversation |page_port, result_chan| { comm::send(result_chan, make_doc_from_pages(page_port)); }; find_pages(doc, page_chan); comm::recv(result_port) } type PagePort = comm::Port>; type PageChan = comm::Chan>; fn make_doc_from_pages(page_port: PagePort) -> doc::Doc { let mut pages = ~[]; loop { let val = comm::recv(page_port); if val.is_some() { pages += ~[option::unwrap(val)]; } else { break; } } doc::Doc_({ pages: pages }) } fn find_pages(doc: doc::Doc, page_chan: PageChan) { let fold = fold::Fold({ fold_crate: fold_crate, fold_mod: fold_mod, fold_nmod: fold_nmod, .. *fold::default_any_fold(page_chan) }); fold.fold_doc(fold, doc); comm::send(page_chan, None); } fn fold_crate( fold: fold::Fold, doc: doc::CrateDoc ) -> doc::CrateDoc { let doc = fold::default_seq_fold_crate(fold, doc); let page = doc::CratePage({ topmod: strip_mod(doc.topmod), .. doc }); comm::send(fold.ctxt, Some(page)); doc } fn fold_mod( fold: fold::Fold, doc: doc::ModDoc ) -> doc::ModDoc { let doc = fold::default_any_fold_mod(fold, doc); if doc.id() != ast::crate_node_id { let doc = strip_mod(doc); let page = doc::ItemPage(doc::ModTag(doc)); comm::send(fold.ctxt, Some(page)); } doc } fn strip_mod(doc: doc::ModDoc) -> doc::ModDoc { doc::ModDoc_({ items: do vec::filter(doc.items) |item| { match *item { doc::ModTag(_) => false, doc::NmodTag(_) => false, _ => true } }, .. *doc }) } fn fold_nmod( fold: fold::Fold, doc: doc::NmodDoc ) -> doc::NmodDoc { let doc = fold::default_seq_fold_nmod(fold, doc); let page = doc::ItemPage(doc::NmodTag(doc)); comm::send(fold.ctxt, Some(page)); return doc; } #[test] fn should_not_split_the_doc_into_pages_for_doc_per_crate() { let doc = test::mk_doc_( config::DocPerCrate, ~"mod a { } mod b { mod c { } }" ); assert doc.pages.len() == 1u; } #[test] fn should_make_a_page_for_every_mod() { let doc = test::mk_doc(~"mod a { }"); assert doc.pages.mods()[0].name() == ~"a"; } #[test] fn should_remove_mods_from_containing_mods() { let doc = test::mk_doc(~"mod a { }"); assert vec::is_empty(doc.cratemod().mods()); } #[test] fn should_make_a_page_for_every_foreign_mod() { let doc = test::mk_doc(~"extern mod a { }"); assert doc.pages.nmods()[0].name() == ~"a"; } #[test] fn should_remove_foreign_mods_from_containing_mods() { let doc = test::mk_doc(~"extern mod a { }"); assert vec::is_empty(doc.cratemod().nmods()); } #[cfg(test)] mod test { #[legacy_exports]; fn mk_doc_( output_style: config::OutputStyle, source: ~str ) -> doc::Doc { do astsrv::from_str(source) |srv| { let doc = extract::from_srv(srv, ~""); run(srv, doc, output_style) } } fn mk_doc(source: ~str) -> doc::Doc { mk_doc_(config::DocPerMod, source) } }