mdbook_playscript/
counter.rs1use std::collections::HashSet;
2use std::path::{Path, PathBuf};
3use mdplayscript::renderer::HtmlRenderer;
4use pulldown_cmark::Event;
5use rand::Rng;
6
7pub struct IgnorePatterns(Vec<glob::Pattern>);
8
9impl IgnorePatterns {
10 pub fn new() -> Self {
11 Self(vec![])
12 }
13
14 pub fn from_toml_values(v: &[toml::Value]) -> IgnorePatterns {
15 let mut pat = Vec::new();
16
17 for s in v.iter() {
18 let s = match s.as_str() {
19 Some(s) => s,
20 None => {
21 log::warn!("given pattern is not a string: {}", s);
22 continue;
23 },
24 };
25 match glob::Pattern::new(s) {
26 Ok(p) => {
27 pat.push(p);
28 },
29 Err(e) => {
30 log::warn!("ignore pattern error: {}", e);
31 },
32 }
33 }
34
35 IgnorePatterns(pat)
36 }
37
38 pub fn matches_path(&self, path: &Path) -> bool {
39 self.0
40 .iter()
41 .any(|pat| pat.matches_path(path))
42 }
43}
44
45pub struct CounterFactory<'a> {
46 prefix: &'a str,
47 issued_class: HashSet<String>,
48}
49
50impl<'a> CounterFactory<'a> {
51 pub fn new(prefix: &'a str) -> Self {
52 Self {
53 prefix: prefix,
54 issued_class: HashSet::new(),
55 }
56 }
57
58 pub fn issue(&mut self) -> Counter {
59 loop {
60 let class = generate_random_class_name(self.prefix);
61 if self.issued_class.insert(class.clone()) {
62 return Counter { class: class };
63 }
64 }
65 }
66}
67
68fn generate_random_class_name(prefix: &str) -> String {
69 let mut rng = rand::thread_rng();
70
71 let tag: String = std::iter::repeat(())
72 .map(|_| rng.sample(rand::distributions::Alphanumeric))
73 .map(char::from)
74 .take(10)
75 .collect();
76
77 format!("{}{}", prefix, tag)
78}
79
80pub struct Counter {
81 class: String,
82}
83
84impl Counter {
85 pub fn set_class_to_renderer(&self, renderer: &mut HtmlRenderer) {
86 renderer.speech_classes.add(&self.class);
87 }
88
89 pub fn generate_placeholder(&self, ignored: &IgnorePatterns, src: Option<&PathBuf>) -> Vec<Event<'static>> {
90 let div = match src {
91 Some(src) if ignored.matches_path(src) => {
92 log::info!("Ignore {}",src.display());
93 crate::IgnoredPlaceholder.to_cow_str()
94 },
95 _ => {
96 log::info!("Process {:?}", src);
97 format!(r#"<div class="mdplayscript-count {}"></div>"#, self.class)
98 .into()
99 },
100 };
101
102 vec![Event::Html(div.into())]
103 }
104}