diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 8ef5fabb9017..bef99087a19d 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -691,7 +691,7 @@ fn string( // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 match href { LinkFromSrc::Local(span) => context - .href_from_span(*span) + .href_from_span(*span, true) .map(|s| format!("{}{}", context_info.root_path, s)), LinkFromSrc::External(def_id) => { format::href_with_root_path(*def_id, context, Some(context_info.root_path)) diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 364be8ae7565..323bae3c9c4b 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -295,10 +295,10 @@ impl<'tcx> Context<'tcx> { /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. pub(super) fn src_href(&self, item: &clean::Item) -> Option { - self.href_from_span(item.span(self.tcx())) + self.href_from_span(item.span(self.tcx()), true) } - crate fn href_from_span(&self, span: clean::Span) -> Option { + crate fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option { if span.is_dummy() { return None; } @@ -345,16 +345,26 @@ impl<'tcx> Context<'tcx> { (&*symbol, &path) }; - let loline = span.lo(self.sess()).line; - let hiline = span.hi(self.sess()).line; - let lines = - if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) }; + let anchor = if with_lines { + let loline = span.lo(self.sess()).line; + let hiline = span.hi(self.sess()).line; + format!( + "#{}", + if loline == hiline { + loline.to_string() + } else { + format!("{}-{}", loline, hiline) + } + ) + } else { + "".to_string() + }; Some(format!( - "{root}src/{krate}/{path}#{lines}", + "{root}src/{krate}/{path}{anchor}", root = Escape(&root), krate = krate, path = path, - lines = lines + anchor = anchor )) } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 5e4b068cf153..3a4c68917081 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2475,12 +2475,11 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, def_id: DefId, item: }; // Generate a unique ID so users can link to this section for a given method - // FIXME: this should use init_id_map instead of derive let id = cx.id_map.borrow_mut().derive("scraped-examples"); write!( w, "
\ - + \
\ Examples found in repository\
", @@ -2516,42 +2515,51 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, def_id: DefId, item: // The call locations need to be updated to reflect that the size of the program has changed. // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point. - let (byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data + let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data .locations .iter() .map(|loc| { let (byte_lo, byte_hi) = loc.call_expr.byte_span; let (line_lo, line_hi) = loc.call_expr.line_span; - ((byte_lo - byte_min, byte_hi - byte_min), (line_lo - line_min, line_hi - line_min)) + let byte_range = (byte_lo - byte_min, byte_hi - byte_min); + let line_range = (line_lo - line_min, line_hi - line_min); + let (anchor, line_title) = if line_lo == line_hi { + (format!("{}", line_lo + 1), format!("line {}", line_lo + 1)) + } else { + ( + format!("{}-{}", line_lo + 1, line_hi + 1), + format!("lines {}-{}", line_lo + 1, line_hi + 1), + ) + }; + let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor); + + (byte_range, (line_range, line_url, line_title)) }) .unzip(); - let (init_min, init_max) = line_ranges[0]; - let line_range = if init_min == init_max { - format!("line {}", init_min + line_min + 1) - } else { - format!("lines {}-{}", init_min + line_min + 1, init_max + line_min + 1) - }; - + let (_, init_url, init_title) = &line_ranges[0]; let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES; + let locations_encoded = serde_json::to_string(&line_ranges).unwrap(); write!( w, "
\
\ - {name} ({line_range})\ + {name} ({title})\
\
", - root = cx.root_path(), - url = call_data.url, - name = call_data.display_name, - line_range = line_range, expanded_cls = if needs_expansion { "" } else { "expanded" }, + name = call_data.display_name, + url = init_url, + title = init_title, // The locations are encoded as a data attribute, so they can be read // later by the JS for interactions. - locations = serde_json::to_string(&line_ranges).unwrap(), + locations = Escape(&locations_encoded) ); - write!(w, r#" "#); + + if line_ranges.len() > 1 { + write!(w, r#" "#); + } if needs_expansion { write!(w, r#""#); @@ -2580,6 +2588,7 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, def_id: DefId, item: let root_path = vec!["../"; cx.current.len() - 1].join(""); let mut decoration_info = FxHashMap::default(); + decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]); decoration_info.insert("highlight", byte_ranges); sources::print_src( diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 820f6a00f208..49bdb2455ac9 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1986,6 +1986,7 @@ details.undocumented[open] > summary::before { .scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust { overflow-y: hidden; max-height: 240px; + padding-bottom: 0; } .scraped-example .code-wrapper .prev { diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js index 307843f24261..664b187e33e9 100644 --- a/src/librustdoc/html/static/js/scrape-examples.js +++ b/src/librustdoc/html/static/js/scrape-examples.js @@ -15,41 +15,23 @@ function updateScrapedExample(example) { var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent); - var first_line_no = example.querySelector('.line-numbers > span:first-child'); - var offset = parseInt(first_line_no.innerHTML) - 1; - var locIndex = 0; var highlights = example.querySelectorAll('.highlight'); var link = example.querySelector('.scraped-example-title a'); - addClass(highlights[0], 'focus'); + if (locs.length > 1) { // Toggle through list of examples in a given file - var onChangeLoc = function(f) { + var onChangeLoc = function(changeIndex) { removeClass(highlights[locIndex], 'focus'); - f(); - scrollToLoc(example, locs[locIndex]); + changeIndex(); + scrollToLoc(example, locs[locIndex][0]); addClass(highlights[locIndex], 'focus'); - var curLoc = locs[locIndex]; - var minLine = curLoc[0] + offset + 1; - var maxLine = curLoc[1] + offset + 1; + var url = locs[locIndex][1]; + var title = locs[locIndex][2]; - var text; - var anchor; - if (minLine == maxLine) { - text = 'line ' + minLine.toString(); - anchor = minLine.toString(); - } else { - var range = minLine.toString() + '-' + maxLine.toString(); - text = 'lines ' + range; - anchor = range; - } - - var url = new URL(link.href); - url.hash = anchor; - - link.href = url.toString(); - link.innerHTML = text; + link.href = url; + link.innerHTML = title; }; example.querySelector('.prev') @@ -61,12 +43,10 @@ example.querySelector('.next') .addEventListener('click', function() { - onChangeLoc(function() { locIndex = (locIndex + 1) % locs.length; }); + onChangeLoc(function() { + locIndex = (locIndex + 1) % locs.length; + }); }); - } else { - // Remove buttons if there's only one example in the file - example.querySelector('.prev').remove(); - example.querySelector('.next').remove(); } var expandButton = example.querySelector('.expand'); @@ -74,7 +54,7 @@ expandButton.addEventListener('click', function () { if (hasClass(example, "expanded")) { removeClass(example, "expanded"); - scrollToLoc(example, locs[0]); + scrollToLoc(example, locs[0][0]); } else { addClass(example, "expanded"); } @@ -82,7 +62,7 @@ } // Start with the first example in view - scrollToLoc(example, locs[0]); + scrollToLoc(example, locs[0][0]); } var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example'); diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 3a8e5337f5bb..c75a42446200 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -171,7 +171,7 @@ where let cx = &self.cx; let mk_call_data = || { let clean_span = crate::clean::types::Span::new(span); - let url = cx.href_from_span(clean_span).unwrap(); + let url = cx.href_from_span(clean_span, false).unwrap(); let display_name = file_path.display().to_string(); let edition = span.edition(); CallData { locations: Vec::new(), url, display_name, edition } @@ -233,6 +233,7 @@ crate fn run( Ok(()) } +// Note: the Handler must be passed in explicitly because sess isn't available while parsing options crate fn load_call_locations( with_examples: Vec, diag: &rustc_errors::Handler, diff --git a/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs index b021f27da56d..f525a4270dde 100644 --- a/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs +++ b/src/test/run-make/rustdoc-scrape-examples-remap/src/lib.rs @@ -1,5 +1,5 @@ -// @has foobar/b/fn.foo.html '//*[@class="scraped-example"]' 'ex.rs' -// @has foobar/c/fn.foo.html '//*[@class="scraped-example"]' 'ex.rs' +// @has foobar/b/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs' +// @has foobar/c/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs' #[path = "a.rs"] pub mod b;