-
Notifications
You must be signed in to change notification settings - Fork 21
Fixes to the way Render handles attributes #45
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
base: master
Are you sure you want to change the base?
Changes from all commits
6a105fe
5320327
9bcd0b2
d159b2a
1d5f88a
23727c0
5de20c1
3d25bff
71710fc
5fb990b
12bf67b
34733c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ use std::fmt::{Result, Write}; | |
| type Attributes<'a> = Option<HashMap<&'a str, Cow<'a, str>>>; | ||
|
|
||
| /// Simple HTML element tag | ||
| #[derive(Debug)] | ||
| #[derive(Debug, Clone)] | ||
| pub struct SimpleElement<'a, T: Render> { | ||
| /// the HTML tag name, like `html`, `head`, `body`, `link`... | ||
| pub tag_name: &'a str, | ||
|
|
@@ -20,9 +20,16 @@ fn write_attributes<'a, W: Write>(maybe_attributes: Attributes<'a>, writer: &mut | |
| None => Ok(()), | ||
| Some(mut attributes) => { | ||
| for (key, value) in attributes.drain() { | ||
| write!(writer, " {}=\"", key)?; | ||
| escape_html(&value, writer)?; | ||
| write!(writer, "\"")?; | ||
| if key.chars().nth(0).unwrap_or('.') == 'b' && key.chars().nth(1).unwrap_or('.') == '!' { | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not my favorite addition as its a bit of a hack-- definitely want a better way to do this in the future. This interprets b! at the start of an attribute as a boolean attribute in HTML, which will cause it to optionally render the key based on a value of "true". Mostly because we need some way to do this today as things like selected='false' in an option isn't actually valid html. |
||
| if(value == "true") { | ||
| write!(writer, " {}", key.replace("b!", ""))?; | ||
| } | ||
| } | ||
| else { | ||
| write!(writer, " {}=\"", key)?; | ||
| write!(writer, "{}", value)?; | ||
| write!(writer, "\"")?; | ||
| } | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,9 @@ use syn::ext::IdentExt; | |
| use syn::parse::{Parse, ParseStream, Result}; | ||
| use syn::spanned::Spanned; | ||
|
|
||
| pub type AttributeKey = syn::punctuated::Punctuated<syn::Ident, syn::Token![-]>; | ||
| pub type AttributeKey = syn::punctuated::Punctuated<proc_macro2::Ident, proc_macro2::Punct>; | ||
|
|
||
| #[derive(Clone)] | ||
| pub enum ElementAttribute { | ||
| Punned(AttributeKey), | ||
| WithValue(AttributeKey, syn::Block), | ||
|
|
@@ -94,14 +95,41 @@ impl Hash for ElementAttribute { | |
|
|
||
| impl Parse for ElementAttribute { | ||
| fn parse(input: ParseStream) -> Result<Self> { | ||
| let name = AttributeKey::parse_separated_nonempty_with(input, syn::Ident::parse_any)?; | ||
| let not_punned = input.peek(syn::Token![=]); | ||
| let mut name: syn::punctuated::Punctuated<proc_macro2::Ident, proc_macro2::Punct> = | ||
| syn::punctuated::Punctuated::new(); | ||
|
|
||
| // Parse the input up to the space | ||
| loop { | ||
| let value = syn::Ident::parse_any(&input).unwrap(); | ||
| name.push_value(value); | ||
|
|
||
| if input.peek(syn::Token![=]) { | ||
| break; | ||
| } | ||
|
|
||
| let punct = input.parse().unwrap(); | ||
| name.push_punct(punct); | ||
| } | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This loop is similar to the implementation in |
||
|
|
||
| // Peak for incoming equals to check if its punned | ||
| let mut not_punned = input.peek(syn::Token![=]); | ||
|
|
||
| if !not_punned { | ||
| not_punned = input.peek2(syn::Token![=]); | ||
| } | ||
|
|
||
| if !not_punned { | ||
| not_punned = input.peek3(syn::Token![=]); | ||
| } | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because there are multiple sets of punctuation that can occur in a row we look forward to see if any of the next 3 |
||
|
|
||
| if !not_punned { | ||
| return Ok(Self::Punned(name)); | ||
| } | ||
|
|
||
| // Parse equals | ||
| input.parse::<syn::Token![=]>()?; | ||
|
|
||
| // Parse body | ||
| let value = input.parse::<syn::Block>()?; | ||
|
|
||
| Ok(Self::WithValue(name, value)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,7 @@ use syn::spanned::Spanned; | |
|
|
||
| pub type Attributes = HashSet<ElementAttribute>; | ||
|
|
||
| #[derive(Default)] | ||
| #[derive(Default, Clone)] | ||
| pub struct ElementAttributes { | ||
| pub attributes: Attributes, | ||
| } | ||
|
|
@@ -123,10 +123,17 @@ impl<'a> ToTokens for SimpleElementAttributes<'a> { | |
| .attributes | ||
| .iter() | ||
| .map(|attribute| { | ||
| let mut iter = attribute.ident().iter(); | ||
| let first_word = iter.next().unwrap().unraw(); | ||
| let ident = iter.fold(first_word.to_string(), |acc, curr| { | ||
| format!("{}-{}", acc, curr.unraw()) | ||
| let mut iter = attribute.ident().pairs(); | ||
| let ident = iter.fold("".to_string(), |acc, curr| { | ||
| format!( | ||
| "{}{}{}", | ||
| acc, | ||
| curr.value(), | ||
| match curr.punct() { | ||
| Some(p) => p.as_char().to_string(), | ||
| None => "".to_string(), | ||
| } | ||
| ) | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This properly collapses our punctuation and ident fields back into a proper string when there are multiple. |
||
| }); | ||
| let value = attribute.value_tokens(); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This stuff makes the Render trait more portable-- we still need sized as its a dependency of the writer structure we're doing, but we can at least scope this requirement to the render method so that it'll only complain about being passed around when used directly in the html! macro... 🤞