use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::rc::Rc;
-use std::sync::mpsc::channel;
+use std::sync::mpsc::{channel, Receiver};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::source_map::FileName;
-use rustc_span::{symbol::sym, Symbol};
+use rustc_span::symbol::sym;
use super::cache::{build_index, ExternalLocation};
use super::print_item::{full_path, item_path, print_item};
use super::write_shared::write_shared;
-use super::{
- print_sidebar, settings, AllTypes, NameDoc, SharedContext, StylePath, BASIC_KEYWORDS,
- CURRENT_DEPTH,
-};
+use super::{print_sidebar, settings, AllTypes, NameDoc, StylePath, BASIC_KEYWORDS};
use crate::clean::{self, AttributesExt};
use crate::config::RenderOptions;
crate struct Context<'tcx> {
/// Current hierarchy of components leading down to what's currently being
/// rendered
- pub(super) current: Vec<String>,
+ pub(crate) current: Vec<String>,
/// The current destination folder of where HTML artifacts should be placed.
/// This changes as the context descends into the module hierarchy.
pub(super) dst: PathBuf,
#[cfg(target_arch = "x86_64")]
rustc_data_structures::static_assert_size!(Context<'_>, 152);
+/// Shared mutable state used in [`Context`] and elsewhere.
+crate struct SharedContext<'tcx> {
+ crate tcx: TyCtxt<'tcx>,
+ /// The path to the crate root source minus the file name.
+ /// Used for simplifying paths to the highlighted source code files.
+ crate src_root: PathBuf,
+ /// This describes the layout of each page, and is not modified after
+ /// creation of the context (contains info like the favicon and added html).
+ crate layout: layout::Layout,
+ /// This flag indicates whether `[src]` links should be generated or not. If
+ /// the source files are present in the html rendering, then this will be
+ /// `true`.
+ crate include_sources: bool,
+ /// The local file sources we've emitted and their respective url-paths.
+ crate local_sources: FxHashMap<PathBuf, String>,
+ /// Whether the collapsed pass ran
+ collapsed: bool,
+ /// The base-URL of the issue tracker for when an item has been tagged with
+ /// an issue number.
+ pub(super) issue_tracker_base_url: Option<String>,
+ /// The directories that have already been created in this doc run. Used to reduce the number
+ /// of spurious `create_dir_all` calls.
+ created_dirs: RefCell<FxHashSet<PathBuf>>,
+ /// This flag indicates whether listings of modules (in the side bar and documentation itself)
+ /// should be ordered alphabetically or in order of appearance (in the source code).
+ pub(super) sort_modules_alphabetically: bool,
+ /// Additional CSS files to be added to the generated docs.
+ crate style_files: Vec<StylePath>,
+ /// Suffix to be added on resource files (if suffix is "-v2" then "light.css" becomes
+ /// "light-v2.css").
+ crate resource_suffix: String,
+ /// Optional path string to be used to load static files on output pages. If not set, uses
+ /// combinations of `../` to reach the documentation root.
+ crate static_root_path: Option<String>,
+ /// The fs handle we are working with.
+ crate fs: DocFS,
+ pub(super) codes: ErrorCodes,
+ pub(super) playground: Option<markdown::Playground>,
+ all: RefCell<AllTypes>,
+ /// Storage for the errors produced while generating documentation so they
+ /// can be printed together at the end.
+ errors: Receiver<String>,
+ /// `None` by default, depends on the `generate-redirect-map` option flag. If this field is set
+ /// to `Some(...)`, it'll store redirections and then generate a JSON file at the top level of
+ /// the crate.
+ redirections: Option<RefCell<FxHashMap<String, String>>>,
+}
+
+impl SharedContext<'_> {
+ crate fn ensure_dir(&self, dst: &Path) -> Result<(), Error> {
+ let mut dirs = self.created_dirs.borrow_mut();
+ if !dirs.contains(dst) {
+ try_err!(self.fs.create_dir_all(dst), dst);
+ dirs.insert(dst.to_path_buf());
+ }
+
+ Ok(())
+ }
+
+ /// Based on whether the `collapse-docs` pass was run, return either the `doc_value` or the
+ /// `collapsed_doc_value` of the given item.
+ crate fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option<String> {
+ if self.collapsed { item.collapsed_doc_value() } else { item.doc_value() }
+ }
+
+ crate fn edition(&self) -> Edition {
+ self.tcx.sess.edition()
+ }
+}
+
impl<'tcx> Context<'tcx> {
- pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
+ pub(crate) fn tcx(&self) -> TyCtxt<'tcx> {
self.shared.tcx
}
+ pub(crate) fn cache(&self) -> &Cache {
+ &self.cache
+ }
+
fn sess(&self) -> &'tcx Session {
&self.shared.tcx.sess
}
"../".repeat(self.current.len())
}
- fn render_item(&self, it: &clean::Item, pushname: bool) -> String {
- // A little unfortunate that this is done like this, but it sure
- // does make formatting *a lot* nicer.
- CURRENT_DEPTH.with(|slot| {
- slot.set(self.current.len());
- });
-
- let mut title = if it.is_primitive() || it.is_keyword() {
- // No need to include the namespace for primitive types and keywords
- String::new()
- } else {
- self.current.join("::")
- };
- if pushname {
- if !title.is_empty() {
- title.push_str("::");
- }
+ fn render_item(&self, it: &clean::Item, is_module: bool) -> String {
+ let mut title = String::new();
+ if !is_module {
title.push_str(&it.name.unwrap().as_str());
}
+ if !it.is_primitive() && !it.is_keyword() {
+ if !is_module {
+ title.push_str(" in ");
+ }
+ // No need to include the namespace for primitive types and keywords
+ title.push_str(&self.current.join("::"));
+ };
title.push_str(" - Rust");
let tyname = it.type_();
let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(&doc));
fn init(
mut krate: clean::Crate,
options: RenderOptions,
- edition: Edition,
mut cache: Cache,
tcx: TyCtxt<'tcx>,
) -> Result<(Self, clean::Crate), Error> {
resource_suffix,
static_root_path,
fs: DocFS::new(sender),
- edition,
codes: ErrorCodes::from(unstable_features.is_nightly_build()),
playground,
all: RefCell::new(AllTypes::new()),
cache: Rc::new(cache),
};
- CURRENT_DEPTH.with(|s| s.set(0));
-
// Write shared runs within a flock; disable thread dispatching of IO temporarily.
Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(true);
write_shared(&cx, &krate, index, &md_opts)?;
}
}
- fn after_krate(
- &mut self,
- crate_name: Symbol,
- diag: &rustc_errors::Handler,
- ) -> Result<(), Error> {
+ fn after_krate(&mut self) -> Result<(), Error> {
+ let crate_name = self.tcx().crate_name(LOCAL_CRATE);
let final_file = self.dst.join(&*crate_name.as_str()).join("all.html");
let settings_file = self.dst.join("settings.html");
// Flush pending errors.
Rc::get_mut(&mut self.shared).unwrap().fs.close();
- let nb_errors = self.shared.errors.iter().map(|err| diag.struct_err(&err).emit()).count();
+ let nb_errors =
+ self.shared.errors.iter().map(|err| self.tcx().sess.struct_err(&err).emit()).count();
if nb_errors > 0 {
Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
} else {
info!("Recursing into {}", self.dst.display());
- let buf = self.render_item(item, false);
+ let buf = self.render_item(item, true);
// buf will be empty if the module is stripped and there is no redirect for it
if !buf.is_empty() {
self.shared.ensure_dir(&self.dst)?;
Ok(())
}
- fn mod_item_out(&mut self, _item_name: &str) -> Result<(), Error> {
+ fn mod_item_out(&mut self) -> Result<(), Error> {
info!("Recursed; leaving {}", self.dst.display());
// Go back to where we were at
self.render_redirect_pages = item.is_stripped();
}
- let buf = self.render_item(&item, true);
+ let buf = self.render_item(&item, false);
// buf will be empty if the item is stripped and there is no redirect for it
if !buf.is_empty() {
let name = item.name.as_ref().unwrap();