rustdoc: Represent item types as a small number in the search index.

Has negligible improvements with gzip, but saves about 7% without it.
This also has an effect of changing the tie-breaking order of item types.
This commit is contained in:
Kang Seonghoon
2014-04-09 16:49:31 +09:00
parent ab6915d7b5
commit f1de04c760
5 changed files with 158 additions and 49 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at // file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT. // http://rust-lang.org/COPYRIGHT.
// //
@@ -24,6 +24,8 @@ use syntax::ast;
use syntax::ast_util; use syntax::ast_util;
use clean; use clean;
use html::item_type;
use html::item_type::ItemType;
use html::render; use html::render;
use html::render::{cache_key, current_location_key}; use html::render::{cache_key, current_location_key};
@@ -172,17 +174,17 @@ fn external_path(w: &mut io::Writer, p: &clean::Path, print_all: bool,
}, },
|_cache| { |_cache| {
Some((Vec::from_slice(fqn), match kind { Some((Vec::from_slice(fqn), match kind {
clean::TypeStruct => "struct", clean::TypeStruct => item_type::Struct,
clean::TypeEnum => "enum", clean::TypeEnum => item_type::Enum,
clean::TypeFunction => "fn", clean::TypeFunction => item_type::Function,
clean::TypeTrait => "trait", clean::TypeTrait => item_type::Trait,
})) }))
}) })
} }
fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool, fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
root: |&render::Cache, &[~str]| -> Option<~str>, root: |&render::Cache, &[~str]| -> Option<~str>,
info: |&render::Cache| -> Option<(Vec<~str> , &'static str)>) info: |&render::Cache| -> Option<(Vec<~str> , ItemType)>)
-> fmt::Result -> fmt::Result
{ {
// The generics will get written to both the title and link // The generics will get written to both the title and link
@@ -252,12 +254,12 @@ fn path(w: &mut io::Writer, path: &clean::Path, print_all: bool,
url.push_str("/"); url.push_str("/");
} }
match shortty { match shortty {
"mod" => { item_type::Module => {
url.push_str(*fqp.last().unwrap()); url.push_str(*fqp.last().unwrap());
url.push_str("/index.html"); url.push_str("/index.html");
} }
_ => { _ => {
url.push_str(shortty); url.push_str(shortty.to_static_str());
url.push_str("."); url.push_str(".");
url.push_str(*fqp.last().unwrap()); url.push_str(*fqp.last().unwrap());
url.push_str(".html"); url.push_str(".html");

View File

@@ -0,0 +1,97 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Item types.
use std::fmt;
use clean;
/// Item type. Corresponds to `clean::ItemEnum` variants.
///
/// The search index uses item types encoded as smaller numbers which equal to
/// discriminants. JavaScript then is used to decode them into the original value.
/// Consequently, every change to this type should be synchronized to
/// the `itemTypes` mapping table in `static/main.js`.
#[deriving(Eq, Clone)]
pub enum ItemType {
Module = 0,
Struct = 1,
Enum = 2,
Function = 3,
Typedef = 4,
Static = 5,
Trait = 6,
Impl = 7,
ViewItem = 8,
TyMethod = 9,
Method = 10,
StructField = 11,
Variant = 12,
ForeignFunction = 13,
ForeignStatic = 14,
Macro = 15,
}
impl ItemType {
pub fn to_static_str(&self) -> &'static str {
match *self {
Module => "mod",
Struct => "struct",
Enum => "enum",
Function => "fn",
Typedef => "typedef",
Static => "static",
Trait => "trait",
Impl => "impl",
ViewItem => "viewitem",
TyMethod => "tymethod",
Method => "method",
StructField => "structfield",
Variant => "variant",
ForeignFunction => "ffi",
ForeignStatic => "ffs",
Macro => "macro",
}
}
}
impl fmt::Show for ItemType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_static_str().fmt(f)
}
}
impl fmt::Unsigned for ItemType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(*self as uint).fmt(f)
}
}
pub fn shortty(item: &clean::Item) -> ItemType {
match item.inner {
clean::ModuleItem(..) => Module,
clean::StructItem(..) => Struct,
clean::EnumItem(..) => Enum,
clean::FunctionItem(..) => Function,
clean::TypedefItem(..) => Typedef,
clean::StaticItem(..) => Static,
clean::TraitItem(..) => Trait,
clean::ImplItem(..) => Impl,
clean::ViewItemItem(..) => ViewItem,
clean::TyMethodItem(..) => TyMethod,
clean::MethodItem(..) => Method,
clean::StructFieldItem(..) => StructField,
clean::VariantItem(..) => Variant,
clean::ForeignFunctionItem(..) => ForeignFunction,
clean::ForeignStaticItem(..) => ForeignStatic,
clean::MacroItem(..) => Macro,
}
}

View File

@@ -52,6 +52,8 @@ use rustc::util::nodemap::NodeSet;
use clean; use clean;
use doctree; use doctree;
use fold::DocFolder; use fold::DocFolder;
use html::item_type;
use html::item_type::{ItemType, shortty};
use html::format::{VisSpace, Method, FnStyleSpace}; use html::format::{VisSpace, Method, FnStyleSpace};
use html::layout; use html::layout;
use html::markdown; use html::markdown;
@@ -138,7 +140,7 @@ pub struct Cache {
/// URLs when a type is being linked to. External paths are not located in /// URLs when a type is being linked to. External paths are not located in
/// this map because the `External` type itself has all the information /// this map because the `External` type itself has all the information
/// necessary. /// necessary.
pub paths: HashMap<ast::NodeId, (Vec<~str> , &'static str)>, pub paths: HashMap<ast::NodeId, (Vec<~str> , ItemType)>,
/// This map contains information about all known traits of this crate. /// This map contains information about all known traits of this crate.
/// Implementations of a crate should inherit the documentation of the /// Implementations of a crate should inherit the documentation of the
@@ -193,7 +195,7 @@ struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
/// Struct representing one entry in the JS search index. These are all emitted /// Struct representing one entry in the JS search index. These are all emitted
/// by hand to a large JS file at the end of cache-creation. /// by hand to a large JS file at the end of cache-creation.
struct IndexItem { struct IndexItem {
ty: &'static str, ty: ItemType,
name: ~str, name: ~str,
path: ~str, path: ~str,
desc: ~str, desc: ~str,
@@ -311,7 +313,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
if i > 0 { if i > 0 {
try!(write!(&mut w, ",")); try!(write!(&mut w, ","));
} }
try!(write!(&mut w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}", try!(write!(&mut w, "\\{ty:{:u},name:\"{}\",path:\"{}\",desc:{}",
item.ty, item.name, item.path, item.ty, item.name, item.path,
item.desc.to_json().to_str())); item.desc.to_json().to_str()));
match item.parent { match item.parent {
@@ -330,7 +332,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
if i > 0 { if i > 0 {
try!(write!(&mut w, ",")); try!(write!(&mut w, ","));
} }
try!(write!(&mut w, "\\{type:'{}',name:'{}'\\}", try!(write!(&mut w, "\\{type:{:u},name:'{}'\\}",
short, *fqp.last().unwrap())); short, *fqp.last().unwrap()));
} }
try!(write!(&mut w, "];")); try!(write!(&mut w, "];"));
@@ -622,12 +624,13 @@ impl DocFolder for Cache {
} else { } else {
let last = self.parent_stack.last().unwrap(); let last = self.parent_stack.last().unwrap();
let path = match self.paths.find(last) { let path = match self.paths.find(last) {
Some(&(_, "trait")) => Some(&(_, item_type::Trait)) =>
Some(self.stack.slice_to(self.stack.len() - 1)), Some(self.stack.slice_to(self.stack.len() - 1)),
// The current stack not necessarily has correlation for // The current stack not necessarily has correlation for
// where the type was defined. On the other hand, // where the type was defined. On the other hand,
// `paths` always has the right information if present. // `paths` always has the right information if present.
Some(&(ref fqp, "struct")) | Some(&(ref fqp, "enum")) => Some(&(ref fqp, item_type::Struct)) |
Some(&(ref fqp, item_type::Enum)) =>
Some(fqp.slice_to(fqp.len() - 1)), Some(fqp.slice_to(fqp.len() - 1)),
Some(..) => Some(self.stack.as_slice()), Some(..) => Some(self.stack.as_slice()),
None => None None => None
@@ -687,7 +690,7 @@ impl DocFolder for Cache {
clean::VariantItem(..) => { clean::VariantItem(..) => {
let mut stack = self.stack.clone(); let mut stack = self.stack.clone();
stack.pop(); stack.pop();
self.paths.insert(item.id, (stack, "enum")); self.paths.insert(item.id, (stack, item_type::Enum));
} }
_ => {} _ => {}
} }
@@ -845,7 +848,7 @@ impl Context {
} }
title.push_str(" - Rust"); title.push_str(" - Rust");
let page = layout::Page { let page = layout::Page {
ty: shortty(it), ty: shortty(it).to_static_str(),
root_path: cx.root_path.as_slice(), root_path: cx.root_path.as_slice(),
title: title.as_slice(), title: title.as_slice(),
}; };
@@ -899,27 +902,6 @@ impl Context {
} }
} }
fn shortty(item: &clean::Item) -> &'static str {
match item.inner {
clean::ModuleItem(..) => "mod",
clean::StructItem(..) => "struct",
clean::EnumItem(..) => "enum",
clean::FunctionItem(..) => "fn",
clean::TypedefItem(..) => "typedef",
clean::StaticItem(..) => "static",
clean::TraitItem(..) => "trait",
clean::ImplItem(..) => "impl",
clean::ViewItemItem(..) => "viewitem",
clean::TyMethodItem(..) => "tymethod",
clean::MethodItem(..) => "method",
clean::StructFieldItem(..) => "structfield",
clean::VariantItem(..) => "variant",
clean::ForeignFunctionItem(..) => "ffi",
clean::ForeignStaticItem(..) => "ffs",
clean::MacroItem(..) => "macro",
}
}
impl<'a> Item<'a> { impl<'a> Item<'a> {
fn ismodule(&self) -> bool { fn ismodule(&self) -> bool {
match self.item.inner { match self.item.inner {
@@ -1009,7 +991,7 @@ impl<'a> fmt::Show for Item<'a> {
fn item_path(item: &clean::Item) -> ~str { fn item_path(item: &clean::Item) -> ~str {
match item.inner { match item.inner {
clean::ModuleItem(..) => *item.name.get_ref() + "/index.html", clean::ModuleItem(..) => *item.name.get_ref() + "/index.html",
_ => shortty(item) + "." + *item.name.get_ref() + ".html" _ => shortty(item).to_static_str() + "." + *item.name.get_ref() + ".html"
} }
} }
@@ -1095,13 +1077,13 @@ fn item_module(w: &mut Writer, cx: &Context,
indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2)); indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
debug!("{:?}", indices); debug!("{:?}", indices);
let mut curty = ""; let mut curty = None;
for &idx in indices.iter() { for &idx in indices.iter() {
let myitem = &items[idx]; let myitem = &items[idx];
let myty = shortty(myitem); let myty = Some(shortty(myitem));
if myty != curty { if myty != curty {
if curty != "" { if curty.is_some() {
try!(write!(w, "</table>")); try!(write!(w, "</table>"));
} }
curty = myty; curty = myty;
@@ -1704,8 +1686,9 @@ impl<'a> fmt::Show for Sidebar<'a> {
}; };
try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty)); try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty));
for item in items.iter() { for item in items.iter() {
let curty = shortty(cur).to_static_str();
let class = if cur.name.get_ref() == item && let class = if cur.name.get_ref() == item &&
short == shortty(cur) { "current" } else { "" }; short == curty { "current" } else { "" };
try!(write!(w, "<a class='{ty} {class}' href='{curty, select, try!(write!(w, "<a class='{ty} {class}' href='{curty, select,
mod{../} mod{../}
other{} other{}
@@ -1716,7 +1699,7 @@ impl<'a> fmt::Show for Sidebar<'a> {
ty = short, ty = short,
tysel = short, tysel = short,
class = class, class = class,
curty = shortty(cur), curty = curty,
name = item.as_slice())); name = item.as_slice()));
} }
try!(write!(w, "</div>")); try!(write!(w, "</div>"));
@@ -1735,7 +1718,7 @@ impl<'a> fmt::Show for Sidebar<'a> {
fn build_sidebar(m: &clean::Module) -> HashMap<~str, Vec<~str> > { fn build_sidebar(m: &clean::Module) -> HashMap<~str, Vec<~str> > {
let mut map = HashMap::new(); let mut map = HashMap::new();
for item in m.items.iter() { for item in m.items.iter() {
let short = shortty(item); let short = shortty(item).to_static_str();
let myname = match item.name { let myname = match item.name {
None => continue, None => continue,
Some(ref s) => s.to_owned(), Some(ref s) => s.to_owned(),

View File

@@ -135,7 +135,7 @@
function execQuery(query, max, searchWords) { function execQuery(query, max, searchWords) {
var valLower = query.query.toLowerCase(), var valLower = query.query.toLowerCase(),
val = valLower, val = valLower,
typeFilter = query.type, typeFilter = itemTypeFromName(query.type),
results = [], results = [],
split = valLower.split("::"); split = valLower.split("::");
@@ -156,7 +156,7 @@
for (var i = 0; i < nSearchWords; i += 1) { for (var i = 0; i < nSearchWords; i += 1) {
if (searchWords[i] === val) { if (searchWords[i] === val) {
// filter type: ... queries // filter type: ... queries
if (!typeFilter || typeFilter === searchIndex[i].ty) { if (typeFilter < 0 || typeFilter === searchIndex[i].ty) {
results.push({id: i, index: -1}); results.push({id: i, index: -1});
} }
} }
@@ -174,7 +174,7 @@
searchWords[j].replace(/_/g, "").indexOf(val) > -1) searchWords[j].replace(/_/g, "").indexOf(val) > -1)
{ {
// filter type: ... queries // filter type: ... queries
if (!typeFilter || typeFilter === searchIndex[j].ty) { if (typeFilter < 0 || typeFilter === searchIndex[j].ty) {
results.push({id: j, index: searchWords[j].replace(/_/g, "").indexOf(val)}); results.push({id: j, index: searchWords[j].replace(/_/g, "").indexOf(val)});
} }
} }
@@ -405,7 +405,7 @@
shown.push(item); shown.push(item);
name = item.name; name = item.name;
type = item.ty; type = itemTypes[item.ty];
output += '<tr class="' + type + ' result"><td>'; output += '<tr class="' + type + ' result"><td>';
@@ -427,7 +427,7 @@
output += item.path + '::' + myparent.name + output += item.path + '::' + myparent.name +
'::<a href="' + rootPath + '::<a href="' + rootPath +
item.path.replace(/::/g, '/') + item.path.replace(/::/g, '/') +
'/' + myparent.type + '/' + itemTypes[myparent.type] +
'.' + myparent.name + '.' + myparent.name +
'.html' + anchor + '.html' + anchor +
'" class="' + type + '" class="' + type +
@@ -505,6 +505,32 @@
showResults(results); showResults(results);
} }
// This mapping table should match the discriminants of
// `rustdoc::html::item_type::ItemType` type in Rust.
var itemTypes = ["mod",
"struct",
"enum",
"fn",
"typedef",
"static",
"trait",
"impl",
"viewitem",
"tymethod",
"method",
"structfield",
"variant",
"ffi",
"ffs",
"macro"];
function itemTypeFromName(typename) {
for (var i = 0; i < itemTypes.length; ++i) {
if (itemTypes[i] === typename) return i;
}
return -1;
}
function buildIndex(rawSearchIndex) { function buildIndex(rawSearchIndex) {
searchIndex = []; searchIndex = [];
var searchWords = []; var searchWords = [];

View File

@@ -41,6 +41,7 @@ pub mod fold;
pub mod html { pub mod html {
pub mod highlight; pub mod highlight;
pub mod escape; pub mod escape;
pub mod item_type;
pub mod format; pub mod format;
pub mod layout; pub mod layout;
pub mod markdown; pub mod markdown;