diff options
Diffstat (limited to 'src/librustdoc/html/render/mod.rs')
| -rw-r--r-- | src/librustdoc/html/render/mod.rs | 298 | 
1 files changed, 169 insertions, 129 deletions
| diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 28f7a4d3162..db04624dca8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -52,10 +52,12 @@ use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::sync::Lrc; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::Mutability; use rustc_middle::middle::stability; +use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::FileName; @@ -76,7 +78,9 @@ use crate::html::format::fmt_impl_for_trait_page; use crate::html::format::Function; use crate::html::format::{href, print_default_space, print_generic_bounds, WhereClause}; use crate::html::format::{print_abi_with_space, Buffer, PrintWithSpace}; -use crate::html::markdown::{self, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine}; +use crate::html::markdown::{ + self, plain_text_summary, ErrorCodes, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine, +}; use crate::html::sources; use crate::html::{highlight, layout, static_files}; use cache::{build_index, ExternalLocation}; @@ -119,6 +123,7 @@ crate struct Context { } crate struct SharedContext { + crate sess: Lrc<Session>, /// 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, @@ -165,12 +170,14 @@ impl Context { // `style-suffix.min.css`. Path::extension would just return `css` // which would result in `style.min-suffix.css` which isn't what we // want. - let mut iter = filename.splitn(2, '.'); - let base = iter.next().unwrap(); - let ext = iter.next().unwrap(); - let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext,); + let (base, ext) = filename.split_once('.').unwrap(); + let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext); self.dst.join(&filename) } + + fn sess(&self) -> &Session { + &self.shared.sess + } } impl SharedContext { @@ -381,6 +388,7 @@ impl FormatRenderer for Context { _render_info: RenderInfo, edition: Edition, cache: &mut Cache, + sess: Lrc<Session>, ) -> Result<(Context, clean::Crate), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); @@ -453,6 +461,7 @@ impl FormatRenderer for Context { } let (sender, receiver) = channel(); let mut scx = SharedContext { + sess, collapsed: krate.collapsed, src_root, include_sources, @@ -1194,6 +1203,16 @@ fn write_minify( } } +fn write_srclink(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) { + if let Some(l) = cx.src_href(item, cache) { + write!( + buf, + "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", + l, "goto source code" + ) + } +} + #[derive(Debug, Eq, PartialEq, Hash)] struct ItemEntry { url: String, @@ -1594,9 +1613,10 @@ impl Context { Some(ref s) => s.to_string(), }; let short = short.to_string(); - map.entry(short) - .or_default() - .push((myname, Some(plain_text_summary(item.doc_value())))); + map.entry(short).or_default().push(( + myname, + Some(item.doc_value().map_or_else(|| String::new(), plain_text_summary)), + )); } if self.shared.sort_modules_alphabetically { @@ -1618,24 +1638,24 @@ impl Context { /// of their crate documentation isn't known. fn src_href(&self, item: &clean::Item, cache: &Cache) -> Option<String> { let mut root = self.root_path(); - let mut path = String::new(); + let cnum = item.source.cnum(self.sess()); // We can safely ignore synthetic `SourceFile`s. - let file = match item.source.filename { + let file = match item.source.filename(self.sess()) { FileName::Real(ref path) => path.local_path().to_path_buf(), _ => return None, }; let file = &file; - let (krate, path) = if item.source.cnum == LOCAL_CRATE { + let (krate, path) = if cnum == LOCAL_CRATE { if let Some(path) = self.shared.local_sources.get(file) { (&self.shared.layout.krate, path) } else { return None; } } else { - let (krate, src_root) = match *cache.extern_locations.get(&item.source.cnum)? { + let (krate, src_root) = match *cache.extern_locations.get(&cnum)? { (ref name, ref src, ExternalLocation::Local) => (name, src), (ref name, ref src, ExternalLocation::Remote(ref s)) => { root = s.to_string(); @@ -1654,11 +1674,10 @@ impl Context { (krate, &path) }; - let lines = if item.source.loline == item.source.hiline { - item.source.loline.to_string() - } else { - format!("{}-{}", item.source.loline, item.source.hiline) - }; + let loline = item.source.lo(self.sess()).line; + let hiline = item.source.hi(self.sess()).line; + let lines = + if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) }; Some(format!( "{root}src/{krate}/{path}#{lines}", root = Escape(&root), @@ -1682,13 +1701,13 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) debug_assert!(!item.is_stripped()); // Write the breadcrumb trail header for the top write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">"); - if let Some(version) = item.stable_since() { - write!( - buf, - "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", - version - ); - } + render_stability_since_raw( + buf, + item.stable_since().as_deref(), + item.const_stable_since().as_deref(), + None, + None, + ); write!( buf, "<span id=\"render-detail\">\ @@ -1706,13 +1725,7 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. if cx.shared.include_sources && !item.is_primitive() { - if let Some(l) = cx.src_href(item, cache) { - write!( - buf, - "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", - l, "goto source code" - ); - } + write_srclink(cx, item, buf, cache); } write!(buf, "</span>"); // out-of-band @@ -1806,41 +1819,11 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } -/// Renders the first paragraph of the given markdown as plain text, making it suitable for -/// contexts like alt-text or the search index. -/// -/// If no markdown is supplied, the empty string is returned. -/// -/// See [`markdown::plain_text_summary`] for further details. -#[inline] -crate fn plain_text_summary(s: Option<&str>) -> String { - s.map(markdown::plain_text_summary).unwrap_or_default() -} - -crate fn shorten(s: String) -> String { - if s.chars().count() > 60 { - let mut len = 0; - let mut ret = s - .split_whitespace() - .take_while(|p| { - // + 1 for the added character after the word. - len += p.chars().count() + 1; - len < 60 - }) - .collect::<Vec<_>>() - .join(" "); - ret.push('…'); - ret - } else { - s - } -} - fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_stability(w, cx, item, false, parent); + document_item_info(w, cx, item, false, parent); document_full(w, item, cx, "", false); } @@ -1876,10 +1859,17 @@ fn render_markdown( fn document_short( w: &mut Buffer, item: &clean::Item, + cx: &Context, link: AssocItemLink<'_>, prefix: &str, is_hidden: bool, + parent: Option<&clean::Item>, + show_def_docs: bool, ) { + document_item_info(w, cx, item, is_hidden, parent); + if !show_def_docs { + return; + } if let Some(s) = item.doc_value() { let mut summary_html = MarkdownSummaryLine(s, &item.links()).into_string(); @@ -1924,18 +1914,23 @@ fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, } } -fn document_stability( +/// Add extra information about an item such as: +/// +/// * Stability +/// * Deprecated +/// * Required features (through the `doc_cfg` feature) +fn document_item_info( w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool, parent: Option<&clean::Item>, ) { - let stabilities = short_stability(item, cx, parent); - if !stabilities.is_empty() { - write!(w, "<div class=\"stability{}\">", if is_hidden { " hidden" } else { "" }); - for stability in stabilities { - write!(w, "{}", stability); + let item_infos = short_item_info(item, cx, parent); + if !item_infos.is_empty() { + write!(w, "<div class=\"item-info{}\">", if is_hidden { " hidden" } else { "" }); + for info in item_infos { + write!(w, "{}", info); } write!(w, "</div>"); } @@ -2190,7 +2185,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: <td class=\"docblock-short\">{stab_tags}{docs}</td>\ </tr>", name = *myitem.name.as_ref().unwrap(), - stab_tags = stability_tags(myitem, item), + stab_tags = extra_info_tags(myitem, item), docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), class = myitem.type_(), add = add, @@ -2212,9 +2207,9 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: } } -/// Render the stability and deprecation tags that are displayed in the item's summary at the -/// module level. -fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String { +/// Render the stability, deprecation and portability tags that are displayed in the item's summary +/// at the module level. +fn extra_info_tags(item: &clean::Item, parent: &clean::Item) -> String { let mut tags = String::new(); fn tag_html(class: &str, title: &str, contents: &str) -> String { @@ -2267,10 +2262,10 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html())) } -/// Render the stability and/or deprecation warning that is displayed at the top of the item's -/// documentation. -fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec<String> { - let mut stability = vec![]; +/// Render the stability, deprecation and portability information that is displayed at the top of +/// the item's documentation. +fn short_item_info(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec<String> { + let mut extra_info = vec![]; let error_codes = cx.shared.codes; if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation { @@ -2297,7 +2292,7 @@ fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item ); message.push_str(&format!(": {}", html.into_string())); } - stability.push(format!( + extra_info.push(format!( "<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>", message, )); @@ -2341,14 +2336,14 @@ fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item ); } - stability.push(format!("<div class=\"stab unstable\">{}</div>", message)); + extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message)); } if let Some(portability) = portability(item, parent) { - stability.push(portability); + extra_info.push(portability); } - stability + extra_info } fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Constant) { @@ -2460,6 +2455,7 @@ fn render_implementor( AssocItemLink::Anchor(None), RenderMode::Normal, implementor.impl_item.stable_since().as_deref(), + implementor.impl_item.const_stable_since().as_deref(), false, Some(use_absolute), false, @@ -2490,6 +2486,7 @@ fn render_impls( assoc_link, RenderMode::Normal, containing_item.stable_since().as_deref(), + containing_item.const_stable_since().as_deref(), true, None, false, @@ -2624,7 +2621,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, write!(w, "{}<span class=\"loading-content\">Loading content...</span>", extra_content) } - fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) { + fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item, cache: &Cache) { let name = m.name.as_ref().unwrap(); info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default()); let item_type = m.type_(); @@ -2633,6 +2630,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, "</code>"); render_stability_since(w, m, t); + write_srclink(cx, m, w, cache); write!(w, "</h3>"); document(w, cx, m, Some(t)); } @@ -2644,8 +2642,8 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, "Associated Types", "<div class=\"methods\">", ); - for t in &types { - trait_item(w, cx, *t, it); + for t in types { + trait_item(w, cx, t, it, cache); } write_loading_content(w, "</div>"); } @@ -2657,8 +2655,8 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, "Associated Constants", "<div class=\"methods\">", ); - for t in &consts { - trait_item(w, cx, *t, it); + for t in consts { + trait_item(w, cx, t, it, cache); } write_loading_content(w, "</div>"); } @@ -2671,8 +2669,8 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, "Required methods", "<div class=\"methods\">", ); - for m in &required { - trait_item(w, cx, *m, it); + for m in required { + trait_item(w, cx, m, it, cache); } write_loading_content(w, "</div>"); } @@ -2683,8 +2681,8 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, "Provided methods", "<div class=\"methods\">", ); - for m in &provided { - trait_item(w, cx, *m, it); + for m in provided { + trait_item(w, cx, m, it, cache); } write_loading_content(w, "</div>"); } @@ -2739,6 +2737,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, assoc_link, RenderMode::Normal, implementor.impl_item.stable_since().as_deref(), + implementor.impl_item.const_stable_since().as_deref(), false, None, true, @@ -2881,10 +2880,40 @@ fn assoc_type( } } -fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: Option<&str>) { +fn render_stability_since_raw( + w: &mut Buffer, + ver: Option<&str>, + const_ver: Option<&str>, + containing_ver: Option<&str>, + containing_const_ver: Option<&str>, +) { + let ver = ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None }); + + let const_ver = const_ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None }); + if let Some(v) = ver { - if containing_ver != ver && !v.is_empty() { - write!(w, "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", v) + if let Some(cv) = const_ver { + if const_ver != containing_const_ver { + write!( + w, + "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>", + v, cv + ); + } else if ver != containing_ver { + write!( + w, + "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", + v + ); + } + } else { + if ver != containing_ver { + write!( + w, + "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", + v + ); + } } } } @@ -2893,7 +2922,9 @@ fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: & render_stability_since_raw( w, item.stable_since().as_deref(), + item.const_stable_since().as_deref(), containing_item.stable_since().as_deref(), + containing_item.const_stable_since().as_deref(), ) } @@ -3445,6 +3476,7 @@ fn render_assoc_items( AssocItemLink::Anchor(None), render_mode, containing_item.stable_since().as_deref(), + containing_item.const_stable_since().as_deref(), true, None, false, @@ -3637,6 +3669,7 @@ fn render_impl( link: AssocItemLink<'_>, render_mode: RenderMode, outer_version: Option<&str>, + outer_const_version: Option<&str>, show_def_docs: bool, use_absolute: Option<bool>, is_on_foreign_type: bool, @@ -3688,23 +3721,19 @@ fn render_impl( ); } write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); - let since = i.impl_item.stability.as_ref().and_then(|s| match s.level { - StabilityLevel::Stable { since } => Some(since.as_str()), - StabilityLevel::Unstable { .. } => None, - }); - render_stability_since_raw(w, since.as_deref(), outer_version); - if let Some(l) = cx.src_href(&i.impl_item, cache) { - write!( - w, - "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", - l, "goto source code" - ); - } + render_stability_since_raw( + w, + i.impl_item.stable_since().as_deref(), + i.impl_item.const_stable_since().as_deref(), + outer_version, + outer_const_version, + ); + write_srclink(cx, &i.impl_item, w, cache); write!(w, "</h3>"); if trait_.is_some() { if let Some(portability) = portability(&i.impl_item, Some(parent)) { - write!(w, "<div class=\"stability\">{}</div>", portability); + write!(w, "<div class=\"item-info\">{}</div>", portability); } } @@ -3735,6 +3764,7 @@ fn render_impl( render_mode: RenderMode, is_default_item: bool, outer_version: Option<&str>, + outer_const_version: Option<&str>, trait_: Option<&clean::Trait>, show_def_docs: bool, cache: &Cache, @@ -3764,14 +3794,14 @@ fn render_impl( write!(w, "<code>"); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, "</code>"); - render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); - if let Some(l) = cx.src_href(item, cache) { - write!( - w, - "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", - l, "goto source code" - ); - } + render_stability_since_raw( + w, + item.stable_since().as_deref(), + item.const_stable_since().as_deref(), + outer_version, + outer_const_version, + ); + write_srclink(cx, item, w, cache); write!(w, "</h4>"); } } @@ -3786,14 +3816,14 @@ fn render_impl( write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class); assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), ""); write!(w, "</code>"); - render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); - if let Some(l) = cx.src_href(item, cache) { - write!( - w, - "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", - l, "goto source code" - ); - } + render_stability_since_raw( + w, + item.stable_since().as_deref(), + item.const_stable_since().as_deref(), + outer_version, + outer_const_version, + ); + write_srclink(cx, item, w, cache); write!(w, "</h4>"); } clean::AssocTypeItem(ref bounds, ref default) => { @@ -3814,26 +3844,32 @@ fn render_impl( if let Some(it) = t.items.iter().find(|i| i.name == item.name) { // We need the stability of the item from the trait // because impls can't have a stability. - document_stability(w, cx, it, is_hidden, Some(parent)); if item.doc_value().is_some() { + document_item_info(w, cx, it, is_hidden, Some(parent)); document_full(w, item, cx, "", is_hidden); - } else if show_def_docs { + } else { // In case the item isn't documented, // provide short documentation from the trait. - document_short(w, it, link, "", is_hidden); + document_short( + w, + it, + cx, + link, + "", + is_hidden, + Some(parent), + show_def_docs, + ); } } } else { - document_stability(w, cx, item, is_hidden, Some(parent)); + document_item_info(w, cx, item, is_hidden, Some(parent)); if show_def_docs { document_full(w, item, cx, "", is_hidden); } } } else { - document_stability(w, cx, item, is_hidden, Some(parent)); - if show_def_docs { - document_short(w, item, link, "", is_hidden); - } + document_short(w, item, cx, link, "", is_hidden, Some(parent), show_def_docs); } } } @@ -3849,6 +3885,7 @@ fn render_impl( render_mode, false, outer_version, + outer_const_version, trait_, show_def_docs, cache, @@ -3863,6 +3900,7 @@ fn render_impl( parent: &clean::Item, render_mode: RenderMode, outer_version: Option<&str>, + outer_const_version: Option<&str>, show_def_docs: bool, cache: &Cache, ) { @@ -3883,6 +3921,7 @@ fn render_impl( render_mode, true, outer_version, + outer_const_version, None, show_def_docs, cache, @@ -3904,6 +3943,7 @@ fn render_impl( &i.impl_item, render_mode, outer_version, + outer_const_version, show_def_docs, cache, ); | 
