Rollup merge of #85833 - willcrichton:example-analyzer, r=jyn514

Scrape code examples from examples/ directory for Rustdoc

Adds support for the functionality described in https://github.com/rust-lang/rfcs/pull/3123

Matching changes to Cargo are here: https://github.com/rust-lang/cargo/pull/9525

Live demo here: https://willcrichton.net/example-analyzer/warp/trait.Filter.html#method.and
This commit is contained in:
Matthias Krüger 2021-10-23 14:58:39 +02:00 committed by GitHub
commit dcf9242795
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1104 additions and 30 deletions

View file

@ -467,6 +467,11 @@ nav.sub {
overflow-x: auto;
}
.rustdoc:not(.source) .example-wrap > pre.line-numbers {
width: auto;
overflow-x: visible;
}
.rustdoc .example-wrap > pre {
margin: 0;
}
@ -1980,3 +1985,166 @@ details.undocumented[open] > summary::before {
overflow-wrap: anywhere;
}
}
/* Begin: styles for --scrape-examples feature */
.scraped-example-title {
font-family: 'Fira Sans';
}
.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
overflow: hidden;
max-height: 240px;
}
.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
overflow-y: hidden;
max-height: 240px;
padding-bottom: 0;
}
.scraped-example .code-wrapper .prev {
position: absolute;
top: 0.25em;
right: 2.25em;
z-index: 100;
cursor: pointer;
}
.scraped-example .code-wrapper .next {
position: absolute;
top: 0.25em;
right: 1.25em;
z-index: 100;
cursor: pointer;
}
.scraped-example .code-wrapper .expand {
position: absolute;
top: 0.25em;
right: 0.25em;
z-index: 100;
cursor: pointer;
}
.scraped-example .code-wrapper {
position: relative;
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.scraped-example:not(.expanded) .code-wrapper:before {
content: " ";
width: 100%;
height: 5px;
position: absolute;
z-index: 100;
top: 0;
background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}
.scraped-example:not(.expanded) .code-wrapper:after {
content: " ";
width: 100%;
height: 5px;
position: absolute;
z-index: 100;
bottom: 0;
background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}
.scraped-example:not(.expanded) .code-wrapper {
overflow: hidden;
max-height: 240px;
}
.scraped-example .code-wrapper .line-numbers {
margin: 0;
padding: 14px 0;
}
.scraped-example .code-wrapper .line-numbers span {
padding: 0 14px;
}
.scraped-example .code-wrapper .example-wrap {
flex: 1;
overflow-x: auto;
overflow-y: hidden;
margin-bottom: 0;
}
.scraped-example .code-wrapper .example-wrap pre.rust {
overflow-x: inherit;
width: inherit;
overflow-y: hidden;
}
.scraped-example .example-wrap .rust span.highlight {
background: #fcffd6;
}
.scraped-example .example-wrap .rust span.highlight.focus {
background: #f6fdb0;
}
.more-examples-toggle {
margin-top: 10px;
}
.more-examples-toggle summary {
color: #999;
font-family: 'Fira Sans';
}
.more-scraped-examples {
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 {
align-self: stretch;
margin-right: 10px;
margin-top: 5px;
padding: 0 4px;
cursor: pointer;
}
.toggle-line:hover .toggle-line-inner {
background: #aaa;
}
.toggle-line-inner {
min-width: 2px;
background: #ddd;
height: 100%;
}
.more-scraped-examples .scraped-example {
margin-bottom: 20px;
}
.more-scraped-examples .scraped-example:last-child {
margin-bottom: 0;
}
.example-links a {
margin-top: 20px;
font-family: 'Fira Sans';
}
.example-links ul {
margin-bottom: 0;
}
/* End: styles for --scrape-examples feature */

View file

@ -613,3 +613,22 @@ div.files > .selected {
input:checked + .slider {
background-color: #ffb454 !important;
}
.scraped-example .example-wrap .rust span.highlight {
background: rgb(91, 59, 1);
}
.scraped-example .example-wrap .rust span.highlight.focus {
background: rgb(124, 75, 15);
}
.scraped-example:not(.expanded) .code-wrapper:before {
background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
}
.scraped-example:not(.expanded) .code-wrapper:after {
background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
}
.toggle-line-inner {
background: #616161;
}
.toggle-line:hover .toggle-line-inner {
background: ##898989;
}

View file

@ -485,3 +485,22 @@ div.files > .selected {
.setting-line > .title {
border-bottom-color: #ddd;
}
.scraped-example .example-wrap .rust span.highlight {
background: rgb(91, 59, 1);
}
.scraped-example .example-wrap .rust span.highlight.focus {
background: rgb(124, 75, 15);
}
.scraped-example:not(.expanded) .code-wrapper:before {
background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
}
.scraped-example:not(.expanded) .code-wrapper:after {
background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
}
.toggle-line-inner {
background: #616161;
}
.toggle-line:hover .toggle-line-inner {
background: ##898989;
}

View file

@ -0,0 +1,86 @@
/* global addClass, hasClass, removeClass, onEach */
(function () {
// Scroll code block to put the given code location in the middle of the viewer
function scrollToLoc(elt, loc) {
var wrapper = elt.querySelector(".code-wrapper");
var halfHeight = wrapper.offsetHeight / 2;
var lines = elt.querySelector('.line-numbers');
var offsetMid = (lines.children[loc[0]].offsetTop
+ lines.children[loc[1]].offsetTop) / 2;
var scrollOffset = offsetMid - halfHeight;
lines.scrollTo(0, scrollOffset);
elt.querySelector(".rust").scrollTo(0, scrollOffset);
}
function updateScrapedExample(example) {
var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
var locIndex = 0;
var highlights = example.querySelectorAll('.highlight');
var link = example.querySelector('.scraped-example-title a');
if (locs.length > 1) {
// Toggle through list of examples in a given file
var onChangeLoc = function(changeIndex) {
removeClass(highlights[locIndex], 'focus');
changeIndex();
scrollToLoc(example, locs[locIndex][0]);
addClass(highlights[locIndex], 'focus');
var url = locs[locIndex][1];
var title = locs[locIndex][2];
link.href = url;
link.innerHTML = title;
};
example.querySelector('.prev')
.addEventListener('click', function() {
onChangeLoc(function() {
locIndex = (locIndex - 1 + locs.length) % locs.length;
});
});
example.querySelector('.next')
.addEventListener('click', function() {
onChangeLoc(function() {
locIndex = (locIndex + 1) % locs.length;
});
});
}
var expandButton = example.querySelector('.expand');
if (expandButton) {
expandButton.addEventListener('click', function () {
if (hasClass(example, "expanded")) {
removeClass(example, "expanded");
scrollToLoc(example, locs[0][0]);
} else {
addClass(example, "expanded");
}
});
}
// Start with the first example in view
scrollToLoc(example, locs[0][0]);
}
var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
onEach(firstExamples, updateScrapedExample);
onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
// Allow users to click the left border of the <details> section to close it,
// since the section can be large and finding the [+] button is annoying.
toggle.querySelector('.toggle-line').addEventListener('click', function() {
toggle.open = false;
});
var moreExamples = toggle.querySelectorAll('.scraped-example');
toggle.querySelector('summary').addEventListener('click', function() {
// Wrapping in setTimeout ensures the update happens after the elements are actually
// visible. This is necessary since updateScrapedExample calls scrollToLoc which
// depends on offsetHeight, a property that requires an element to be visible to
// compute correctly.
setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
}, {once: true});
});
})();