diff options
| author | clubby789 <jamie@hill-daniel.co.uk> | 2023-03-12 16:55:32 +0000 |
|---|---|---|
| committer | clubby789 <jamie@hill-daniel.co.uk> | 2023-03-16 14:33:51 +0000 |
| commit | 102c8fa29028e3fd501fe297a5d7edc86697f3d9 (patch) | |
| tree | 5614f3a01a1dcaf1b1bad88ccf642555ee8fb05a | |
| parent | 24c0b81c1fd5de8e00276524896d3352ed91a8cb (diff) | |
| download | rust-102c8fa29028e3fd501fe297a5d7edc86697f3d9.tar.gz rust-102c8fa29028e3fd501fe297a5d7edc86697f3d9.zip | |
Render source page layout with Askama
Co-authored-by: Michael Howell <michael@notriddle.com>
| -rw-r--r-- | src/librustdoc/html/highlight.rs | 59 | ||||
| -rw-r--r-- | src/librustdoc/html/sources.rs | 58 | ||||
| -rw-r--r-- | src/librustdoc/html/templates/source.html | 19 |
3 files changed, 67 insertions, 69 deletions
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 2c9fc4e3ca3..c099d0e4f3f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -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, @@ -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 @@ -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`. @@ -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() { @@ -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>, @@ -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 { @@ -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 @@ -915,7 +898,7 @@ 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<'_, '_>>, @@ -923,7 +906,7 @@ fn string<T: Display>( ) { 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(); } } @@ -937,7 +920,7 @@ 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<'_, '_>>, @@ -945,16 +928,16 @@ fn string_without_closing_tag<T: Display>( ) -> 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>"); }; @@ -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>") } } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 2c90bf4fadc..5161e8fe74d 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -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; @@ -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; @@ -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">↕</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(); } diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html new file mode 100644 index 00000000000..968b55ac158 --- /dev/null +++ b/src/librustdoc/html/templates/source.html @@ -0,0 +1,19 @@ +<div class="example-wrap"> {# #} + <pre class="src-line-numbers"> + {% for line in lines.clone() %} + {% if embedded %} + <span>{{line}}</span> + {%~ else %} + <a href="#{{line}}" id="{{line}}">{{line}}</a> + {%~ endif %} + {% endfor %} + </pre> {# #} + <pre class="rust"> {# #} + <code> + {% if needs_expansion %} + <button class="expand">↕</button> + {% endif %} + {{code_html|safe}} + </code> {# #} + </pre> {# #} +</div> |
