Skip to content

Commit

Permalink
Auto merge of #64044 - Mark-Simulacrum:rustdoc-clean-2, r=GuillaumeGomez
Browse files Browse the repository at this point in the history
Rustdoc: formatting to buffers

This should be reviewed commit-by-commit.

I've not attempted to fully flesh out what the end state of this PR could look like yet as I wanted to get it up for some early feedback (I already think this has some wins, too, so we could land it as-is).

The primary idea with `Buffer` is that it internally tracks whether we're printing to HTML or text, and the goal is that eventually instead of branch on `fmt.alternate()` anywhere, we'd call a helper like `buf.nbsp()` which would either return ` ` or ` ` depending on the target we're printing to. Obviously, that's not included in this PR, in part because it was already getting quite big.
  • Loading branch information
bors committed Sep 8, 2019
2 parents f7b05af + 02c5c5c commit 4a8ccdb
Show file tree
Hide file tree
Showing 4 changed files with 864 additions and 916 deletions.
110 changes: 102 additions & 8 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,100 @@ use crate::clean::{self, PrimitiveType};
use crate::html::item_type::ItemType;
use crate::html::render::{self, cache, CURRENT_DEPTH};

pub trait Print {
fn print(self, buffer: &mut Buffer);
}

impl<F> Print for F
where F: FnOnce(&mut Buffer),
{
fn print(self, buffer: &mut Buffer) {
(self)(buffer)
}
}

impl Print for String {
fn print(self, buffer: &mut Buffer) {
buffer.write_str(&self);
}
}

impl Print for &'_ str {
fn print(self, buffer: &mut Buffer) {
buffer.write_str(self);
}
}

#[derive(Debug, Clone)]
pub struct Buffer {
for_html: bool,
buffer: String,
}

impl Buffer {
crate fn empty_from(v: &Buffer) -> Buffer {
Buffer {
for_html: v.for_html,
buffer: String::new(),
}
}

crate fn html() -> Buffer {
Buffer {
for_html: true,
buffer: String::new(),
}
}

crate fn is_empty(&self) -> bool {
self.buffer.is_empty()
}

crate fn into_inner(self) -> String {
self.buffer
}

crate fn insert_str(&mut self, idx: usize, s: &str) {
self.buffer.insert_str(idx, s);
}

crate fn push_str(&mut self, s: &str) {
self.buffer.push_str(s);
}

// Intended for consumption by write! and writeln! (std::fmt) but without
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
// import).
crate fn write_str(&mut self, s: &str) {
self.buffer.push_str(s);
}

// Intended for consumption by write! and writeln! (std::fmt) but without
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
// import).
crate fn write_fmt(&mut self, v: fmt::Arguments<'_>) {
use fmt::Write;
self.buffer.write_fmt(v).unwrap();
}

crate fn to_display<T: Print>(mut self, t: T) -> String {
t.print(&mut self);
self.into_inner()
}

crate fn with_formatter<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result>(&mut self, t: T) {
self.from_display(display_fn(move |f| (t)(f)));
}

crate fn from_display<T: std::fmt::Display>(&mut self, t: T) {
if self.for_html {
write!(self, "{}", t);
} else {
write!(self, "{:#}", t);
}
}
}

/// Helper to render an optional visibility with a space after it (if the
/// visibility is preset)
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -200,11 +294,11 @@ impl<'a> fmt::Display for WhereClause<'a> {
}
&clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => {
clause.push_str(&format!("{}: {}",
lifetime,
bounds.iter()
.map(|b| b.to_string())
.collect::<Vec<_>>()
.join(" + ")));
lifetime,
bounds.iter()
.map(|b| b.to_string())
.collect::<Vec<_>>()
.join(" + ")));
}
&clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
if f.alternate() {
Expand Down Expand Up @@ -778,9 +872,9 @@ impl fmt::Display for clean::Impl {

// The difference from above is that trait is not hyperlinked.
pub fn fmt_impl_for_trait_page(i: &clean::Impl,
f: &mut fmt::Formatter<'_>,
use_absolute: bool) -> fmt::Result {
fmt_impl(i, f, false, use_absolute)
f: &mut Buffer,
use_absolute: bool) {
f.with_formatter(|f| fmt_impl(i, f, false, use_absolute))
}

impl fmt::Display for clean::Arguments {
Expand Down
35 changes: 18 additions & 17 deletions src/librustdoc/html/layout.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use std::fmt;
use std::io;
use std::path::PathBuf;

use crate::externalfiles::ExternalHtml;
use crate::html::render::SlashChecker;
use crate::html::format::{Buffer, Print};

#[derive(Clone)]
pub struct Layout {
pub logo: String,
pub favicon: String,
pub external_html: ExternalHtml,
pub krate: String,
/// The given user css file which allow to customize the generated
/// documentation theme.
pub css_file_extension: Option<PathBuf>,
/// If false, the `select` element to have search filtering by crates on rendered docs
/// won't be generated.
pub generate_search_filter: bool,
}

pub struct Page<'a> {
Expand All @@ -25,19 +30,15 @@ pub struct Page<'a> {
pub static_extra_scripts: &'a [&'a str],
}

pub fn render<T: fmt::Display, S: fmt::Display>(
dst: &mut dyn io::Write,
pub fn render<T: Print, S: Print>(
layout: &Layout,
page: &Page<'_>,
sidebar: &S,
t: &T,
css_file_extension: bool,
sidebar: S,
t: T,
themes: &[PathBuf],
generate_search_filter: bool,
) -> io::Result<()> {
) -> String {
let static_root_path = page.static_root_path.unwrap_or(page.root_path);
write!(dst,
"<!DOCTYPE html>\
format!("<!DOCTYPE html>\
<html lang=\"en\">\
<head>\
<meta charset=\"utf-8\">\
Expand Down Expand Up @@ -164,7 +165,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
<script defer src=\"{root_path}search-index{suffix}.js\"></script>\
</body>\
</html>",
css_extension = if css_file_extension {
css_extension = if layout.css_file_extension.is_some() {
format!("<link rel=\"stylesheet\" \
type=\"text/css\" \
href=\"{static_root_path}theme{suffix}.css\">",
Expand All @@ -173,7 +174,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
} else {
String::new()
},
content = *t,
content = Buffer::html().to_display(t),
static_root_path = static_root_path,
root_path = page.root_path,
css_class = page.css_class,
Expand Down Expand Up @@ -207,7 +208,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
in_header = layout.external_html.in_header,
before_content = layout.external_html.before_content,
after_content = layout.external_html.after_content,
sidebar = *sidebar,
sidebar = Buffer::html().to_display(sidebar),
krate = layout.krate,
themes = themes.iter()
.filter_map(|t| t.file_stem())
Expand All @@ -228,7 +229,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
root_path=page.root_path,
extra_script=e)
}).collect::<String>(),
filter_crates=if generate_search_filter {
filter_crates=if layout.generate_search_filter {
"<select id=\"crate-search\">\
<option value=\"All crates\">All crates</option>\
</select>"
Expand All @@ -238,9 +239,9 @@ pub fn render<T: fmt::Display, S: fmt::Display>(
)
}

pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> {
pub fn redirect(url: &str) -> String {
// <script> triggers a redirect before refresh, so this is fine.
write!(dst,
format!(
r##"<!DOCTYPE html>
<html lang="en">
<head>
Expand Down
Loading

0 comments on commit 4a8ccdb

Please sign in to comment.