1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use quote::{quote, quote_spanned, ToTokens};
use rstml::node::NodeName;
use syn::spanned::Spanned;

#[derive(Default)]
pub struct IdeHelper {
	open_tag_names: Vec<NodeName>,
	close_tag_names: Vec<NodeName>,
	attr_names: Vec<NodeName>,
}

impl IdeHelper {
	pub fn new() -> Self {
		Default::default()
	}

	pub fn mark_open_tag(&mut self, name: NodeName) {
		self.open_tag_names.push(name);
	}

	pub fn mark_close_tag(&mut self, name: NodeName) {
		self.close_tag_names.push(name);
	}

	pub fn mark_attr_name(&mut self, name: NodeName) {
		self.attr_names.push(name);
	}
}

impl ToTokens for IdeHelper {
	fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
		fn mark_as_element(name: &NodeName, open: bool) -> proc_macro2::TokenStream {
			let element = quote_spanned!(name.span() => enum);
			let mut name_string = name.to_string();
			if !open {
				name_string.push('/');
			}

			quote!({
				#[doc = #name_string]
				#element X{}
			})
		}

		fn mark_as_attribute(name: &NodeName) -> proc_macro2::TokenStream {
			let element = quote_spanned!(name.span() => A);
			quote!({enum X {#element}})
		}

		self
			.open_tag_names
			.iter()
			.for_each(|name| tokens.extend(mark_as_element(name, true)));
		self
			.close_tag_names
			.iter()
			.for_each(|name| tokens.extend(mark_as_element(name, false)));
		self
			.attr_names
			.iter()
			.for_each(|name| tokens.extend(mark_as_attribute(name)));
	}
}