From 18edcf86d2870de7975f1142f272b9a1236cdef4 Mon Sep 17 00:00:00 2001 From: Will Crichton Date: Mon, 13 Sep 2021 18:08:14 -0700 Subject: [PATCH] Reduce blur size, fix example width bug, add better error handling for I/O issues Remove repository url Fix formatting Fix file_span in print_src Formatting --- src/librustdoc/html/render/context.rs | 10 +-- src/librustdoc/html/render/mod.rs | 74 +++++++++++++++++----- src/librustdoc/html/static/css/rustdoc.css | 13 ++-- 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index fd53a3d7bfb..b99d2fe5aa0 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -124,7 +124,6 @@ crate struct SharedContext<'tcx> { crate span_correspondance_map: FxHashMap, /// The [`Cache`] used during rendering. crate cache: Cache, - pub(super) repository_url: Option, } impl SharedContext<'_> { @@ -141,11 +140,7 @@ impl SharedContext<'_> { /// Returns the `collapsed_doc_value` of the given item if this is the main crate, otherwise /// returns the `doc_value`. crate fn maybe_collapsed_doc_value<'a>(&self, item: &'a clean::Item) -> Option { - if self.collapsed { - item.collapsed_doc_value() - } else { - item.doc_value() - } + if self.collapsed { item.collapsed_doc_value() } else { item.doc_value() } } crate fn edition(&self) -> Edition { @@ -351,7 +346,6 @@ impl<'tcx> Context<'tcx> { let hiline = span.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), @@ -395,7 +389,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { generate_redirect_map, show_type_layout, generate_link_to_definition, - repository_url, .. } = options; @@ -487,7 +480,6 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { templates, span_correspondance_map: matches, cache, - repository_url, }; // Add the default themes to the `Vec` of stylepaths diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 24e50ef91ab..24eb4e88c3b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -40,6 +40,7 @@ use std::collections::VecDeque; use std::default::Default; use std::fmt; use std::fs; +use std::iter::Peekable; use std::path::PathBuf; use std::str; use std::string::ToString; @@ -53,7 +54,10 @@ use rustc_hir::def_id::DefId; use rustc_hir::Mutability; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_span::{ + symbol::{kw, sym, Symbol}, + BytePos, FileName, RealFileName, +}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; @@ -590,7 +594,7 @@ fn document_full_inner( match &*item.kind { clean::ItemKind::FunctionItem(f) | clean::ItemKind::MethodItem(f, _) => { - render_call_locations(w, cx, &f.call_locations); + render_call_locations(w, cx, &f.call_locations, item); } _ => {} } @@ -2458,6 +2462,7 @@ fn render_call_locations( w: &mut Buffer, cx: &Context<'_>, call_locations: &Option, + item: &clean::Item, ) { let call_locations = match call_locations.as_ref() { Some(call_locations) if call_locations.len() > 0 => call_locations, @@ -2488,11 +2493,17 @@ fn render_call_locations( }; // Generate the HTML for a single example, being the title and code block - let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| { - // FIXME(wcrichto): is there a better way to handle an I/O error than a panic? - // When would such an error arise? - let contents = - fs::read_to_string(&path).expect(&format!("Failed to read file: {}", path.display())); + let tcx = cx.tcx(); + let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool { + let contents = match fs::read_to_string(&path) { + Ok(contents) => contents, + Err(err) => { + let span = item.span(tcx).inner(); + tcx.sess + .span_err(span, &format!("failed to read file {}: {}", path.display(), err)); + return false; + } + }; // To reduce file sizes, we only want to embed the source code needed to understand the example, not // the entire file. So we find the smallest byte range that covers all items enclosing examples. @@ -2522,23 +2533,42 @@ fn render_call_locations( let edition = cx.shared.edition(); write!( w, - r#"
+ r#"
{title}
"#, title = example_url(call_data), - // The code and locations are encoded as data attributes, so they can be read + // The locations are encoded as a data attribute, so they can be read // later by the JS for interactions. - code = contents_subset.replace("\"", """), locations = serde_json::to_string(&line_ranges).unwrap(), ); write!(w, r#" "#); write!(w, r#""#); - // FIXME(wcrichto): where should file_span and root_path come from? - let file_span = rustc_span::DUMMY_SP; - let root_path = "".to_string(); + // Look for the example file in the source map if it exists, otherwise return a dummy span + let file_span = (|| { + let source_map = tcx.sess.source_map(); + let crate_src = tcx.sess.local_crate_source_file.as_ref()?; + let abs_crate_src = crate_src.canonicalize().ok()?; + let crate_root = abs_crate_src.parent()?.parent()?; + let rel_path = path.strip_prefix(crate_root).ok()?; + let files = source_map.files(); + let file = files.iter().find(|file| match &file.name { + FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path, + _ => false, + })?; + Some(rustc_span::Span::with_root_ctxt( + file.start_pos + BytePos(min_byte), + file.start_pos + BytePos(max_byte), + )) + })() + .unwrap_or(rustc_span::DUMMY_SP); + + // The root path is the inverse of Context::current + let root_path = vec!["../"; cx.current.len() - 1].join(""); + let mut decoration_info = FxHashMap::default(); decoration_info.insert("highlight", byte_ranges); + sources::print_src( w, contents_subset, @@ -2550,6 +2580,8 @@ fn render_call_locations( Some(decoration_info), ); write!(w, "
"); + + true }; // The call locations are output in sequence, so that sequence needs to be determined. @@ -2570,7 +2602,15 @@ fn render_call_locations( // Write just one example that's visible by default in the method's description. let mut it = ordered_locations.into_iter().peekable(); - write_example(w, it.next().unwrap()); + let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| { + while let Some(example) = it.next() { + if write_example(&mut *w, example) { + break; + } + } + }; + + write_and_skip_failure(w, &mut it); // Then add the remaining examples in a hidden section. if it.peek().is_some() { @@ -2582,13 +2622,15 @@ fn render_call_locations(
-
+
"# ); // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could // make the page arbitrarily huge! - (&mut it).take(MAX_FULL_EXAMPLES).for_each(|ex| write_example(w, ex)); + for _ in 0..MAX_FULL_EXAMPLES { + write_and_skip_failure(w, &mut it); + } // For the remaining examples, generate a
    containing links to the source files. if it.peek().is_some() { diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index ccb6bb79868..a9f7113c881 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2020,7 +2020,7 @@ details.undocumented[open] > summary::before { .scraped-example:not(.expanded) .code-wrapper:before { content: " "; width: 100%; - height: 20px; + height: 10px; position: absolute; z-index: 100; top: 0; @@ -2030,7 +2030,7 @@ details.undocumented[open] > summary::before { .scraped-example:not(.expanded) .code-wrapper:after { content: " "; width: 100%; - height: 20px; + height: 10px; position: absolute; z-index: 100; bottom: 0; @@ -2078,10 +2078,15 @@ details.undocumented[open] > summary::before { } .more-scraped-examples { - padding-left: 10px; - margin-left: 15px; + margin-left: 25px; display: flex; flex-direction: row; + width: calc(100% - 25px); +} + +.more-scraped-examples-inner { + /* 20px is width of toggle-line + toggle-line-inner */ + width: calc(100% - 20px); } .toggle-line {