Open clubby789 opened 1 year ago
I'm working on fn assoc_method
and fn inner_full_print
.
I'm working on fn print_src
As part of this, I'd like to get rid of struct Buffer
and the f.alternate()
method of emitting text instead of HTML.
Rationale: Using Formatter::alternate()
to emit text instead of HTML was introduced to support line-wrapping function declarations over 80 characters. To this day, we only use f.alternate()
when emitting function / method declarations, and we only care about the number of characters emitted.
Buffer was introduced as an alternative to f.alternate()
: Instead of checking f.alternate()
repeatedly throughout format.rs
, the buffer itself could carry the information about whether we're outputting text or HTML. Removing the repeated checks of f.alternate()
is a good goal - they significantly complicate format.rs
. Also, Askama does not currently offer a way to access f.alternate()
or format with {:#}
, AFAICT. However, Buffer itself also doesn't compose well with Askama. Askama templates implement Display
; ideally we would want a stack of structures, each potentially containing other structs that implement Display
; then we can interpolate them directly into the parent template without excess allocations.
In the original PR adding f.alternate()
support for the purpose of line wrapping, generating and then stripping HTML was considered and discarded. But I think it's the right solution here. Because we control the HTML and because we only care about counting the text output, we can get away with a very simplified HTML processor that knows how to strip tags and count entities (e.g. &
) as a single character.
This is a summary of a similar comment I made on Zulip.
Update on the above: I missed a few places where we use {:#}
and actually emit the plain output:
Methods from Deref<Target = Foo>
, it's used to print the plain form of Deref
and Foo
.
I still think it makes sense to filter internally-generated HTML with a limited tag stripper, but it looks like we'll need to be able to actually emit the text rather than just count it, which means processing the entities (no big deal).
FWIW, feel free to tag me in reviews if there are questions. Excited to see more usage of Askama in rustdoc!
As part of this, I'd like to get rid of
struct Buffer
and thef.alternate()
method of emitting text instead of HTML.
As a potential point of interest, at work we have started using a very small procedural macro that effectively duplicates a template type to allow having two Template
s wrapped around the same input type, one for plaintext and one for HTML. So this:
#[email(template = "contact-email")]
pub struct DomainContactEmail<'a> {
pub domain: &'a str,
pub sender: &'a ContactSender<'a>,
pub message: &'a str,
pub inbox_url: &'a str,
}
expands to this:
impl<'a: 'email, 'email> email::BodyTemplates<'email> for DomainContactEmail<'a> {
type Text = DomainContactEmailText<'a, 'email>;
type Html = DomainContactEmailHtml<'a, 'email>;
}
#[derive(askama::Template)]
#[template(path = "contact-email.txt")]
pub struct DomainContactEmailText<'a, 'email>(&'email DomainContactEmail<'a>);
impl<'a: 'email, 'email> From<&'email DomainContactEmail<'a>>
for DomainContactEmailText<'a, 'email>
{
fn from(email: &'email DomainContactEmail<'a>) -> Self {
Self(email)
}
}
impl<'a: 'email, 'email> std::ops::Deref for DomainContactEmailText<'a, 'email> {
type Target = &'email DomainContactEmail<'a>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(askama::Template)]
#[template(path = "contact-email.html")]
pub struct DomainContactEmailHtml<'a, 'email>(&'email DomainContactEmail<'a>);
impl<'a: 'email, 'email> std::ops::Deref for DomainContactEmailHtml<'a, 'email> {
type Target = &'email DomainContactEmail<'a>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a: 'email, 'email> From<&'email DomainContactEmail<'a>>
for DomainContactEmailHtml<'a, 'email>
{
fn from(email: &'email DomainContactEmail<'a>) -> Self {
Self(email)
}
}
Maybe this is used too much/duplicating the templates would be too much work for Rustdoc, just thought I'd mention it here as a point in the design space.
I'm working on changing primitive_link_fragment, href_relative_parts, and href_with_root_path to use a template to construct the hrefs with fewer allocations.
And thanks for the proc macro advice, and the kind offer of assistance, @djc!
I'm working on item_struct
Awesome, welcome @nicklimmm!
A reminder to double-check the STYLE.md guide, in particular:
Askama templates support quite sophisticated control flow. To keep our templates simple and understandable, we use only a subset: if and for. In particular we avoid assignments in the template logic and Askama macros. This also may make things easier if we switch to a different Jinja-style template system, like Askama, in the future.
(hah, this needs to be updated since it says "if we switch to ... Askama" :-))
But also, more particularly: Askama lets you write a lot of Rust code inside your templates. But generally we don't want to be writing Rust inside of templates - we want Rust on the outside, producing simple struct that can be interpolated into templates in a straightforward way. So for instance if the template struct contains a complex object with lots of methods, like a DefId or a Context, that's undesirable. Instead, when creating the template struct we'd like to extract the specific things we want from those complex objects: Strings, &str's, Cows, Vecs, slices, etc.
@clubby789 can I please ask you to update the current status of components? Judging by PRs merged, these components have been migrated: static items, trait aliases, proc macros, primitives, foreign types, opaque types.
Tracking Issue for Rustdoc Askama Migration
Zulip Discussion
This issue is to track the progress of migrating rustdoc's HTML rendering to Askama.
Suggested Workflow
If you'd like to work on a component, please leave a comment claiming it so that work doesn't conflict. Work on translating the current series of
format!()
and string building calls into an HTML template. Where possible, try to keep as much logic as possible on the Rust side. Make sure to refer toSTYLE.md
for templating style, especially using comment blocks to minimize whitespace.A specific example of a migration (and some style considerations) is here.
Components to Migrate
print_item.rs
)KeywordsImplementation History
@rustbot label +T-rustdoc +A-rustdoc-ui