Skip to content

Commit c85386c

Browse files
Put the navigation back!
1 parent e8d4c31 commit c85386c

File tree

7 files changed

+256
-32
lines changed

7 files changed

+256
-32
lines changed

Cargo.lock

Lines changed: 173 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ badge = { version = "0", path = "src/web/badge" }
2828
error-chain = "0.10"
2929
comrak = { version = "0.2.10", default-features = false }
3030
toml = "0.4"
31+
html5ever = "0.22"
3132

3233
# iron dependencies
3334
iron = "0.5"

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ extern crate badge;
2828
extern crate crates_index_diff;
2929
extern crate git2;
3030
extern crate toml;
31+
extern crate html5ever;
3132

3233
pub use self::docbuilder::DocBuilder;
3334
pub use self::docbuilder::ChrootBuilderResult;

src/utils/html.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use error::{Result, Error};
2+
3+
use html5ever::serialize::{serialize, SerializeOpts};
4+
use html5ever::rcdom::{RcDom, NodeData, Handle};
5+
use html5ever::driver::{parse_document, ParseOpts};
6+
use html5ever::tendril::TendrilSink;
7+
8+
/// Extracts the contents of the `<head>` and `<body>` tags from an HTML document.
9+
pub fn extract_head_and_body(html: &str) -> Result<(String, String)> {
10+
let parser = parse_document(RcDom::default(), ParseOpts::default());
11+
let dom = parser.one(html);
12+
13+
let (head, body) = extract_from_rcdom(&dom)?;
14+
15+
Ok((stringify(head), stringify(body)))
16+
}
17+
18+
fn extract_from_rcdom(dom: &RcDom) -> Result<(Handle, Handle)> {
19+
let mut worklist = vec![dom.document.clone()];
20+
let (mut head, mut body) = (None, None);
21+
22+
while let Some(handle) = worklist.pop() {
23+
match handle.data {
24+
NodeData::Element { ref name, .. } => match name.local.as_ref() {
25+
"head" => {
26+
if head.is_some() {
27+
return Err("duplicate <head> tag".into());
28+
} else {
29+
head = Some(handle.clone());
30+
}
31+
}
32+
"body" => {
33+
if body.is_some() {
34+
return Err("duplicate <body> tag".into());
35+
} else {
36+
body = Some(handle.clone());
37+
}
38+
}
39+
_ => {} // do nothing
40+
}
41+
_ => {} // do nothing
42+
}
43+
44+
worklist.extend(handle.children.borrow().iter().cloned());
45+
}
46+
47+
let head = head.ok_or_else(|| Error::from("couldn't find <head> tag in rustdoc output"))?;
48+
let body = body.ok_or_else(|| Error::from("couldn't find <body> tag in rustdoc output"))?;
49+
Ok((head, body))
50+
}
51+
52+
fn stringify(node: Handle) -> String {
53+
let mut vec = Vec::new();
54+
serialize(&mut vec, &node, SerializeOpts::default())
55+
.expect("serializing into buffer failed");
56+
57+
String::from_utf8(vec).expect("html5ever returned non-utf8 data")
58+
}

src/utils/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub use self::github_updater::github_updater;
77
pub use self::release_activity_updater::update_release_activity;
88
pub use self::daemon::start_daemon;
99
pub use self::rustc_version::{parse_rustc_version, get_current_versions, command_result};
10+
pub use self::html::extract_head_and_body;
1011

1112
mod github_updater;
1213
mod build_doc;
@@ -15,3 +16,4 @@ mod release_activity_updater;
1516
mod daemon;
1617
mod pubsubhubbub;
1718
mod rustc_version;
19+
mod html;

src/web/rustdoc.rs

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::collections::BTreeMap;
1717
use iron::headers::{Expires, HttpDate, CacheControl, CacheDirective};
1818
use time;
1919
use iron::Handler;
20+
use utils;
2021

2122

2223
#[derive(Debug)]
@@ -155,34 +156,13 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {
155156
return Ok(file.serve());
156157
}
157158

158-
let (mut in_head, mut in_body) = (false, false);
159-
160159
let mut content = RustdocPage::default();
161160

162161
let file_content = ctry!(String::from_utf8(file.content));
163162

164-
for line in file_content.lines() {
165-
166-
if line.starts_with("<head") {
167-
in_head = true;
168-
continue;
169-
} else if line.starts_with("</head") {
170-
in_head = false;
171-
} else if line.starts_with("<body") {
172-
in_body = true;
173-
continue;
174-
} else if line.starts_with("</body") {
175-
in_body = false;
176-
}
177-
178-
if in_head {
179-
content.head.push_str(&line[..]);
180-
content.head.push('\n');
181-
} else if in_body {
182-
content.body.push_str(&line[..]);
183-
content.body.push('\n');
184-
}
185-
}
163+
let (head, body) = ctry!(utils::extract_head_and_body(&file_content));
164+
content.head = head;
165+
content.body = body;
186166

187167
content.full = file_content;
188168
let crate_details = cexpect!(CrateDetails::new(&conn, &name, &version));

templates/rustdoc.hbs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1-
{{{content.rustdoc_full}}}
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
{{{content.rustdoc_head}}}
5+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pure/0.6.0/menus-min.css" type="text/css" media="all" />
6+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pure/0.6.0/grids-min.css" type="text/css" media="all" />
7+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css" type="text/css" media="all" />
8+
<link rel="stylesheet" href="/style.css?{{cratesfyi_version_safe}}" type="text/css" media="all" />
9+
<link rel="search" href="/opensearch.xml" type="application/opensearchdescription+xml" title="Docs.rs">
10+
</head>
11+
<body>
12+
{{> navigation_rustdoc}}
13+
<div class="rustdoc container-rustdoc">
14+
{{{content.rustdoc_body}}}
15+
</div>
16+
</body>
17+
</html>

0 commit comments

Comments
 (0)