Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render source page layout with Askama #109187

Merged
merged 2 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 21 additions & 38 deletions src/librustdoc/html/highlight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,23 +65,6 @@ pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
write!(out, "</pre>");
}

/// Highlights `src` as a source code page, returning the HTML output.
pub(crate) fn render_source_with_highlighting(
src: &str,
out: &mut Buffer,
line_numbers: Buffer,
href_context: HrefContext<'_, '_>,
decoration_info: DecorationInfo,
extra: Option<&str>,
) {
write_header(out, "", Some(line_numbers), Tooltip::None);
if let Some(extra) = extra {
out.push_str(extra);
}
write_code(out, src, Some(href_context), Some(decoration_info));
write_footer(out, None);
}

fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>, tooltip: Tooltip) {
write!(
out,
Expand Down Expand Up @@ -143,8 +126,8 @@ fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {

/// This type is used as a conveniency to prevent having to pass all its fields as arguments into
/// the various functions (which became its methods).
struct TokenHandler<'a, 'tcx> {
out: &'a mut Buffer,
struct TokenHandler<'a, 'tcx, F: Write> {
out: &'a mut F,
/// It contains the closing tag and the associated `Class`.
closing_tags: Vec<(&'static str, Class)>,
/// This is used because we don't automatically generate the closing tag on `ExitSpan` in
Expand All @@ -159,7 +142,7 @@ struct TokenHandler<'a, 'tcx> {
href_context: Option<HrefContext<'a, 'tcx>>,
}

impl<'a, 'tcx> TokenHandler<'a, 'tcx> {
impl<'a, 'tcx, F: Write> TokenHandler<'a, 'tcx, F> {
fn handle_exit_span(&mut self) {
// We can't get the last `closing_tags` element using `pop()` because `closing_tags` is
// being used in `write_pending_elems`.
Expand Down Expand Up @@ -211,7 +194,7 @@ impl<'a, 'tcx> TokenHandler<'a, 'tcx> {
}
}

impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> {
impl<'a, 'tcx, F: Write> Drop for TokenHandler<'a, 'tcx, F> {
/// When leaving, we need to flush all pending data to not have missing content.
fn drop(&mut self) {
if self.pending_exit_span.is_some() {
Expand All @@ -233,8 +216,8 @@ impl<'a, 'tcx> Drop for TokenHandler<'a, 'tcx> {
/// item definition.
///
/// More explanations about spans and how we use them here are provided in the
fn write_code(
out: &mut Buffer,
pub(super) fn write_code(
out: &mut impl Write,
src: &str,
href_context: Option<HrefContext<'_, '_>>,
decoration_info: Option<DecorationInfo>,
Expand Down Expand Up @@ -883,7 +866,7 @@ impl<'src> Classifier<'src> {
/// Called when we start processing a span of text that should be highlighted.
/// The `Class` argument specifies how it should be highlighted.
fn enter_span(
out: &mut Buffer,
out: &mut impl Write,
klass: Class,
href_context: &Option<HrefContext<'_, '_>>,
) -> &'static str {
Expand All @@ -894,8 +877,8 @@ fn enter_span(
}

/// Called at the end of a span of highlighted text.
fn exit_span(out: &mut Buffer, closing_tag: &str) {
out.write_str(closing_tag);
fn exit_span(out: &mut impl Write, closing_tag: &str) {
out.write_str(closing_tag).unwrap();
}

/// Called for a span of text. If the text should be highlighted differently
Expand All @@ -915,15 +898,15 @@ fn exit_span(out: &mut Buffer, closing_tag: &str) {
/// will then try to find this `span` in the `span_correspondance_map`. If found, it'll then
/// generate a link for this element (which corresponds to where its definition is located).
fn string<T: Display>(
out: &mut Buffer,
out: &mut impl Write,
text: T,
klass: Option<Class>,
href_context: &Option<HrefContext<'_, '_>>,
open_tag: bool,
) {
if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
{
out.write_str(closing_tag);
out.write_str(closing_tag).unwrap();
}
}

Expand All @@ -937,24 +920,24 @@ fn string<T: Display>(
/// in `span_map.rs::collect_spans_and_sources`. If it cannot retrieve the information, then it's
/// the same as the second point (`klass` is `Some` but doesn't have a [`rustc_span::Span`]).
fn string_without_closing_tag<T: Display>(
out: &mut Buffer,
out: &mut impl Write,
text: T,
klass: Option<Class>,
href_context: &Option<HrefContext<'_, '_>>,
open_tag: bool,
) -> Option<&'static str> {
let Some(klass) = klass
else {
write!(out, "{}", text);
write!(out, "{}", text).unwrap();
return None;
};
let Some(def_span) = klass.get_span()
else {
if !open_tag {
write!(out, "{}", text);
write!(out, "{}", text).unwrap();
return None;
}
write!(out, "<span class=\"{}\">{}", klass.as_html(), text);
write!(out, "<span class=\"{}\">{}", klass.as_html(), text).unwrap();
return Some("</span>");
};

Expand Down Expand Up @@ -1009,28 +992,28 @@ fn string_without_closing_tag<T: Display>(
if !open_tag {
// We're already inside an element which has the same klass, no need to give it
// again.
write!(out, "<a href=\"{}\">{}", href, text_s);
write!(out, "<a href=\"{}\">{}", href, text_s).unwrap();
} else {
let klass_s = klass.as_html();
if klass_s.is_empty() {
write!(out, "<a href=\"{}\">{}", href, text_s);
write!(out, "<a href=\"{}\">{}", href, text_s).unwrap();
} else {
write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s);
write!(out, "<a class=\"{}\" href=\"{}\">{}", klass_s, href, text_s).unwrap();
}
}
return Some("</a>");
}
}
if !open_tag {
write!(out, "{}", text_s);
write!(out, "{}", text_s).unwrap();
return None;
}
let klass_s = klass.as_html();
if klass_s.is_empty() {
write!(out, "{}", text_s);
out.write_str(&text_s).unwrap();
Some("")
} else {
write!(out, "<span class=\"{}\">{}", klass_s, text_s);
write!(out, "<span class=\"{}\">{}", klass_s, text_s).unwrap();
Some("</span>")
}
}
Expand Down
58 changes: 27 additions & 31 deletions src/librustdoc/html/sources.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::clean;
use crate::docfs::PathError;
use crate::error::Error;
use crate::html::format;
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::layout;
use crate::html::render::Context;
use crate::visit::DocVisitor;

use askama::Template;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
Expand All @@ -16,6 +18,7 @@ use rustc_span::source_map::FileName;
use std::cell::RefCell;
use std::ffi::OsStr;
use std::fs;
use std::ops::RangeInclusive;
use std::path::{Component, Path, PathBuf};
use std::rc::Rc;

Expand Down Expand Up @@ -299,39 +302,32 @@ pub(crate) fn print_src(
decoration_info: highlight::DecorationInfo,
source_context: SourceContext,
) {
#[derive(Template)]
#[template(path = "source.html")]
struct Source<Code: std::fmt::Display> {
embedded: bool,
needs_expansion: bool,
lines: RangeInclusive<usize>,
code_html: Code,
}
let lines = s.lines().count();
let mut line_numbers = Buffer::empty_from(buf);
let extra;
line_numbers.write_str("<pre class=\"src-line-numbers\">");
let (embedded, needs_expansion, lines) = match source_context {
SourceContext::Standalone => (false, false, 1..=lines),
SourceContext::Embedded { offset, needs_expansion } => {
(true, needs_expansion, (1 + offset)..=(lines + offset))
}
};
let current_href = context
.href_from_span(clean::Span::new(file_span), false)
.expect("only local crates should have sources emitted");
match source_context {
SourceContext::Standalone => {
extra = None;
for line in 1..=lines {
writeln!(line_numbers, "<a href=\"#{line}\" id=\"{line}\">{line}</a>")
}
}
SourceContext::Embedded { offset, needs_expansion } => {
extra = if needs_expansion {
Some(r#"<button class="expand">&varr;</button>"#)
} else {
None
};
for line_number in 1..=lines {
let line = line_number + offset;
writeln!(line_numbers, "<span>{line}</span>")
}
}
}
line_numbers.write_str("</pre>");
highlight::render_source_with_highlighting(
s,
buf,
line_numbers,
highlight::HrefContext { context, file_span, root_path, current_href },
decoration_info,
extra,
);
let code = format::display_fn(move |fmt| {
highlight::write_code(
fmt,
s,
Some(highlight::HrefContext { context, file_span, root_path, current_href }),
Some(decoration_info),
);
Ok(())
});
Source { embedded, needs_expansion, lines, code_html: code }.render_into(buf).unwrap();
}
19 changes: 19 additions & 0 deletions src/librustdoc/html/templates/source.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div class="example-wrap"> {# #}
<pre class="src-line-numbers">
{% for line in lines.clone() %}
clubby789 marked this conversation as resolved.
Show resolved Hide resolved
{% if embedded %}
<span>{{line|safe}}</span>
{%~ else %}
<a href="#{{line|safe}}" id="{{line|safe}}">{{line|safe}}</a>
{%~ endif %}
{% endfor %}
</pre> {# #}
<pre class="rust"> {# #}
<code>
{% if needs_expansion %}
<button class="expand">&varr;</button>
{% endif %}
{{code_html|safe}}
</code> {# #}
</pre> {# #}
</div>