Auto merge of #123372 - GuillaumeGomez:rollup-nwxdzev, r=GuillaumeGomez

Rollup of 4 pull requests

Successful merges:

 - #122614 (rustdoc-search: shard the search result descriptions)
 - #123338 (Update to new browser-ui-test version)
 - #123366 (Minor by_move_body impl cleanups)
 - #123371 (Remove dangling `.mir.stderr` and `.thir.stderr` test files)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-04-02 17:08:11 +00:00
commit 029cb1b13b
80 changed files with 1103 additions and 807 deletions

View File

@ -4783,6 +4783,8 @@ version = "0.0.0"
dependencies = [
"arrayvec",
"askama",
"base64",
"byteorder",
"expect-test",
"indexmap",
"itertools 0.12.1",

View File

@ -3,7 +3,7 @@
//! be a coroutine body that takes all of its upvars by-move, and which we stash
//! into the `CoroutineInfo` for all coroutines returned by coroutine-closures.
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::unord::UnordSet;
use rustc_hir as hir;
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::{self, dump_mir, MirPass};
@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
return;
}
let mut by_ref_fields = FxIndexSet::default();
let mut by_ref_fields = UnordSet::default();
let by_move_upvars = Ty::new_tup_from_iter(
tcx,
tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| {
@ -73,7 +73,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
struct MakeByMoveBody<'tcx> {
tcx: TyCtxt<'tcx>,
by_ref_fields: FxIndexSet<FieldIdx>,
by_ref_fields: UnordSet<FieldIdx>,
by_move_coroutine_ty: Ty<'tcx>,
}
@ -89,11 +89,11 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
location: mir::Location,
) {
if place.local == ty::CAPTURE_STRUCT_LOCAL
&& !place.projection.is_empty()
&& let mir::ProjectionElem::Field(idx, ty) = place.projection[0]
&& let Some((&mir::ProjectionElem::Field(idx, ty), projection)) =
place.projection.split_first()
&& self.by_ref_fields.contains(&idx)
{
let (begin, end) = place.projection[1..].split_first().unwrap();
let (begin, end) = projection.split_first().unwrap();
// FIXME(async_closures): I'm actually a bit surprised to see that we always
// initially deref the by-ref upvars. If this is not actually true, then we
// will at least get an ICE that explains why this isn't true :^)

View File

@ -60,7 +60,7 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
/scripts/validate-error-codes.sh && \
reuse --include-submodules lint && \
# Runs checks to ensure that there are no ES5 issues in our JS code.
es-check es6 ../src/librustdoc/html/static/js/*.js && \
es-check es8 ../src/librustdoc/html/static/js/*.js && \
eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js && \
eslint -c ../src/tools/rustdoc-js/.eslintrc.js ../src/tools/rustdoc-js/tester.js && \
eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js

View File

@ -9,6 +9,8 @@ path = "lib.rs"
[dependencies]
arrayvec = { version = "0.7", default-features = false }
askama = { version = "0.12", default-features = false, features = ["config"] }
base64 = "0.21.7"
byteorder = "1.5"
itertools = "0.12"
indexmap = "2"
minifier = "0.3.0"

View File

@ -184,40 +184,15 @@ pub(crate) enum RenderTypeId {
impl RenderTypeId {
pub fn write_to_string(&self, string: &mut String) {
// (sign, value)
let (sign, id): (bool, u32) = match &self {
let id: i32 = match &self {
// 0 is a sentinel, everything else is one-indexed
// concrete type
RenderTypeId::Index(idx) if *idx >= 0 => (false, (idx + 1isize).try_into().unwrap()),
RenderTypeId::Index(idx) if *idx >= 0 => (idx + 1isize).try_into().unwrap(),
// generic type parameter
RenderTypeId::Index(idx) => (true, (-*idx).try_into().unwrap()),
RenderTypeId::Index(idx) => (*idx).try_into().unwrap(),
_ => panic!("must convert render types to indexes before serializing"),
};
// zig-zag encoding
let value: u32 = (id << 1) | (if sign { 1 } else { 0 });
// Self-terminating hex use capital letters for everything but the
// least significant digit, which is lowercase. For example, decimal 17
// would be `` Aa `` if zig-zag encoding weren't used.
//
// Zig-zag encoding, however, stores the sign bit as the last bit.
// This means, in the last hexit, 1 is actually `c`, -1 is `b`
// (`a` is the imaginary -0), and, because all the bits are shifted
// by one, `` A` `` is actually 8 and `` Aa `` is -8.
//
// https://rust-lang.github.io/rustc-dev-guide/rustdoc-internals/search.html
// describes the encoding in more detail.
let mut shift: u32 = 28;
let mut mask: u32 = 0xF0_00_00_00;
while shift < 32 {
let hexit = (value & mask) >> shift;
if hexit != 0 || shift == 0 {
let hex =
char::try_from(if shift == 0 { '`' } else { '@' } as u32 + hexit).unwrap();
string.push(hex);
}
shift = shift.wrapping_sub(4);
mask = mask >> 4;
}
search_index::encode::write_vlqhex_to_string(id, string);
}
}

View File

@ -1,3 +1,5 @@
pub(crate) mod encode;
use std::collections::hash_map::Entry;
use std::collections::{BTreeMap, VecDeque};
@ -17,12 +19,46 @@ use crate::html::format::join_with_double_colon;
use crate::html::markdown::short_markdown_summary;
use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
use encode::{bitmap_to_string, write_vlqhex_to_string};
/// The serialized search description sharded version
///
/// The `index` is a JSON-encoded list of names and other information.
///
/// The desc has newlined descriptions, split up by size into 128KiB shards.
/// For example, `(4, "foo\nbar\nbaz\nquux")`.
///
/// There is no single, optimal size for these shards, because it depends on
/// configuration values that we can't predict or control, such as the version
/// of HTTP used (HTTP/1.1 would work better with larger files, while HTTP/2
/// and 3 are more agnostic), transport compression (gzip, zstd, etc), whether
/// the search query is going to produce a large number of results or a small
/// number, the bandwidth delay product of the network...
///
/// Gzipping some standard library descriptions to guess what transport
/// compression will do, the compressed file sizes can be as small as 4.9KiB
/// or as large as 18KiB (ignoring the final 1.9KiB shard of leftovers).
/// A "reasonable" range for files is for them to be bigger than 1KiB,
/// since that's about the amount of data that can be transferred in a
/// single TCP packet, and 64KiB, the maximum amount of data that
/// TCP can transfer in a single round trip without extensions.
///
/// [1]: https://en.wikipedia.org/wiki/Maximum_transmission_unit#MTUs_for_common_media
/// [2]: https://en.wikipedia.org/wiki/Sliding_window_protocol#Basic_concept
/// [3]: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features
pub(crate) struct SerializedSearchIndex {
pub(crate) index: String,
pub(crate) desc: Vec<(usize, String)>,
}
const DESC_INDEX_SHARD_LEN: usize = 128 * 1024;
/// Builds the search index from the collected metadata
pub(crate) fn build_index<'tcx>(
krate: &clean::Crate,
cache: &mut Cache,
tcx: TyCtxt<'tcx>,
) -> String {
) -> SerializedSearchIndex {
let mut itemid_to_pathid = FxHashMap::default();
let mut primitives = FxHashMap::default();
let mut associated_types = FxHashMap::default();
@ -319,7 +355,6 @@ pub(crate) fn build_index<'tcx>(
.collect::<Vec<_>>();
struct CrateData<'a> {
doc: String,
items: Vec<&'a IndexItem>,
paths: Vec<(ItemType, Vec<Symbol>)>,
// The String is alias name and the vec is the list of the elements with this alias.
@ -328,6 +363,11 @@ pub(crate) fn build_index<'tcx>(
aliases: &'a BTreeMap<String, Vec<usize>>,
// Used when a type has more than one impl with an associated item with the same name.
associated_item_disambiguators: &'a Vec<(usize, String)>,
// A list of shard lengths encoded as vlqhex. See the comment in write_vlqhex_to_string
// for information on the format.
desc_index: String,
// A list of items with no description. This is eventually turned into a bitmap.
empty_desc: Vec<u32>,
}
struct Paths {
@ -409,7 +449,6 @@ pub(crate) fn build_index<'tcx>(
let mut names = Vec::with_capacity(self.items.len());
let mut types = String::with_capacity(self.items.len());
let mut full_paths = Vec::with_capacity(self.items.len());
let mut descriptions = Vec::with_capacity(self.items.len());
let mut parents = Vec::with_capacity(self.items.len());
let mut functions = String::with_capacity(self.items.len());
let mut deprecated = Vec::with_capacity(self.items.len());
@ -432,7 +471,6 @@ pub(crate) fn build_index<'tcx>(
parents.push(item.parent_idx.map(|x| x + 1).unwrap_or(0));
names.push(item.name.as_str());
descriptions.push(&item.desc);
if !item.path.is_empty() {
full_paths.push((index, &item.path));
@ -444,7 +482,8 @@ pub(crate) fn build_index<'tcx>(
}
if item.deprecation.is_some() {
deprecated.push(index);
// bitmasks always use 1-indexing for items, with 0 as the crate itself
deprecated.push(u32::try_from(index + 1).unwrap());
}
}
@ -455,17 +494,16 @@ pub(crate) fn build_index<'tcx>(
let has_aliases = !self.aliases.is_empty();
let mut crate_data =
serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
crate_data.serialize_field("doc", &self.doc)?;
crate_data.serialize_field("t", &types)?;
crate_data.serialize_field("n", &names)?;
// Serialize as an array of item indices and full paths
crate_data.serialize_field("q", &full_paths)?;
crate_data.serialize_field("d", &descriptions)?;
crate_data.serialize_field("i", &parents)?;
crate_data.serialize_field("f", &functions)?;
crate_data.serialize_field("c", &deprecated)?;
crate_data.serialize_field("D", &self.desc_index)?;
crate_data.serialize_field("p", &paths)?;
crate_data.serialize_field("b", &self.associated_item_disambiguators)?;
crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?;
crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?;
if has_aliases {
crate_data.serialize_field("a", &self.aliases)?;
}
@ -473,16 +511,58 @@ pub(crate) fn build_index<'tcx>(
}
}
// Collect the index into a string
format!(
let (empty_desc, desc) = {
let mut empty_desc = Vec::new();
let mut result = Vec::new();
let mut set = String::new();
let mut len: usize = 0;
let mut item_index: u32 = 0;
for desc in std::iter::once(&crate_doc).chain(crate_items.iter().map(|item| &item.desc)) {
if desc == "" {
empty_desc.push(item_index);
item_index += 1;
continue;
}
if set.len() >= DESC_INDEX_SHARD_LEN {
result.push((len, std::mem::replace(&mut set, String::new())));
len = 0;
} else if len != 0 {
set.push('\n');
}
set.push_str(&desc);
len += 1;
item_index += 1;
}
result.push((len, std::mem::replace(&mut set, String::new())));
(empty_desc, result)
};
let desc_index = {
let mut desc_index = String::with_capacity(desc.len() * 4);
for &(len, _) in desc.iter() {
write_vlqhex_to_string(len.try_into().unwrap(), &mut desc_index);
}
desc_index
};
assert_eq!(
crate_items.len() + 1,
desc.iter().map(|(len, _)| *len).sum::<usize>() + empty_desc.len()
);
// The index, which is actually used to search, is JSON
// It uses `JSON.parse(..)` to actually load, since JSON
// parses faster than the full JavaScript syntax.
let index = format!(
r#"["{}",{}]"#,
krate.name(tcx),
serde_json::to_string(&CrateData {
doc: crate_doc,
items: crate_items,
paths: crate_paths,
aliases: &aliases,
associated_item_disambiguators: &associated_item_disambiguators,
desc_index,
empty_desc,
})
.expect("failed serde conversion")
// All these `replace` calls are because we have to go through JS string for JSON content.
@ -490,7 +570,8 @@ pub(crate) fn build_index<'tcx>(
.replace('\'', r"\'")
// We need to escape double quotes for the JSON.
.replace("\\\"", "\\\\\"")
)
);
SerializedSearchIndex { index, desc }
}
pub(crate) fn get_function_type_for_search<'tcx>(

View File

@ -0,0 +1,243 @@
use base64::prelude::*;
pub(crate) fn write_vlqhex_to_string(n: i32, string: &mut String) {
let (sign, magnitude): (bool, u32) =
if n >= 0 { (false, n.try_into().unwrap()) } else { (true, (-n).try_into().unwrap()) };
// zig-zag encoding
let value: u32 = (magnitude << 1) | (if sign { 1 } else { 0 });
// Self-terminating hex use capital letters for everything but the
// least significant digit, which is lowercase. For example, decimal 17
// would be `` Aa `` if zig-zag encoding weren't used.
//
// Zig-zag encoding, however, stores the sign bit as the last bit.
// This means, in the last hexit, 1 is actually `c`, -1 is `b`
// (`a` is the imaginary -0), and, because all the bits are shifted
// by one, `` A` `` is actually 8 and `` Aa `` is -8.
//
// https://rust-lang.github.io/rustc-dev-guide/rustdoc-internals/search.html
// describes the encoding in more detail.
let mut shift: u32 = 28;
let mut mask: u32 = 0xF0_00_00_00;
// first skip leading zeroes
while shift < 32 {
let hexit = (value & mask) >> shift;
if hexit != 0 || shift == 0 {
break;
}
shift = shift.wrapping_sub(4);
mask = mask >> 4;
}
// now write the rest
while shift < 32 {
let hexit = (value & mask) >> shift;
let hex = char::try_from(if shift == 0 { '`' } else { '@' } as u32 + hexit).unwrap();
string.push(hex);
shift = shift.wrapping_sub(4);
mask = mask >> 4;
}
}
// Used during bitmap encoding
enum Container {
/// number of ones, bits
Bits(Box<[u64; 1024]>),
/// list of entries
Array(Vec<u16>),
/// list of (start, len-1)
Run(Vec<(u16, u16)>),
}
impl Container {
fn popcount(&self) -> u32 {
match self {
Container::Bits(bits) => bits.iter().copied().map(|x| x.count_ones()).sum(),
Container::Array(array) => {
array.len().try_into().expect("array can't be bigger than 2**32")
}
Container::Run(runs) => {
runs.iter().copied().map(|(_, lenm1)| u32::from(lenm1) + 1).sum()
}
}
}
fn push(&mut self, value: u16) {
match self {
Container::Bits(bits) => bits[value as usize >> 6] |= 1 << (value & 0x3F),
Container::Array(array) => {
array.push(value);
if array.len() >= 4096 {
let array = std::mem::replace(array, Vec::new());
*self = Container::Bits(Box::new([0; 1024]));
for value in array {
self.push(value);
}
}
}
Container::Run(runs) => {
if let Some(r) = runs.last_mut()
&& r.0 + r.1 + 1 == value
{
r.1 += 1;
} else {
runs.push((value, 0));
}
}
}
}
fn try_make_run(&mut self) -> bool {
match self {
Container::Bits(bits) => {
let mut r: u64 = 0;
for (i, chunk) in bits.iter().copied().enumerate() {
let next_chunk =
i.checked_add(1).and_then(|i| bits.get(i)).copied().unwrap_or(0);
r += !chunk & u64::from((chunk << 1).count_ones());
r += !next_chunk & u64::from((chunk >> 63).count_ones());
}
if (2 + 4 * r) >= 8192 {
return false;
}
let bits = std::mem::replace(bits, Box::new([0; 1024]));
*self = Container::Run(Vec::new());
for (i, bits) in bits.iter().copied().enumerate() {
if bits == 0 {
continue;
}
for j in 0..64 {
let value = (u16::try_from(i).unwrap() << 6) | j;
if bits & (1 << j) != 0 {
self.push(value);
}
}
}
true
}
Container::Array(array) if array.len() <= 5 => false,
Container::Array(array) => {
let mut r = 0;
let mut prev = None;
for value in array.iter().copied() {
if value.checked_sub(1) != prev {
r += 1;
}
prev = Some(value);
}
if 2 + 4 * r >= 2 * array.len() + 2 {
return false;
}
let array = std::mem::replace(array, Vec::new());
*self = Container::Run(Vec::new());
for value in array {
self.push(value);
}
true
}
Container::Run(_) => true,
}
}
}
// checked against roaring-rs in
// https://gitlab.com/notriddle/roaring-test
pub(crate) fn write_bitmap_to_bytes(
domain: &[u32],
mut out: impl std::io::Write,
) -> std::io::Result<()> {
// https://arxiv.org/pdf/1603.06549.pdf
let mut keys = Vec::<u16>::new();
let mut containers = Vec::<Container>::new();
let mut key: u16;
let mut domain_iter = domain.into_iter().copied().peekable();
let mut has_run = false;
while let Some(entry) = domain_iter.next() {
key = (entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
let value: u16 = (entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit");
let mut container = Container::Array(vec![value]);
while let Some(entry) = domain_iter.peek().copied() {
let entry_key: u16 =
(entry >> 16).try_into().expect("shifted off the top 16 bits, so it should fit");
if entry_key != key {
break;
}
domain_iter.next().expect("peeking just succeeded");
container
.push((entry & 0x00_00_FF_FF).try_into().expect("AND 16 bits, so it should fit"));
}
keys.push(key);
has_run = container.try_make_run() || has_run;
containers.push(container);
}
// https://github.com/RoaringBitmap/RoaringFormatSpec
use byteorder::{WriteBytesExt, LE};
const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346;
const SERIAL_COOKIE: u32 = 12347;
const NO_OFFSET_THRESHOLD: u32 = 4;
let size: u32 = containers.len().try_into().unwrap();
let start_offset = if has_run {
out.write_u32::<LE>(SERIAL_COOKIE | ((size - 1) << 16))?;
for set in containers.chunks(8) {
let mut b = 0;
for (i, container) in set.iter().enumerate() {
if matches!(container, &Container::Run(..)) {
b |= 1 << i;
}
}
out.write_u8(b)?;
}
if size < NO_OFFSET_THRESHOLD {
4 + 4 * size + ((size + 7) / 8)
} else {
4 + 8 * size + ((size + 7) / 8)
}
} else {
out.write_u32::<LE>(SERIAL_COOKIE_NO_RUNCONTAINER)?;
out.write_u32::<LE>(containers.len().try_into().unwrap())?;
4 + 4 + 4 * size + 4 * size
};
for (&key, container) in keys.iter().zip(&containers) {
// descriptive header
let key: u32 = key.into();
let count: u32 = container.popcount() - 1;
out.write_u32::<LE>((count << 16) | key)?;
}
if !has_run || size >= NO_OFFSET_THRESHOLD {
// offset header
let mut starting_offset = start_offset;
for container in &containers {
out.write_u32::<LE>(starting_offset)?;
starting_offset += match container {
Container::Bits(_) => 8192u32,
Container::Array(array) => u32::try_from(array.len()).unwrap() * 2,
Container::Run(runs) => 2 + u32::try_from(runs.len()).unwrap() * 4,
};
}
}
for container in &containers {
match container {
Container::Bits(bits) => {
for chunk in bits.iter() {
out.write_u64::<LE>(*chunk)?;
}
}
Container::Array(array) => {
for value in array.iter() {
out.write_u16::<LE>(*value)?;
}
}
Container::Run(runs) => {
out.write_u16::<LE>((runs.len()).try_into().unwrap())?;
for (start, lenm1) in runs.iter().copied() {
out.write_u16::<LE>(start)?;
out.write_u16::<LE>(lenm1)?;
}
}
}
}
Ok(())
}
pub(crate) fn bitmap_to_string(domain: &[u32]) -> String {
let mut buf = Vec::new();
let mut strbuf = String::new();
write_bitmap_to_bytes(&domain, &mut buf).unwrap();
BASE64_STANDARD.encode_string(&buf, &mut strbuf);
strbuf
}

View File

@ -24,6 +24,7 @@ use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
use crate::formats::Impl;
use crate::html::format::Buffer;
use crate::html::render::search_index::SerializedSearchIndex;
use crate::html::render::{AssocItemLink, ImplRenderingParameters};
use crate::html::{layout, static_files};
use crate::visit::DocVisitor;
@ -46,7 +47,7 @@ use crate::{try_err, try_none};
pub(super) fn write_shared(
cx: &mut Context<'_>,
krate: &Crate,
search_index: String,
search_index: SerializedSearchIndex,
options: &RenderOptions,
) -> Result<(), Error> {
// Write out the shared files. Note that these are shared among all rustdoc
@ -312,7 +313,7 @@ pub(super) fn write_shared(
let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
let (mut all_indexes, mut krates) =
try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst);
all_indexes.push(search_index);
all_indexes.push(search_index.index);
krates.push(krate.name(cx.tcx()).to_string());
krates.sort();
@ -335,6 +336,32 @@ else if (window.initSearch) window.initSearch(searchIndex);
Ok(v.into_bytes())
})?;
let search_desc_dir = cx.dst.join(format!("search.desc/{krate}", krate = krate.name(cx.tcx())));
if Path::new(&search_desc_dir).exists() {
try_err!(std::fs::remove_dir_all(&search_desc_dir), &search_desc_dir);
}
try_err!(std::fs::create_dir_all(&search_desc_dir), &search_desc_dir);
let kratename = krate.name(cx.tcx()).to_string();
for (i, (_, data)) in search_index.desc.into_iter().enumerate() {
let output_filename = static_files::suffix_path(
&format!("{kratename}-desc-{i}-.js"),
&cx.shared.resource_suffix,
);
let path = search_desc_dir.join(output_filename);
try_err!(
std::fs::write(
&path,
&format!(
r##"searchState.loadedDescShard({kratename}, {i}, {data})"##,
kratename = serde_json::to_string(&kratename).unwrap(),
data = serde_json::to_string(&data).unwrap(),
)
.into_bytes()
),
&path
);
}
write_invocation_specific("crates.js", &|| {
let krates = krates.iter().map(|k| format!("\"{k}\"")).join(",");
Ok(format!("window.ALL_CRATES = [{krates}];").into_bytes())

View File

@ -5,7 +5,7 @@ module.exports = {
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2015,
"ecmaVersion": 8,
"sourceType": "module"
},
"rules": {

View File

@ -329,6 +329,30 @@ function preLoadCss(cssUrl) {
search.innerHTML = "<h3 class=\"search-loading\">" + searchState.loadingText + "</h3>";
searchState.showResults(search);
},
descShards: new Map(),
loadDesc: async function({descShard, descIndex}) {
if (descShard.promise === null) {
descShard.promise = new Promise((resolve, reject) => {
// The `resolve` callback is stored in the `descShard`
// object, which is itself stored in `this.descShards` map.
// It is called in `loadedDescShard` by the
// search.desc script.
descShard.resolve = resolve;
const ds = descShard;
const fname = `${ds.crate}-desc-${ds.shard}-`;
const url = resourcePath(
`search.desc/${descShard.crate}/${fname}`,
".js",
);
loadScript(url, reject);
});
}
const list = await descShard.promise;
return list[descIndex];
},
loadedDescShard: function(crate, shard, data) {
this.descShards.get(crate)[shard].resolve(data.split("\n"));
},
};
const toggleAllDocsId = "toggle-all-docs";
@ -381,7 +405,7 @@ function preLoadCss(cssUrl) {
window.location.replace("#" + item.id);
}, 0);
}
}
},
);
}
}
@ -585,7 +609,7 @@ function preLoadCss(cssUrl) {
const script = document
.querySelector("script[data-ignore-extern-crates]");
const ignoreExternCrates = new Set(
(script ? script.getAttribute("data-ignore-extern-crates") : "").split(",")
(script ? script.getAttribute("data-ignore-extern-crates") : "").split(","),
);
for (const lib of libs) {
if (lib === window.currentCrate || ignoreExternCrates.has(lib)) {
@ -1098,7 +1122,7 @@ function preLoadCss(cssUrl) {
} else {
wrapper.style.setProperty(
"--popover-arrow-offset",
(wrapperPos.right - pos.right + 4) + "px"
(wrapperPos.right - pos.right + 4) + "px",
);
}
wrapper.style.visibility = "";
@ -1680,7 +1704,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
pendingSidebarResizingFrame = false;
document.documentElement.style.setProperty(
"--resizing-sidebar-width",
desiredSidebarSize + "px"
desiredSidebarSize + "px",
);
}, 100);
}

View File

@ -206,14 +206,14 @@ const editDistanceState = {
// insertion
this.current[j - 1] + 1,
// substitution
this.prev[j - 1] + substitutionCost
this.prev[j - 1] + substitutionCost,
);
if ((i > 1) && (j > 1) && (a[aIdx] === b[bIdx - 1]) && (a[aIdx - 1] === b[bIdx])) {
// transposition
this.current[j] = Math.min(
this.current[j],
this.prevPrev[j - 2] + 1
this.prevPrev[j - 2] + 1,
);
}
}
@ -242,6 +242,14 @@ function initSearch(rawSearchIndex) {
* @type {Array<Row>}
*/
let searchIndex;
/**
* @type {Map<String, RoaringBitmap>}
*/
let searchIndexDeprecated;
/**
* @type {Map<String, RoaringBitmap>}
*/
let searchIndexEmptyDesc;
/**
* @type {Uint32Array}
*/
@ -426,7 +434,7 @@ function initSearch(rawSearchIndex) {
return c === "," || c === "=";
}
/**
/**
* Returns `true` if the given `c` character is a path separator. For example
* `:` in `a::b` or a whitespace in `a b`.
*
@ -856,8 +864,8 @@ function initSearch(rawSearchIndex) {
parserState,
parserState.userQuery.slice(start, end),
generics,
isInGenerics
)
isInGenerics,
),
);
}
}
@ -1295,7 +1303,7 @@ function initSearch(rawSearchIndex) {
*
* @return {ResultsTable}
*/
function execQuery(parsedQuery, filterCrates, currentCrate) {
async function execQuery(parsedQuery, filterCrates, currentCrate) {
const results_others = new Map(), results_in_args = new Map(),
results_returned = new Map();
@ -1342,9 +1350,9 @@ function initSearch(rawSearchIndex) {
* @param {Results} results
* @param {boolean} isType
* @param {string} preferredCrate
* @returns {[ResultObject]}
* @returns {Promise<[ResultObject]>}
*/
function sortResults(results, isType, preferredCrate) {
async function sortResults(results, isType, preferredCrate) {
const userQuery = parsedQuery.userQuery;
const result_list = [];
for (const result of results.values()) {
@ -1394,8 +1402,8 @@ function initSearch(rawSearchIndex) {
}
// sort deprecated items later
a = aaa.item.deprecated;
b = bbb.item.deprecated;
a = searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex);
b = searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex);
if (a !== b) {
return a - b;
}
@ -1422,8 +1430,8 @@ function initSearch(rawSearchIndex) {
}
// sort by description (no description goes later)
a = (aaa.item.desc === "");
b = (bbb.item.desc === "");
a = searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex);
b = searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex);
if (a !== b) {
return a - b;
}
@ -1446,7 +1454,16 @@ function initSearch(rawSearchIndex) {
return 0;
});
return transformResults(result_list);
const transformed = transformResults(result_list);
const descs = await Promise.all(transformed.map(result => {
return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ?
"" :
searchState.loadDesc(result);
}));
for (const [i, result] of transformed.entries()) {
result.desc = descs[i];
}
return transformed;
}
/**
@ -1477,7 +1494,7 @@ function initSearch(rawSearchIndex) {
whereClause,
mgensIn,
solutionCb,
unboxingDepth
unboxingDepth,
) {
if (unboxingDepth >= UNBOXING_LIMIT) {
return false;
@ -1524,7 +1541,7 @@ function initSearch(rawSearchIndex) {
queryElem,
whereClause,
mgens,
unboxingDepth + 1
unboxingDepth + 1,
)) {
continue;
}
@ -1541,7 +1558,7 @@ function initSearch(rawSearchIndex) {
whereClause,
mgensScratch,
solutionCb,
unboxingDepth + 1
unboxingDepth + 1,
)) {
return true;
}
@ -1551,7 +1568,7 @@ function initSearch(rawSearchIndex) {
whereClause,
mgens ? new Map(mgens) : null,
solutionCb,
unboxingDepth + 1
unboxingDepth + 1,
)) {
return true;
}
@ -1625,7 +1642,7 @@ function initSearch(rawSearchIndex) {
queryElem,
whereClause,
mgensScratch,
unboxingDepth
unboxingDepth,
);
if (!solution) {
return false;
@ -1638,7 +1655,7 @@ function initSearch(rawSearchIndex) {
whereClause,
simplifiedMgens,
solutionCb,
unboxingDepth
unboxingDepth,
);
if (passesUnification) {
return true;
@ -1646,7 +1663,7 @@ function initSearch(rawSearchIndex) {
}
return false;
},
unboxingDepth
unboxingDepth,
);
if (passesUnification) {
return true;
@ -1663,7 +1680,7 @@ function initSearch(rawSearchIndex) {
queryElem,
whereClause,
mgens,
unboxingDepth + 1
unboxingDepth + 1,
)) {
continue;
}
@ -1689,7 +1706,7 @@ function initSearch(rawSearchIndex) {
whereClause,
mgensScratch,
solutionCb,
unboxingDepth + 1
unboxingDepth + 1,
);
if (passesUnification) {
return true;
@ -1820,7 +1837,7 @@ function initSearch(rawSearchIndex) {
queryElem,
whereClause,
mgensIn,
unboxingDepth
unboxingDepth,
) {
if (fnType.bindings.size < queryElem.bindings.size) {
return false;
@ -1849,7 +1866,7 @@ function initSearch(rawSearchIndex) {
// possible solutions
return false;
},
unboxingDepth
unboxingDepth,
);
return newSolutions;
});
@ -1887,7 +1904,7 @@ function initSearch(rawSearchIndex) {
queryElem,
whereClause,
mgens,
unboxingDepth
unboxingDepth,
) {
if (unboxingDepth >= UNBOXING_LIMIT) {
return false;
@ -1914,7 +1931,7 @@ function initSearch(rawSearchIndex) {
queryElem,
whereClause,
mgensTmp,
unboxingDepth
unboxingDepth,
);
} else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
const simplifiedGenerics = [
@ -1926,7 +1943,7 @@ function initSearch(rawSearchIndex) {
queryElem,
whereClause,
mgens,
unboxingDepth
unboxingDepth,
);
}
return false;
@ -1975,7 +1992,7 @@ function initSearch(rawSearchIndex) {
elem,
whereClause,
mgens,
unboxingDepth + 1
unboxingDepth + 1,
);
}
if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
@ -1989,7 +2006,7 @@ function initSearch(rawSearchIndex) {
elem,
whereClause,
mgens,
unboxingDepth
unboxingDepth,
);
}
}
@ -2007,7 +2024,7 @@ function initSearch(rawSearchIndex) {
return 0;
}
const maxPathEditDistance = Math.floor(
contains.reduce((acc, next) => acc + next.length, 0) / 3
contains.reduce((acc, next) => acc + next.length, 0) / 3,
);
let ret_dist = maxPathEditDistance + 1;
const path = ty.path.split("::");
@ -2066,12 +2083,13 @@ function initSearch(rawSearchIndex) {
crate: item.crate,
name: item.name,
path: item.path,
desc: item.desc,
descShard: item.descShard,
descIndex: item.descIndex,
ty: item.ty,
parent: item.parent,
type: item.type,
is_alias: true,
deprecated: item.deprecated,
bitIndex: item.bitIndex,
implDisambiguator: item.implDisambiguator,
};
}
@ -2192,7 +2210,7 @@ function initSearch(rawSearchIndex) {
results_others,
results_in_args,
results_returned,
maxEditDistance
maxEditDistance,
) {
if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
return;
@ -2204,7 +2222,7 @@ function initSearch(rawSearchIndex) {
// atoms in the function not present in the query
const tfpDist = compareTypeFingerprints(
fullId,
parsedQuery.typeFingerprint
parsedQuery.typeFingerprint,
);
if (tfpDist !== null) {
const in_args = row.type && row.type.inputs
@ -2276,7 +2294,7 @@ function initSearch(rawSearchIndex) {
const tfpDist = compareTypeFingerprints(
row.id,
parsedQuery.typeFingerprint
parsedQuery.typeFingerprint,
);
if (tfpDist === null) {
return;
@ -2298,10 +2316,10 @@ function initSearch(rawSearchIndex) {
row.type.where_clause,
mgens,
null,
0 // unboxing depth
0, // unboxing depth
);
},
0 // unboxing depth
0, // unboxing depth
)) {
return;
}
@ -2419,7 +2437,7 @@ function initSearch(rawSearchIndex) {
}
return [typeNameIdMap.get(name).id, constraints];
})
}),
);
}
@ -2446,7 +2464,7 @@ function initSearch(rawSearchIndex) {
results_others,
results_in_args,
results_returned,
maxEditDistance
maxEditDistance,
);
}
}
@ -2477,10 +2495,15 @@ function initSearch(rawSearchIndex) {
innerRunQuery();
}
const ret = createQueryResults(
const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
sortResults(results_in_args, true, currentCrate),
sortResults(results_returned, true, currentCrate),
sortResults(results_others, false, currentCrate),
]);
const ret = createQueryResults(
sorted_in_args,
sorted_returned,
sorted_others,
parsedQuery);
handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate);
if (parsedQuery.error !== null && ret.others.length !== 0) {
@ -2581,14 +2604,14 @@ function initSearch(rawSearchIndex) {
* @param {ParsedQuery} query
* @param {boolean} display - True if this is the active tab
*/
function addTab(array, query, display) {
async function addTab(array, query, display) {
const extraClass = display ? " active" : "";
const output = document.createElement("div");
if (array.length > 0) {
output.className = "search-results " + extraClass;
array.forEach(item => {
for (const item of array) {
const name = item.name;
const type = itemTypes[item.ty];
const longType = longItemTypes[item.ty];
@ -2624,7 +2647,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
link.appendChild(description);
output.appendChild(link);
});
}
} else if (query.error === null) {
output.className = "search-failed" + extraClass;
output.innerHTML = "No results :(<br/>" +
@ -2666,7 +2689,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
* @param {boolean} go_to_first
* @param {string} filterCrates
*/
function showResults(results, go_to_first, filterCrates) {
async function showResults(results, go_to_first, filterCrates) {
const search = searchState.outputElement();
if (go_to_first || (results.others.length === 1
&& getSettingValue("go-to-only-result") === "true")
@ -2699,9 +2722,11 @@ ${item.displayPath}<span class="${type}">${name}</span>\
currentResults = results.query.userQuery;
const ret_others = addTab(results.others, results.query, true);
const ret_in_args = addTab(results.in_args, results.query, false);
const ret_returned = addTab(results.returned, results.query, false);
const [ret_others, ret_in_args, ret_returned] = await Promise.all([
addTab(results.others, results.query, true),
addTab(results.in_args, results.query, false),
addTab(results.returned, results.query, false),
]);
// Navigate to the relevant tab if the current tab is empty, like in case users search
// for "-> String". If they had selected another tab previously, they have to click on
@ -2822,7 +2847,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
* and display the results.
* @param {boolean} [forced]
*/
function search(forced) {
async function search(forced) {
const query = parseQuery(searchState.input.value.trim());
let filterCrates = getFilterCrates();
@ -2850,8 +2875,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
// recent search query is added to the browser history.
updateSearchHistory(buildUrl(query.original, filterCrates));
showResults(
execQuery(query, filterCrates, window.currentCrate),
await showResults(
await execQuery(query, filterCrates, window.currentCrate),
params.go_to_first,
filterCrates);
}
@ -2920,7 +2945,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
pathIndex = type[PATH_INDEX_DATA];
generics = buildItemSearchTypeAll(
type[GENERICS_DATA],
lowercasePaths
lowercasePaths,
);
if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
bindings = new Map(type[BINDINGS_DATA].map(binding => {
@ -3030,101 +3055,49 @@ ${item.displayPath}<span class="${type}">${name}</span>\
* The raw function search type format is generated using serde in
* librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
*
* @param {{
* string: string,
* offset: number,
* backrefQueue: FunctionSearchType[]
* }} itemFunctionDecoder
* @param {Array<{name: string, ty: number}>} lowercasePaths
* @param {Map<string, integer>}
*
* @return {null|FunctionSearchType}
*/
function buildFunctionSearchType(itemFunctionDecoder, lowercasePaths) {
const c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
itemFunctionDecoder.offset += 1;
const [zero, ua, la, ob, cb] = ["0", "@", "`", "{", "}"].map(c => c.charCodeAt(0));
// `` ` `` is used as a sentinel because it's fewer bytes than `null`, and decodes to zero
// `0` is a backref
if (c === la) {
return null;
}
// sixteen characters after "0" are backref
if (c >= zero && c < ua) {
return itemFunctionDecoder.backrefQueue[c - zero];
}
if (c !== ob) {
throw ["Unexpected ", c, " in function: expected ", "{", "; this is a bug"];
}
// call after consuming `{`
function decodeList() {
let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
const ret = [];
while (c !== cb) {
ret.push(decode());
c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
function buildFunctionSearchTypeCallback(lowercasePaths) {
return functionSearchType => {
if (functionSearchType === 0) {
return null;
}
itemFunctionDecoder.offset += 1; // eat cb
return ret;
}
// consumes and returns a list or integer
function decode() {
let n = 0;
let c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
if (c === ob) {
itemFunctionDecoder.offset += 1;
return decodeList();
}
while (c < la) {
n = (n << 4) | (c & 0xF);
itemFunctionDecoder.offset += 1;
c = itemFunctionDecoder.string.charCodeAt(itemFunctionDecoder.offset);
}
// last character >= la
n = (n << 4) | (c & 0xF);
const [sign, value] = [n & 1, n >> 1];
itemFunctionDecoder.offset += 1;
return sign ? -value : value;
}
const functionSearchType = decodeList();
const INPUTS_DATA = 0;
const OUTPUT_DATA = 1;
let inputs, output;
if (typeof functionSearchType[INPUTS_DATA] === "number") {
inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)];
} else {
inputs = buildItemSearchTypeAll(
functionSearchType[INPUTS_DATA],
lowercasePaths
);
}
if (functionSearchType.length > 1) {
if (typeof functionSearchType[OUTPUT_DATA] === "number") {
output = [buildItemSearchType(functionSearchType[OUTPUT_DATA], lowercasePaths)];
const INPUTS_DATA = 0;
const OUTPUT_DATA = 1;
let inputs, output;
if (typeof functionSearchType[INPUTS_DATA] === "number") {
inputs = [buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths)];
} else {
output = buildItemSearchTypeAll(
functionSearchType[OUTPUT_DATA],
lowercasePaths
inputs = buildItemSearchTypeAll(
functionSearchType[INPUTS_DATA],
lowercasePaths,
);
}
} else {
output = [];
}
const where_clause = [];
const l = functionSearchType.length;
for (let i = 2; i < l; ++i) {
where_clause.push(typeof functionSearchType[i] === "number"
? [buildItemSearchType(functionSearchType[i], lowercasePaths)]
: buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
}
const ret = {
inputs, output, where_clause,
if (functionSearchType.length > 1) {
if (typeof functionSearchType[OUTPUT_DATA] === "number") {
output = [buildItemSearchType(functionSearchType[OUTPUT_DATA], lowercasePaths)];
} else {
output = buildItemSearchTypeAll(
functionSearchType[OUTPUT_DATA],
lowercasePaths,
);
}
} else {
output = [];
}
const where_clause = [];
const l = functionSearchType.length;
for (let i = 2; i < l; ++i) {
where_clause.push(typeof functionSearchType[i] === "number"
? [buildItemSearchType(functionSearchType[i], lowercasePaths)]
: buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
}
return {
inputs, output, where_clause,
};
};
itemFunctionDecoder.backrefQueue.unshift(ret);
if (itemFunctionDecoder.backrefQueue.length > 16) {
itemFunctionDecoder.backrefQueue.pop();
}
return ret;
}
/**
@ -3245,6 +3218,185 @@ ${item.displayPath}<span class="${type}">${name}</span>\
return functionTypeFingerprint[(fullId * 4) + 3];
}
class VlqHexDecoder {
constructor(string, cons) {
this.string = string;
this.cons = cons;
this.offset = 0;
this.backrefQueue = [];
}
// call after consuming `{`
decodeList() {
const cb = "}".charCodeAt(0);
let c = this.string.charCodeAt(this.offset);
const ret = [];
while (c !== cb) {
ret.push(this.decode());
c = this.string.charCodeAt(this.offset);
}
this.offset += 1; // eat cb
return ret;
}
// consumes and returns a list or integer
decode() {
const [ob, la] = ["{", "`"].map(c => c.charCodeAt(0));
let n = 0;
let c = this.string.charCodeAt(this.offset);
if (c === ob) {
this.offset += 1;
return this.decodeList();
}
while (c < la) {
n = (n << 4) | (c & 0xF);
this.offset += 1;
c = this.string.charCodeAt(this.offset);
}
// last character >= la
n = (n << 4) | (c & 0xF);
const [sign, value] = [n & 1, n >> 1];
this.offset += 1;
return sign ? -value : value;
}
next() {
const c = this.string.charCodeAt(this.offset);
const [zero, ua, la] = ["0", "@", "`"].map(c => c.charCodeAt(0));
// sixteen characters after "0" are backref
if (c >= zero && c < ua) {
this.offset += 1;
return this.backrefQueue[c - zero];
}
// special exception: 0 doesn't use backref encoding
// it's already one character, and it's always nullish
if (c === la) {
this.offset += 1;
return this.cons(0);
}
const result = this.cons(this.decode());
this.backrefQueue.unshift(result);
if (this.backrefQueue.length > 16) {
this.backrefQueue.pop();
}
return result;
}
}
class RoaringBitmap {
constructor(str) {
const strdecoded = atob(str);
const u8array = new Uint8Array(strdecoded.length);
for (let j = 0; j < strdecoded.length; ++j) {
u8array[j] = strdecoded.charCodeAt(j);
}
const has_runs = u8array[0] === 0x3b;
const size = has_runs ?
((u8array[2] | (u8array[3] << 8)) + 1) :
((u8array[4] | (u8array[5] << 8) | (u8array[6] << 16) | (u8array[7] << 24)));
let i = has_runs ? 4 : 8;
let is_run;
if (has_runs) {
const is_run_len = Math.floor((size + 7) / 8);
is_run = u8array.slice(i, i + is_run_len);
i += is_run_len;
} else {
is_run = new Uint8Array();
}
this.keys = [];
this.cardinalities = [];
for (let j = 0; j < size; ++j) {
this.keys.push(u8array[i] | (u8array[i + 1] << 8));
i += 2;
this.cardinalities.push((u8array[i] | (u8array[i + 1] << 8)) + 1);
i += 2;
}
this.containers = [];
let offsets = null;
if (!has_runs || this.keys.length >= 4) {
offsets = [];
for (let j = 0; j < size; ++j) {
offsets.push(u8array[i] | (u8array[i + 1] << 8) | (u8array[i + 2] << 16) |
(u8array[i + 3] << 24));
i += 4;
}
}
for (let j = 0; j < size; ++j) {
if (offsets && offsets[j] !== i) {
console.log(this.containers);
throw new Error(`corrupt bitmap ${j}: ${i} / ${offsets[j]}`);
}
if (is_run[j >> 3] & (1 << (j & 0x7))) {
const runcount = (u8array[i] | (u8array[i + 1] << 8));
i += 2;
this.containers.push(new RoaringBitmapRun(
runcount,
u8array.slice(i, i + (runcount * 4)),
));
i += runcount * 4;
} else if (this.cardinalities[j] >= 4096) {
this.containers.push(new RoaringBitmapBits(u8array.slice(i, i + 8192)));
i += 8192;
} else {
const end = this.cardinalities[j] * 2;
this.containers.push(new RoaringBitmapArray(
this.cardinalities[j],
u8array.slice(i, i + end),
));
i += end;
}
}
}
contains(keyvalue) {
const key = keyvalue >> 16;
const value = keyvalue & 0xFFFF;
for (let i = 0; i < this.keys.length; ++i) {
if (this.keys[i] === key) {
return this.containers[i].contains(value);
}
}
return false;
}
}
class RoaringBitmapRun {
constructor(runcount, array) {
this.runcount = runcount;
this.array = array;
}
contains(value) {
const l = this.runcount * 4;
for (let i = 0; i < l; i += 4) {
const start = this.array[i] | (this.array[i + 1] << 8);
const lenm1 = this.array[i + 2] | (this.array[i + 3] << 8);
if (value >= start && value <= (start + lenm1)) {
return true;
}
}
return false;
}
}
class RoaringBitmapArray {
constructor(cardinality, array) {
this.cardinality = cardinality;
this.array = array;
}
contains(value) {
const l = this.cardinality * 2;
for (let i = 0; i < l; i += 2) {
const start = this.array[i] | (this.array[i + 1] << 8);
if (value === start) {
return true;
}
}
return false;
}
}
class RoaringBitmapBits {
constructor(array) {
this.array = array;
}
contains(value) {
return !!(this.array[value >> 3] & (1 << (value & 7)));
}
}
/**
* Convert raw search index into in-memory search index.
*
@ -3252,6 +3404,8 @@ ${item.displayPath}<span class="${type}">${name}</span>\
*/
function buildIndex(rawSearchIndex) {
searchIndex = [];
searchIndexDeprecated = new Map();
searchIndexEmptyDesc = new Map();
const charA = "A".charCodeAt(0);
let currentIndex = 0;
let id = 0;
@ -3271,26 +3425,48 @@ ${item.displayPath}<span class="${type}">${name}</span>\
id = 0;
for (const [crate, crateCorpus] of rawSearchIndex) {
// a string representing the lengths of each description shard
// a string representing the list of function types
const itemDescShardDecoder = new VlqHexDecoder(crateCorpus.D, noop => noop);
let descShard = {
crate,
shard: 0,
start: 0,
len: itemDescShardDecoder.next(),
promise: null,
resolve: null,
};
const descShardList = [ descShard ];
// Deprecated items and items with no description
searchIndexDeprecated.set(crate, new RoaringBitmap(crateCorpus.c));
searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e));
let descIndex = 0;
// This object should have exactly the same set of fields as the "row"
// object defined below. Your JavaScript runtime will thank you.
// https://mathiasbynens.be/notes/shapes-ics
const crateRow = {
crate: crate,
crate,
ty: 3, // == ExternCrate
name: crate,
path: "",
desc: crateCorpus.doc,
descShard,
descIndex,
parent: undefined,
type: null,
id: id,
id,
word: crate,
normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""),
deprecated: null,
bitIndex: 0,
implDisambiguator: null,
};
id += 1;
searchIndex.push(crateRow);
currentIndex += 1;
if (!searchIndexEmptyDesc.get(crate).contains(0)) {
descIndex += 1;
}
// a String of one character item type codes
const itemTypes = crateCorpus.t;
@ -3302,19 +3478,9 @@ ${item.displayPath}<span class="${type}">${name}</span>\
// i.e. if indices 4 and 11 are present, but 5-10 and 12-13 are not present,
// 5-10 will fall back to the path for 4 and 12-13 will fall back to the path for 11
const itemPaths = new Map(crateCorpus.q);
// an array of (String) descriptions
const itemDescs = crateCorpus.d;
// an array of (Number) the parent path index + 1 to `paths`, or 0 if none
const itemParentIdxs = crateCorpus.i;
// a string representing the list of function types
const itemFunctionDecoder = {
string: crateCorpus.f,
offset: 0,
backrefQueue: [],
};
// an array of (Number) indices for the deprecated items
const deprecatedItems = new Set(crateCorpus.c);
// an array of (Number) indices for the deprecated items
// a map Number, string for impl disambiguators
const implDisambiguator = new Map(crateCorpus.b);
// an array of [(Number) item type,
// (String) name]
@ -3326,6 +3492,12 @@ ${item.displayPath}<span class="${type}">${name}</span>\
// an array of [{name: String, ty: Number}]
const lowercasePaths = [];
// a string representing the list of function types
const itemFunctionDecoder = new VlqHexDecoder(
crateCorpus.f,
buildFunctionSearchTypeCallback(lowercasePaths),
);
// convert `rawPaths` entries into object form
// generate normalizedPaths for function search mode
let len = paths.length;
@ -3354,12 +3526,26 @@ ${item.displayPath}<span class="${type}">${name}</span>\
lastPath = "";
len = itemTypes.length;
for (let i = 0; i < len; ++i) {
const bitIndex = i + 1;
if (descIndex >= descShard.len &&
!searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
descShard = {
crate,
shard: descShard.shard + 1,
start: descShard.start + descShard.len,
len: itemDescShardDecoder.next(),
promise: null,
resolve: null,
};
descIndex = 0;
descShardList.push(descShard);
}
let word = "";
if (typeof itemNames[i] === "string") {
word = itemNames[i].toLowerCase();
}
const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
const type = buildFunctionSearchType(itemFunctionDecoder, lowercasePaths);
const type = itemFunctionDecoder.next();
if (type !== null) {
if (type) {
const fp = functionTypeFingerprint.subarray(id * 4, (id + 1) * 4);
@ -3380,22 +3566,26 @@ ${item.displayPath}<span class="${type}">${name}</span>\
// This object should have exactly the same set of fields as the "crateRow"
// object defined above.
const row = {
crate: crate,
crate,
ty: itemTypes.charCodeAt(i) - charA,
name: itemNames[i],
path: path,
desc: itemDescs[i],
path,
descShard,
descIndex,
parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined,
type,
id: id,
id,
word,
normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""),
deprecated: deprecatedItems.has(i),
bitIndex,
implDisambiguator: implDisambiguator.has(i) ? implDisambiguator.get(i) : null,
};
id += 1;
searchIndex.push(row);
lastPath = row.path;
if (!searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
descIndex += 1;
}
}
if (aliases) {
@ -3419,6 +3609,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
}
}
currentIndex += itemTypes.length;
searchState.descShards.set(crate, descShardList);
}
// Drop the (rather large) hash table used for reusing function items
TYPES_POOL = new Map();

View File

@ -211,14 +211,14 @@ function updateSidebarWidth() {
if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
document.documentElement.style.setProperty(
"--desktop-sidebar-width",
desktopSidebarWidth + "px"
desktopSidebarWidth + "px",
);
}
const srcSidebarWidth = getSettingValue("src-sidebar-width");
if (srcSidebarWidth && srcSidebarWidth !== "null") {
document.documentElement.style.setProperty(
"--src-sidebar-width",
srcSidebarWidth + "px"
srcSidebarWidth + "px",
);
}
}

View File

@ -6,7 +6,7 @@ module.exports = {
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 2015,
"ecmaVersion": 8,
"sourceType": "module"
},
"rules": {

View File

@ -1,3 +1,4 @@
/* global globalThis */
const fs = require("fs");
const path = require("path");
@ -133,7 +134,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
expected_value,
result.get(key),
error_text,
queryName
queryName,
);
} else {
error_text.push(`${queryName}==> EXPECTED has extra key in map from field ` +
@ -212,11 +213,11 @@ function runParser(query, expected, parseQuery, queryName) {
return error_text;
}
function runSearch(query, expected, doSearch, loadedFile, queryName) {
async function runSearch(query, expected, doSearch, loadedFile, queryName) {
const ignore_order = loadedFile.ignore_order;
const exact_check = loadedFile.exact_check;
const results = doSearch(query, loadedFile.FILTER_CRATE);
const results = await doSearch(query, loadedFile.FILTER_CRATE);
const error_text = [];
for (const key in expected) {
@ -238,7 +239,7 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) {
}
let prev_pos = -1;
entry.forEach((elem, index) => {
for (const [index, elem] of entry.entries()) {
const entry_pos = lookForEntry(elem, results[key]);
if (entry_pos === -1) {
error_text.push(queryName + "==> Result not found in '" + key + "': '" +
@ -260,13 +261,13 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) {
} else {
prev_pos = entry_pos;
}
});
}
}
return error_text;
}
function runCorrections(query, corrections, getCorrections, loadedFile) {
const qc = getCorrections(query, loadedFile.FILTER_CRATE);
async function runCorrections(query, corrections, getCorrections, loadedFile) {
const qc = await getCorrections(query, loadedFile.FILTER_CRATE);
const error_text = [];
if (corrections === null) {
@ -299,18 +300,27 @@ function checkResult(error_text, loadedFile, displaySuccess) {
return 1;
}
function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
async function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
if (typeof entry.query !== "string") {
console.log("FAILED");
console.log("==> Missing `query` field");
return false;
}
let error_text = callback(entry.query, entry, extra ? "[ query `" + entry.query + "`]" : "");
let error_text = await callback(
entry.query,
entry,
extra ? "[ query `" + entry.query + "`]" : "",
);
if (checkResult(error_text, loadedFile, false) !== 0) {
return false;
}
if (entry.correction !== undefined) {
error_text = runCorrections(entry.query, entry.correction, getCorrections, loadedFile);
error_text = await runCorrections(
entry.query,
entry.correction,
getCorrections,
loadedFile,
);
if (checkResult(error_text, loadedFile, false) !== 0) {
return false;
}
@ -318,16 +328,16 @@ function runCheckInner(callback, loadedFile, entry, getCorrections, extra) {
return true;
}
function runCheck(loadedFile, key, getCorrections, callback) {
async function runCheck(loadedFile, key, getCorrections, callback) {
const expected = loadedFile[key];
if (Array.isArray(expected)) {
for (const entry of expected) {
if (!runCheckInner(callback, loadedFile, entry, getCorrections, true)) {
if (!await runCheckInner(callback, loadedFile, entry, getCorrections, true)) {
return 1;
}
}
} else if (!runCheckInner(callback, loadedFile, expected, getCorrections, false)) {
} else if (!await runCheckInner(callback, loadedFile, expected, getCorrections, false)) {
return 1;
}
console.log("OK");
@ -338,7 +348,7 @@ function hasCheck(content, checkName) {
return content.startsWith(`const ${checkName}`) || content.includes(`\nconst ${checkName}`);
}
function runChecks(testFile, doSearch, parseQuery, getCorrections) {
async function runChecks(testFile, doSearch, parseQuery, getCorrections) {
let checkExpected = false;
let checkParsed = false;
let testFileContent = readFile(testFile);
@ -367,12 +377,12 @@ function runChecks(testFile, doSearch, parseQuery, getCorrections) {
let res = 0;
if (checkExpected) {
res += runCheck(loadedFile, "EXPECTED", getCorrections, (query, expected, text) => {
res += await runCheck(loadedFile, "EXPECTED", getCorrections, (query, expected, text) => {
return runSearch(query, expected, doSearch, loadedFile, text);
});
}
if (checkParsed) {
res += runCheck(loadedFile, "PARSED", getCorrections, (query, expected, text) => {
res += await runCheck(loadedFile, "PARSED", getCorrections, (query, expected, text) => {
return runParser(query, expected, parseQuery, text);
});
}
@ -393,6 +403,35 @@ function loadSearchJS(doc_folder, resource_suffix) {
const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
const searchIndex = require(searchIndexJs);
globalThis.searchState = {
descShards: new Map(),
loadDesc: async function({descShard, descIndex}) {
if (descShard.promise === null) {
descShard.promise = new Promise((resolve, reject) => {
descShard.resolve = resolve;
const ds = descShard;
const fname = `${ds.crate}-desc-${ds.shard}-${resource_suffix}.js`;
fs.readFile(
`${doc_folder}/search.desc/${descShard.crate}/${fname}`,
(err, data) => {
if (err) {
reject(err);
} else {
eval(data.toString("utf8"));
}
},
);
});
}
const list = await descShard.promise;
return list[descIndex];
},
loadedDescShard: function(crate, shard, data) {
//console.log(this.descShards);
this.descShards.get(crate)[shard].resolve(data.split("\n"));
},
};
const staticFiles = path.join(doc_folder, "static.files");
const searchJs = fs.readdirSync(staticFiles).find(f => f.match(/search.*\.js$/));
const searchModule = require(path.join(staticFiles, searchJs));
@ -474,7 +513,7 @@ function parseOptions(args) {
return null;
}
function main(argv) {
async function main(argv) {
const opts = parseOptions(argv.slice(2));
if (opts === null) {
return 1;
@ -482,7 +521,7 @@ function main(argv) {
const parseAndSearch = loadSearchJS(
opts["doc_folder"],
opts["resource_suffix"]
opts["resource_suffix"],
);
let errors = 0;
@ -494,21 +533,29 @@ function main(argv) {
};
if (opts["test_file"].length !== 0) {
opts["test_file"].forEach(file => {
for (const file of opts["test_file"]) {
process.stdout.write(`Testing ${file} ... `);
errors += runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections);
});
errors += await runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections);
}
} else if (opts["test_folder"].length !== 0) {
fs.readdirSync(opts["test_folder"]).forEach(file => {
for (const file of fs.readdirSync(opts["test_folder"])) {
if (!file.endsWith(".js")) {
return;
continue;
}
process.stdout.write(`Testing ${file} ... `);
errors += runChecks(path.join(opts["test_folder"], file), doSearch,
errors += await runChecks(path.join(opts["test_folder"], file), doSearch,
parseAndSearch.parseQuery, getCorrections);
});
}
}
return errors > 0 ? 1 : 0;
}
process.exit(main(process.argv));
main(process.argv).catch(e => {
console.log(e);
process.exit(1);
}).then(x => process.exit(x));
process.on("beforeExit", () => {
console.log("process did not complete");
process.exit(1);
});

View File

@ -2,7 +2,7 @@
define-function: (
"check-colors",
(theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color),
[theme, main_color, title_color, main_heading_color, main_heading_type_color, src_link_color, sidebar_link_color],
block {
go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
// This is needed to ensure that the text color is computed.

View File

@ -8,7 +8,7 @@ show-text: true
define-function: (
"check-colors",
(theme, doc_code_color, doc_inline_code_color),
[theme, doc_code_color, doc_inline_code_color],
block {
// Set the theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}

View File

@ -4,7 +4,7 @@ show-text: true
define-function: (
"check-colors",
(theme, background, color, border),
[theme, background, color, border],
block {
// Setting the theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}

View File

@ -8,7 +8,7 @@ assert-css: ("#toggle-all-docs", {"cursor": "pointer"})
assert-css: ("#copy-path", {"cursor": "pointer"})
// the search tabs
write: (".search-input", "Foo")
write-into: (".search-input", "Foo")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -10,7 +10,7 @@ assert-false: "pre.example-line-numbers"
// Let's now check some CSS properties...
define-function: (
"check-colors",
(theme, color),
[theme, color],
block {
// We now set the setting to show the line numbers on code examples.
set-local-storage: {

View File

@ -6,7 +6,7 @@ compare-elements-css: (".impl-items .docblock table td", ".top-doc .docblock tab
define-function: (
"check-colors",
(theme, border_color, zebra_stripe_color),
[theme, border_color, zebra_stripe_color],
block {
set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
reload:

View File

@ -2,7 +2,7 @@
// current content displayed.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// First, we check that the search results are hidden when the Escape key is pressed.
write: (".search-input", "test")
write-into: (".search-input", "test")
// To be SURE that the search will be run.
press-key: 'Enter'
wait-for: "#search h1" // The search element is empty before the first search

View File

@ -10,7 +10,7 @@ assert-window-property: {"srcIndex": null}
// Form input
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "Foo")
write-into: (".search-input", "Foo")
press-key: 'Enter'
wait-for: "#search-tabs"
assert-window-property-false: {"searchIndex": null}

View File

@ -9,14 +9,14 @@ set-property: ("#implementations-list .implementors-toggle", {"open": "false"})
click: "//*[@class='sidebar']//a[@href='#method.must_use']"
assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})
define-function: ("collapsed-from-search", (), block {
define-function: ("collapsed-from-search", [], block {
// Now we do the same through search result.
// First we reload the page without the anchor in the URL.
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// Then we collapse the section again...
set-property: ("#implementations-list .implementors-toggle", {"open": "false"})
// Then we run the search.
write: (".search-input", "foo::must_use")
write-into: (".search-input", "foo::must_use")
wait-for: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
click: "//*[@id='search']//a[@href='../test_docs/struct.Foo.html#method.must_use']"
assert-property: ("#implementations-list .implementors-toggle", {"open": "true"})

View File

@ -2,7 +2,7 @@
define-function: (
"check-colors",
(theme, color, code_header_color, focus_background_color, headings_color),
[theme, color, code_header_color, focus_background_color, headings_color],
block {
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// This is needed so that the text color is computed.

View File

@ -4,7 +4,7 @@ show-text: true
define-function: (
"check-heading-anchor",
(heading_id),
[heading_id],
block {
// The anchor should not be displayed by default.
assert-css: ("#" + |heading_id| + " .doc-anchor", { "display": "none" })
@ -27,6 +27,6 @@ move-cursor-to: "#top-doc-prose-title"
// to prevent it from overlapping with the `[-]` element.
assert-css: ("#top-doc-prose-title:hover .doc-anchor", { "display": "none" })
call-function: ("check-heading-anchor", ("top-doc-prose-sub-heading"))
call-function: ("check-heading-anchor", ("top-doc-prose-sub-sub-heading"))
call-function: ("check-heading-anchor", ("you-know-the-drill"))
call-function: ("check-heading-anchor", {"heading_id": "top-doc-prose-sub-heading"})
call-function: ("check-heading-anchor", {"heading_id": "top-doc-prose-sub-sub-heading"})
call-function: ("check-heading-anchor", {"heading_id": "you-know-the-drill"})

View File

@ -156,7 +156,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/struct.HeavilyDocumentedStruct.html"
define-function: (
"check-colors",
(theme, heading_color, small_heading_color, heading_border_color),
[theme, heading_color, small_heading_color, heading_border_color],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:
@ -220,7 +220,7 @@ call-function: (
define-function: (
"check-since-color",
(theme),
[theme],
block {
set-local-storage: {"rustdoc-theme": |theme|}
reload:
@ -229,6 +229,6 @@ define-function: (
)
go-to: "file://" + |DOC_PATH| + "/staged_api/struct.Foo.html"
call-function: ("check-since-color", ("ayu"))
call-function: ("check-since-color", ("dark"))
call-function: ("check-since-color", ("light"))
call-function: ("check-since-color", {"theme": "ayu"})
call-function: ("check-since-color", {"theme": "dark"})
call-function: ("check-since-color", {"theme": "light"})

View File

@ -7,17 +7,17 @@ assert-css: ("#help dd", {"font-size": "16px"})
click: "#help-button > a"
assert-css: ("#help", {"display": "block"})
compare-elements-property: (".sub", "#help", ["offsetWidth"])
compare-elements-position: (".sub", "#help", ("x"))
compare-elements-position: (".sub", "#help", ["x"])
set-window-size: (500, 1000) // Try mobile next.
assert-css: ("#help", {"display": "block"})
compare-elements-property: (".sub", "#help", ["offsetWidth"])
compare-elements-position: (".sub", "#help", ("x"))
compare-elements-position: (".sub", "#help", ["x"])
// Checking the color of the elements of the help menu.
show-text: true
define-function: (
"check-colors",
(theme, color, background, box_shadow),
[theme, color, background, box_shadow],
block {
// Setting the theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@ -60,7 +60,7 @@ assert-css: ("#help dd", {"font-size": "16px"})
click: "#help-button > a"
assert-css: ("#help", {"display": "none"})
compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
compare-elements-position-false: (".sub", "#help", ("x"))
compare-elements-position-false: (".sub", "#help", ["x"])
// This test ensures that the "the rustdoc book" anchor link within the help popover works.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"

View File

@ -4,7 +4,7 @@ show-text: true
define-function: (
"check-colors",
(
[
theme,
kw,
kw2,
@ -20,7 +20,7 @@ define-function: (
question_mark,
comment,
doc_comment,
),
],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:

View File

@ -6,7 +6,7 @@ fail-on-request-error: false
define-function: (
"check-colors",
(
[
theme,
attr_color,
trait_color,
@ -16,7 +16,7 @@ define-function: (
constant_color,
fn_color,
assoc_type_color,
),
],
block {
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.WithGenerics.html"
show-text: true

View File

@ -4,7 +4,7 @@ show-text: true
define-function: (
"check-item-decl-comment",
(theme, url, comment_color),
[theme, url, comment_color],
block {
go-to: |url|
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@ -15,7 +15,7 @@ define-function: (
define-function: (
"check-items-for-theme",
(theme, comment_color),
[theme, comment_color],
block {
call-function: ("check-item-decl-comment", {
"theme": |theme|,

View File

@ -4,7 +4,7 @@ go-to: "file://" + |DOC_PATH| + "/lib2/struct.ItemInfoAlignmentTest.html"
// First, we try it in "desktop" mode.
set-window-size: (1200, 870)
compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ["x"])
// Next, we try it in "mobile" mode (max-width: 700px).
set-window-size: (650, 650)
compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x"))
compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ["x"])

View File

@ -31,13 +31,13 @@ assert-count: ("#main-content > .item-info .stab", 2)
compare-elements-position-false: (
"#main-content > .item-info .stab:nth-of-type(1)",
"#main-content > .item-info .stab:nth-of-type(2)",
("y"),
["y"],
)
// But they should have the same `x` position.
compare-elements-position: (
"#main-content > .item-info .stab:nth-of-type(1)",
"#main-content > .item-info .stab:nth-of-type(2)",
("x"),
["x"],
)
// They are supposed to have the same height too.
compare-elements-css: (

View File

@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/src/link_to_definition/lib.rs.html"
define-function: (
"check-background-color",
(theme, background_color),
[theme, background_color],
block {
// Set the theme.
set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
@ -17,6 +17,15 @@ define-function: (
},
)
call-function: ("check-background-color", ("ayu", "#333"))
call-function: ("check-background-color", ("dark", "#333"))
call-function: ("check-background-color", ("light", "#eee"))
call-function: ("check-background-color", {
"theme": "ayu",
"background_color": "#333",
})
call-function: ("check-background-color", {
"theme": "dark",
"background_color": "#333",
})
call-function: ("check-background-color", {
"theme": "light",
"background_color": "#eee",
})

View File

@ -27,14 +27,14 @@ compare-elements-position-near: (
compare-elements-position: (
".item-name .stab.deprecated",
".item-name .stab.portability",
("y"),
["y"],
)
// Ensure no wrap
compare-elements-position: (
"//*[@class='item-name']//a[text()='replaced_function']/..",
"//*[@class='desc docblock-short'][text()='a thing with a label']",
("y"),
["y"],
)
// Mobile view
@ -49,19 +49,19 @@ compare-elements-position-near: (
compare-elements-position: (
".item-name .stab.deprecated",
".item-name .stab.portability",
("y"),
["y"],
)
// Ensure wrap
compare-elements-position-false: (
"//*[@class='item-name']//a[text()='replaced_function']/..",
"//*[@class='desc docblock-short'][text()='a thing with a label']",
("y"),
["y"],
)
compare-elements-position-false: (
".item-name .stab.deprecated",
"//*[@class='desc docblock-short'][text()='a thing with a label']",
("y"),
["y"],
)
// Ensure it doesn't expand.
@ -72,5 +72,5 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/cfgs/index.html"
compare-elements-position-false: (
"//*[@class='stab portability']/code[text()='appservice-api-c']",
"//*[@class='stab portability']/code[text()='server']",
("y"),
["y"],
)

View File

@ -6,8 +6,8 @@ show-text: true
define-function: (
"check-colors",
(theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
sidebar, sidebar_current, sidebar_current_background),
[theme, mod, macro, struct, enum, trait, fn, type, union, keyword,
sidebar, sidebar_current, sidebar_current_background],
block {
set-local-storage: {
"rustdoc-theme": |theme|,

View File

@ -7,13 +7,13 @@ set-window-size: (1100, 600)
compare-elements-position: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y"),
["y"],
)
// Checking they don't have the same x position.
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("x"),
["x"],
)
// The `i` should be *after* the type.
assert-position: (
@ -37,7 +37,7 @@ compare-elements-position-near: (
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
"//*[@class='tooltip popover']",
("x")
["x"]
)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//h1"
@ -48,7 +48,7 @@ set-window-size: (1055, 600)
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y", "x"),
["y", "x"],
)
// Now both the `i` and the struct name should be on the next line.
@ -57,13 +57,13 @@ set-window-size: (980, 600)
compare-elements-position: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y"),
["y"],
)
// Checking they don't have the same x position.
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("x"),
["x"],
)
// The `i` should be *after* the type.
assert-position: (
@ -81,13 +81,13 @@ set-window-size: (650, 600)
compare-elements-position: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("y"),
["y"],
)
// Checking they don't have the same x position.
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//a[text()='NotableStructWithLongName']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
("x"),
["x"],
)
// The `i` should be *after* the type.
assert-position: (
@ -109,7 +109,7 @@ compare-elements-position-near: (
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']",
"//*[@class='tooltip popover']",
("x")
["x"]
)
assert-position: (
"//*[@class='tooltip popover']",
@ -122,7 +122,7 @@ assert-count: ("//*[@class='tooltip popover']", 0)
// Now check the colors.
define-function: (
"check-colors",
(theme, header_color, content_color, type_color, trait_color, link_color),
[theme, header_color, content_color, type_color, trait_color, link_color],
block {
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"
// This is needed to ensure that the text color is computed.

View File

@ -31,7 +31,7 @@ assert-css: ("#settings-menu .popover", {"display": "none"})
define-function: (
"check-popover-colors",
(theme, border_color),
[theme, border_color],
block {
set-local-storage: {
"rustdoc-theme": |theme|,

View File

@ -7,7 +7,7 @@ show-text: true
define-function: (
"check-run-button",
(theme, color, background, hover_color, hover_background),
[theme, color, background, hover_color, hover_background],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:

View File

@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"
define-function: (
"check-logo",
(theme, filter),
[theme, filter],
block {
// Going to the doc page.
go-to: "file://" + |DOC_PATH| + "/staged_api/index.html"

View File

@ -4,8 +4,8 @@ show-text: true
define-function: (
"check-colors",
(theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
help_hover_color),
[theme, highlight, highlight_focus, help_border, help_color, help_hover_border,
help_hover_color],
block {
set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
reload:
@ -64,7 +64,7 @@ go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test.html"
define-function: (
"check-background",
(theme, background_color_start, background_color_end),
[theme, background_color_start, background_color_end],
block {
set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false", }
reload:

View File

@ -5,7 +5,7 @@ go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
show-text: true
define-function: (
"check-color",
(theme, toggle_line_color, toggle_line_hover_color),
[theme, toggle_line_color, toggle_line_hover_color],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:

View File

@ -4,7 +4,7 @@
// First, try a search-by-name
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// Intentionally wrong spelling of "NotableStructWithLongName"
write: (".search-input", "NotableStructWithLongNamr")
write-into: (".search-input", "NotableStructWithLongNamr")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -41,7 +41,7 @@ assert-text: (
// Now, explicit return values
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// Intentionally wrong spelling of "NotableStructWithLongName"
write: (".search-input", "-> NotableStructWithLongNamr")
write-into: (".search-input", "-> NotableStructWithLongNamr")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -58,7 +58,7 @@ assert-text: (
// Now, generic correction
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// Intentionally wrong spelling of "NotableStructWithLongName"
write: (".search-input", "NotableStructWithLongNamr, NotableStructWithLongNamr")
write-into: (".search-input", "NotableStructWithLongNamr, NotableStructWithLongNamr")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -75,7 +75,7 @@ assert-text: (
// Now, generic correction plus error
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// Intentionally wrong spelling of "NotableStructWithLongName"
write: (".search-input", "Foo<NotableStructWithLongNamr>,y")
write-into: (".search-input", "Foo<NotableStructWithLongNamr>,y")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -91,7 +91,7 @@ assert-text: (
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// Intentionally wrong spelling of "NotableStructWithLongName"
write: (".search-input", "generic:NotableStructWithLongNamr<x>,y")
write-into: (".search-input", "generic:NotableStructWithLongNamr<x>,y")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -4,7 +4,7 @@ show-text: true
define-function: (
"check-colors",
(theme, error_background),
[theme, error_background],
block {
// Setting the theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}

View File

@ -1,7 +1,7 @@
// Checks that the crate search filtering is handled correctly and changes the results.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
show-text: true
write: (".search-input", "test")
write-into: (".search-input", "test")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -4,10 +4,10 @@ show-text: true
define-function: (
"check-search-colors",
(
[
theme, border, background, search_input_color, search_input_border_focus,
menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color,
),
],
block {
set-local-storage: {
"rustdoc-theme": |theme|,

View File

@ -1,7 +1,7 @@
// Checks that the search tab results work correctly with function signature syntax
// First, try a search-by-name
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "Foo")
write-into: (".search-input", "Foo")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -4,7 +4,7 @@ show-text: true
define-function: (
"check-no-result",
(theme, link, link_hover),
[theme, link, link_hover],
block {
// Changing theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}

View File

@ -6,7 +6,7 @@ reload:
// First we check that the reexport has the correct ID and no background color.
assert-text: ("//*[@id='reexport.TheStdReexport']", "pub use ::std as TheStdReexport;")
assert-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "rgba(0, 0, 0, 0)"})
write: (".search-input", "TheStdReexport")
write-into: (".search-input", "TheStdReexport")
// To be SURE that the search will be run.
press-key: 'Enter'
wait-for: "//a[@class='result-import']"
@ -22,7 +22,7 @@ wait-for-css: ("//*[@id='reexport.TheStdReexport']", {"background-color": "#494a
// We now check that the alias is working as well on the reexport.
// To be SURE that the search will be run.
press-key: 'Enter'
write: (".search-input", "AliasForTheStdReexport")
write-into: (".search-input", "AliasForTheStdReexport")
wait-for: "//a[@class='result-import']"
assert-text: (
"a.result-import .result-name",

View File

@ -2,7 +2,7 @@
define-function: (
"check-result-color",
(result_kind, color, hover_color),
[result_kind, color, hover_color],
block {
assert-css: (".result-" + |result_kind| + " ." + |result_kind|, {"color": |color|}, ALL)
assert-css: (
@ -78,60 +78,60 @@ store-value: (hover_background_color, "#3c3c3c") // hover background color
store-value: (grey, "#999")
call-function: (
"check-result-color", (
"keyword", // item kind
"#39afd7", // color of item kind
"#39afd7", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "keyword",
"color": "#39afd7",
"hover_color": "#39afd7",
},
)
call-function: (
"check-result-color", (
"struct", // item kind
"#ffa0a5", // color of item kind
"#ffa0a5", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "struct",
"color": "#ffa0a5",
"hover_color": "#ffa0a5",
},
)
call-function: (
"check-result-color", (
"associatedtype", // item kind
"#39afd7", // color of item kind
"#39afd7", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "associatedtype",
"color": "#39afd7",
"hover_color": "#39afd7",
},
)
call-function: (
"check-result-color", (
"tymethod", // item kind
"#fdd687", // color of item kind
"#fdd687", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "tymethod",
"color": "#fdd687",
"hover_color": "#fdd687",
},
)
call-function: (
"check-result-color", (
"method", // item kind
"#fdd687", // color of item kind
"#fdd687", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "method",
"color": "#fdd687",
"hover_color": "#fdd687",
},
)
call-function: (
"check-result-color", (
"structfield", // item kind
"#0096cf", // color of item kind
"#fff", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "structfield",
"color": "#0096cf",
"hover_color": "#fff",
},
)
call-function: (
"check-result-color", (
"macro", // item kind
"#a37acc", // color of item kind
"#a37acc", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "macro",
"color": "#a37acc",
"hover_color": "#a37acc",
},
)
call-function: (
"check-result-color", (
"fn", // item kind
"#fdd687", // color of item kind
"#fdd687", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "fn",
"color": "#fdd687",
"hover_color": "#fdd687",
},
)
// Checking the `<a>` container.
@ -190,60 +190,60 @@ store-value: (hover_background_color, "#616161") // hover background color
store-value: (grey, "#ccc")
call-function: (
"check-result-color", (
"keyword", // item kind
"#d2991d", // color of item kind
"#d2991d", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "keyword",
"color": "#d2991d",
"hover_color": "#d2991d",
},
)
call-function: (
"check-result-color", (
"struct", // item kind
"#2dbfb8", // color of item kind
"#2dbfb8", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "struct",
"color": "#2dbfb8",
"hover_color": "#2dbfb8",
},
)
call-function: (
"check-result-color", (
"associatedtype", // item kind
"#d2991d", // color of item kind
"#d2991d", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "associatedtype",
"color": "#d2991d",
"hover_color": "#d2991d",
},
)
call-function: (
"check-result-color", (
"tymethod", // item kind
"#2bab63", // color of item kind
"#2bab63", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "tymethod",
"color": "#2bab63",
"hover_color": "#2bab63",
},
)
call-function: (
"check-result-color", (
"method", // item kind
"#2bab63", // color of item kind
"#2bab63", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "method",
"color": "#2bab63",
"hover_color": "#2bab63",
},
)
call-function: (
"check-result-color", (
"structfield", // item kind
"#ddd", // color of item kind
"#ddd", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "structfield",
"color": "#ddd",
"hover_color": "#ddd",
},
)
call-function: (
"check-result-color", (
"macro", // item kind
"#09bd00", // color of item kind
"#09bd00", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "macro",
"color": "#09bd00",
"hover_color": "#09bd00",
},
)
call-function: (
"check-result-color", (
"fn", // item kind
"#2bab63", // color of item kind
"#2bab63", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "fn",
"color": "#2bab63",
"hover_color": "#2bab63",
},
)
// Checking the `<a>` container.
@ -287,60 +287,60 @@ store-value: (hover_background_color, "#ccc") // hover background color
store-value: (grey, "#999")
call-function: (
"check-result-color", (
"keyword", // item kind
"#3873ad", // color of item kind
"#3873ad", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "keyword",
"color": "#3873ad",
"hover_color": "#3873ad",
},
)
call-function: (
"check-result-color", (
"struct", // item kind
"#ad378a", // color of item kind
"#ad378a", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "struct",
"color": "#ad378a",
"hover_color": "#ad378a",
},
)
call-function: (
"check-result-color", (
"associatedtype", // item kind
"#3873ad", // color of item kind
"#3873ad", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "associatedtype",
"color": "#3873ad",
"hover_color": "#3873ad",
},
)
call-function: (
"check-result-color", (
"tymethod", // item kind
"#ad7c37", // color of item kind
"#ad7c37", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "tymethod",
"color": "#ad7c37",
"hover_color": "#ad7c37",
},
)
call-function: (
"check-result-color", (
"method", // item kind
"#ad7c37", // color of item kind
"#ad7c37", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "method",
"color": "#ad7c37",
"hover_color": "#ad7c37",
},
)
call-function: (
"check-result-color", (
"structfield", // item kind
"#000", // color of item kind
"#000", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "structfield",
"color": "#000",
"hover_color": "#000",
},
)
call-function: (
"check-result-color", (
"macro", // item kind
"#068000", // color of item kind
"#068000", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "macro",
"color": "#068000",
"hover_color": "#068000",
},
)
call-function: (
"check-result-color", (
"fn", // item kind
"#ad7c37", // color of item kind
"#ad7c37", // color of hovered/focused item kind
),
"check-result-color", {
"result_kind": "fn",
"color": "#ad7c37",
"hover_color": "#ad7c37",
},
)
// Checking the `<a>` container.
@ -358,11 +358,11 @@ show-text: true
define-function: (
"check-alias",
(theme, alias, grey),
[theme, alias, grey],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:
write: (".search-input", "thisisanalias")
write-into: (".search-input", "thisisanalias")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -2,7 +2,7 @@
// Checks that the search results have the expected width.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
set-window-size: (900, 1000)
write: (".search-input", "test")
write-into: (".search-input", "test")
// To be SURE that the search will be run.
press-key: 'Enter'
wait-for: "#crate-search"
@ -69,7 +69,7 @@ assert-css: ("#search", {"width": "640px"})
show-text: true
define-function: (
"check-filter",
(theme, border, filter, hover_border, hover_filter),
[theme, border, filter, hover_border, hover_filter],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:

View File

@ -5,7 +5,7 @@
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// This should link to the inherent impl
write: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
write-into: (".search-input", "ZyxwvutMethodDisambiguation -> bool")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -25,7 +25,7 @@ assert: "section:target"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
// This should link to the trait impl
write: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
write-into: (".search-input", "ZyxwvutMethodDisambiguation, usize -> usize")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -1,6 +1,6 @@
// Checks that the "keyword" results have the expected text alongside them.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "CookieMonster")
write-into: (".search-input", "CookieMonster")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -1,7 +1,7 @@
// Checks that the search tab results work correctly with function signature syntax
// First, try a search-by-name
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "Foo")
write-into: (".search-input", "Foo")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -23,7 +23,7 @@ wait-for-attribute: ("#search-tabs > button:nth-of-type(3)", {"class": "selected
// Now try search-by-return
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "-> String")
write-into: (".search-input", "-> String")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -45,7 +45,7 @@ wait-for-attribute: ("#search-tabs > button:nth-of-type(1)", {"class": "selected
// Try with a search-by-return with no results
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "-> Something")
write-into: (".search-input", "-> Something")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -55,7 +55,7 @@ assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Return Types"
// Try with a search-by-parameter
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "usize,pattern")
write-into: (".search-input", "usize,pattern")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...
@ -65,7 +65,7 @@ assert-text: ("#search-tabs > button:nth-of-type(1)", "In Function Parameters",
// Try with a search-by-parameter-and-return
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
write: (".search-input", "pattern -> str")
write-into: (".search-input", "pattern -> str")
// To be SURE that the search will be run.
press-key: 'Enter'
// Waiting for the search results to appear...

View File

@ -4,9 +4,9 @@ show-text: true
define-function: (
"check-colors",
(theme, background, background_selected, background_hover, border_bottom,
[theme, background, background_selected, background_hover, border_bottom,
border_bottom_selected, border_bottom_hover, border_top, border_top_selected,
border_top_hover),
border_top_hover],
block {
// Setting the theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@ -93,12 +93,12 @@ assert-property: ("#search-tabs > button:nth-child(3) > .count", {"offsetWidth":
compare-elements-position: (
"#search-tabs > button:nth-child(1) > .count",
"#search-tabs > button:nth-child(2) > .count",
("y")
["y"]
)
compare-elements-position: (
"#search-tabs > button:nth-child(2) > .count",
"#search-tabs > button:nth-child(3) > .count",
("y")
["y"]
)
// Check that counts are beside the titles and haven't wrapped
compare-elements-position-near: (
@ -135,12 +135,12 @@ assert-property: ("#search-tabs > button:nth-child(3) > .count", {"offsetWidth":
compare-elements-position: (
"#search-tabs > button:nth-child(1) > .count",
"#search-tabs > button:nth-child(2) > .count",
("y")
["y"]
)
compare-elements-position: (
"#search-tabs > button:nth-child(2) > .count",
"#search-tabs > button:nth-child(3) > .count",
("y")
["y"]
)
// Check that counts are NOT beside the titles; now they have wrapped
compare-elements-position-near-false: (

View File

@ -6,7 +6,7 @@ fail-on-request-error: false
define-function: (
"check-setting",
(storage_value, setting_attribute_value, toggle_attribute_value),
[storage_value, setting_attribute_value, toggle_attribute_value],
block {
assert-local-storage: {"rustdoc-auto-hide-large-items": |storage_value|}
click: "#settings-menu"

View File

@ -3,7 +3,7 @@
define-function: (
"check-setting",
(storage_value, setting_attribute_value, toggle_attribute_value),
[storage_value, setting_attribute_value, toggle_attribute_value],
block {
assert-local-storage: {"rustdoc-auto-hide-method-docs": |storage_value|}
click: "#settings-menu"

View File

@ -2,7 +2,7 @@
define-function: (
"check-setting",
(storage_value, setting_attribute_value, toggle_attribute_value),
[storage_value, setting_attribute_value, toggle_attribute_value],
block {
assert-local-storage: {"rustdoc-auto-hide-trait-implementations": |storage_value|}
click: "#settings-menu"

View File

@ -2,7 +2,7 @@
define-function: (
"check-setting",
(storage_value, setting_attribute_value),
[storage_value, setting_attribute_value],
block {
assert-local-storage: {"rustdoc-go-to-only-result": |storage_value|}
click: "#settings-menu"
@ -32,7 +32,7 @@ assert-local-storage: {"rustdoc-go-to-only-result": "true"}
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
// We enter it into the search.
write: (".search-input", "HasALongTraitWithParams")
write-into: (".search-input", "HasALongTraitWithParams")
wait-for-document-property: {"title": "HasALongTraitWithParams in lib2 - Rust"}
assert-window-property: ({"location": "/lib2/struct.HasALongTraitWithParams.html"}, ENDS_WITH)

View File

@ -304,7 +304,7 @@ wait-for: "#settings"
assert-css: (".setting-radio", {"cursor": "pointer"})
assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
compare-elements-position: (".sub form", "#settings", ("x"))
compare-elements-position: (".sub form", "#settings", ["x"])
// Check that setting-line has the same margin in this mode as in the popover.
assert-css: (".setting-line", {"margin": |setting_line_margin|})

View File

@ -6,12 +6,12 @@ show-text: true
define-function: (
"check-colors",
(
[
theme, struct, struct_hover, struct_hover_background, enum, enum_hover,
enum_hover_background, union, union_hover, union_hover_background, trait, trait_hover,
trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover,
type_hover_background, keyword, keyword_hover, keyword_hover_background,
),
],
block {
set-local-storage: { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }
reload:

View File

@ -57,7 +57,7 @@ show-text: true
define-function: (
"check-colors",
(theme, color, background),
[theme, color, background],
block {
set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
reload:

View File

@ -30,9 +30,9 @@ show-text: true
define-function: (
"check-colors",
(
[
theme, color, color_hover, background, background_hover, background_toggle,
),
],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:

View File

@ -6,7 +6,7 @@ show-text: true
// First, check the sidebar colors.
define-function: (
"check-colors",
(theme, color, background_color),
[theme, color, background_color],
block {
set-local-storage: {
"rustdoc-theme": |theme|,

View File

@ -6,7 +6,7 @@ show-text: true
// First, check the sidebar colors.
define-function: (
"check-colors",
(theme, color, background_color),
[theme, color, background_color],
block {
set-local-storage: {
"rustdoc-theme": |theme|,

View File

@ -21,7 +21,7 @@ assert-attribute-false: (".src-line-numbers > a:nth-child(7)", {"class": "line-h
define-function: (
"check-colors",
(theme, color, background_color, highlight_color, highlight_background_color),
[theme, color, background_color, highlight_color, highlight_background_color],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:
@ -61,7 +61,7 @@ call-function: ("check-colors", {
})
// This is to ensure that the content is correctly align with the line numbers.
compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
compare-elements-position: ("//*[@id='1']", ".rust > code > span", ["y"])
// Check the `href` property so that users can treat anchors as links.
assert-property: (".src-line-numbers > a:nth-child(1)", {
"href": |DOC_PATH| + "/src/test_docs/lib.rs.html#1"
@ -122,7 +122,7 @@ store-property: (
)
define-function: (
"check-sidebar-dir-entry",
(x, y),
[x, y],
block {
assert: "details:first-of-type.dir-entry[open] > summary::marker"
assert-css: ("#src-sidebar > details:first-of-type.dir-entry", {"padding-left": "4px"})

View File

@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
show-text: true
define-function: (
"check-badge",
(theme, background, color),
[theme, background, color],
block {
set-local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": |theme|}
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"

View File

@ -7,7 +7,7 @@ assert: "#method\.a_method:target"
define-function: (
"check-style",
(theme, background, border),
[theme, background, border],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:

View File

@ -49,7 +49,7 @@ assert-attribute: ("details.toggle", {"open": ""}, ALL)
show-text: true
define-function: (
"check-color",
(theme, filter),
[theme, filter],
block {
// Setting the theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}

View File

@ -47,18 +47,18 @@ assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
// On desktop, they wrap when too big.
set-window-size: (1100, 800)
go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ("y"))
compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ["y"])
// make sure there is a gap between them
compare-elements-position-near-false: (".main-heading h1", ".main-heading .out-of-band", {"x": 550})
// On mobile, they always wrap.
set-window-size: (600, 600)
go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ("y"))
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
// Now we will check that the scrolling is working.
// First on an item with "hidden methods".

View File

@ -13,7 +13,7 @@ define-function: (
"sup-check",
// `theme` is the theme being tested.
// `color` is the expected color of the `<sup>` element.
(theme, color),
[theme, color],
block {
// Set the theme.
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
@ -23,6 +23,15 @@ define-function: (
},
)
call-function: ("sup-check", ("ayu", "#c5c5c5"))
call-function: ("sup-check", ("dark", "#ddd"))
call-function: ("sup-check", ("light", "black"))
call-function: ("sup-check", {
"theme": "ayu",
"color": "#c5c5c5",
})
call-function: ("sup-check", {
"theme": "dark",
"color": "#ddd",
})
call-function: ("sup-check", {
"theme": "light",
"color": "black",
})

View File

@ -5,7 +5,7 @@ show-text: true
store-value: (default_y_pos, 5)
define-function: (
"check-warning",
(theme, color, border_color),
[theme, color, border_color],
block {
set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}
reload:

View File

@ -3,25 +3,25 @@ go-to: "file://" + |DOC_PATH| + "/lib2/trait.Whitespace.html"
show-text: true
// First, we check in the trait definition if the where clause is "on its own" (not on the same
// line than "pub trait Whitespace<Idx>").
compare-elements-position-false: (".item-decl code", "div.where", ("y"))
compare-elements-position-false: (".item-decl code", "div.where", ["y"])
// And that the code following it isn't on the same line either.
compare-elements-position-false: (".item-decl .fn", "div.where", ("y"))
compare-elements-position-false: (".item-decl .fn", "div.where", ["y"])
go-to: "file://" + |DOC_PATH| + "/lib2/struct.WhereWhitespace.html"
// We make the screen a bit wider to ensure that the trait impl is on one line.
set-window-size: (915, 915)
compare-elements-position-false: ("#method\.new .fn", "#method\.new div.where", ("y"))
compare-elements-position-false: ("#method\.new .fn", "#method\.new div.where", ["y"])
// We ensure that both the trait name and the struct name are on the same line in
// "impl<K, T> Whitespace<&K> for WhereWhitespace<T>".
compare-elements-position: (
"#trait-implementations-list .impl h3 .trait",
"#trait-implementations-list .impl h3 .struct",
("y"),
["y"],
)
// And we now check that the where condition isn't on the same line.
compare-elements-position-false: (
"#trait-implementations-list .impl h3 .trait",
"#trait-implementations-list .impl h3 div.where",
("y"),
["y"],
)

View File

@ -1,6 +1,6 @@
#![crate_name = "foo"]
// @hasraw 'search-index.js' 'Foo short link.'
// @hasraw 'search.desc/foo/foo-desc-0-.js' 'Foo short link.'
// @!hasraw - 'www.example.com'
// @!hasraw - 'More Foo.'

View File

@ -1,19 +0,0 @@
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> $DIR/const-extern-fn-requires-unsafe.rs:12:5
|
LL | foo();
| ^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
--> $DIR/const-extern-fn-requires-unsafe.rs:9:17
|
LL | let a: [u8; foo()];
| ^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -1,19 +0,0 @@
error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
--> $DIR/const-extern-fn-requires-unsafe.rs:12:5
|
LL | foo();
| ^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error[E0133]: call to unsafe function `foo` is unsafe and requires unsafe function or block
--> $DIR/const-extern-fn-requires-unsafe.rs:9:17
|
LL | let a: [u8; foo()];
| ^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -1,23 +0,0 @@
error[E0308]: mismatched types
--> $DIR/fn-ptr.rs:11:21
|
LL | #[target_feature(enable = "sse2")]
| ---------------------------------- `#[target_feature]` added here
...
LL | let foo: fn() = foo;
| ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
| |
| expected due to this
|
= note: expected fn pointer `fn()`
found fn item `fn() {foo}`
= note: fn items are distinct from fn pointers
= note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
help: consider casting to a fn pointer
|
LL | let foo: fn() = foo as fn();
| ~~~~~~~~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -1,23 +0,0 @@
error[E0308]: mismatched types
--> $DIR/fn-ptr.rs:11:21
|
LL | #[target_feature(enable = "sse2")]
| ---------------------------------- `#[target_feature]` added here
...
LL | let foo: fn() = foo;
| ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
| |
| expected due to this
|
= note: expected fn pointer `fn()`
found fn item `fn() {foo}`
= note: fn items are distinct from fn pointers
= note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
help: consider casting to a fn pointer
|
LL | let foo: fn() = foo as fn();
| ~~~~~~~~~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -1,115 +0,0 @@
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:28:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:31:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:34:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:41:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:44:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:51:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:54:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: bmi2
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:57:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: bmi2
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:65:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:70:15
|
LL | const _: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:74:15
|
LL | const _: () = sse2_and_fxsr();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
= note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error: call to function with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
--> $DIR/safe-calls.rs:82:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/safe-calls.rs:81:1
|
LL | unsafe fn needs_unsafe_block() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/safe-calls.rs:78:8
|
LL | #[deny(unsafe_op_in_unsafe_fn)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0133`.

View File

@ -1,115 +0,0 @@
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:28:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:31:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:34:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:41:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:44:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:51:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:54:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: bmi2
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:57:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: bmi2
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:65:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:70:15
|
LL | const _: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:74:15
|
LL | const _: () = sse2_and_fxsr();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
= note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
error: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
--> $DIR/safe-calls.rs:82:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
note: an unsafe function restricts its caller, but its body is safe by default
--> $DIR/safe-calls.rs:81:1
|
LL | unsafe fn needs_unsafe_block() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: the lint level is defined here
--> $DIR/safe-calls.rs:78:8
|
LL | #[deny(unsafe_op_in_unsafe_fn)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0133`.