yew_macro/html_tree/
html_dashed_name.rs1use std::fmt;
2
3use proc_macro2::{Ident, Span, TokenStream};
4use quote::{quote, ToTokens};
5use syn::buffer::Cursor;
6use syn::ext::IdentExt;
7use syn::parse::{Parse, ParseStream};
8use syn::spanned::Spanned;
9use syn::{LitStr, Token};
10
11use crate::stringify::Stringify;
12use crate::{non_capitalized_ascii, Peek};
13
14#[derive(Clone, PartialEq, Eq)]
15pub struct HtmlDashedName {
16 pub name: Ident,
17 pub extended: Vec<(Token![-], Ident)>,
18}
19
20impl HtmlDashedName {
21 pub fn eq_ignore_ascii_case<S>(&self, other: S) -> bool
24 where
25 S: Into<String>,
26 {
27 let mut s = other.into();
28 s.make_ascii_lowercase();
29 s == self.to_ascii_lowercase_string()
30 }
31
32 pub fn to_ascii_lowercase_string(&self) -> String {
33 let mut s = self.to_string();
34 s.make_ascii_lowercase();
35 s
36 }
37
38 pub fn to_lit_str(&self) -> LitStr {
39 LitStr::new(&self.to_string(), self.span())
40 }
41}
42
43impl fmt::Display for HtmlDashedName {
44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
45 write!(f, "{}", self.name)?;
46 for (_, ident) in &self.extended {
47 write!(f, "-{ident}")?;
48 }
49 Ok(())
50 }
51}
52
53impl Peek<'_, Self> for HtmlDashedName {
54 fn peek(cursor: Cursor) -> Option<(Self, Cursor)> {
55 let (name, cursor) = cursor.ident()?;
56 if !non_capitalized_ascii(&name.to_string()) {
57 return None;
58 }
59
60 let mut extended = Vec::new();
61 let mut cursor = cursor;
62 loop {
63 if let Some((punct, p_cursor)) = cursor.punct() {
64 if punct.as_char() == '-' {
65 let (ident, i_cursor) = p_cursor.ident()?;
66 cursor = i_cursor;
67 extended.push((Token), ident));
68 continue;
69 }
70 }
71 break;
72 }
73
74 Some((HtmlDashedName { name, extended }, cursor))
75 }
76}
77
78impl Parse for HtmlDashedName {
79 fn parse(input: ParseStream) -> syn::Result<Self> {
80 let name = input.call(Ident::parse_any)?;
81 let mut extended = Vec::new();
82 while input.peek(Token![-]) {
83 extended.push((input.parse::<Token![-]>()?, input.call(Ident::parse_any)?));
84 }
85
86 Ok(HtmlDashedName { name, extended })
87 }
88}
89
90impl ToTokens for HtmlDashedName {
91 fn to_tokens(&self, tokens: &mut TokenStream) {
92 let HtmlDashedName { name, extended } = self;
93 let dashes = extended.iter().map(|(dash, _)| quote! {#dash});
94 let idents = extended.iter().map(|(_, ident)| quote! {#ident});
95 let extended = quote! { #(#dashes #idents)* };
96 tokens.extend(quote! { #name #extended });
97 }
98}
99
100impl Stringify for HtmlDashedName {
101 fn try_into_lit(&self) -> Option<LitStr> {
102 Some(self.to_lit_str())
103 }
104
105 fn stringify(&self) -> TokenStream {
106 self.to_lit_str().stringify()
107 }
108}
109
110impl From<Ident> for HtmlDashedName {
111 fn from(name: Ident) -> Self {
112 HtmlDashedName {
113 name,
114 extended: vec![],
115 }
116 }
117}