mdbook_regex_replacer/
lib.rs1use log::{debug};
2use mdbook::preprocess::{Preprocessor, PreprocessorContext, CmdPreprocessor};
3use mdbook::book::Book;
4use mdbook::errors::Error;
5use clap::ArgMatches;
6use std::{process, io};
7use mdbook::BookItem;
8use regex::Regex;
9use serde_derive::{Deserialize, Serialize};
10
11
12#[macro_use]
13extern crate lazy_static;
14
15
16lazy_static! {
17 static ref RE : Regex= Regex::new(r"==(?P<c>\S+?)==[^>]").unwrap();
19}
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
22#[serde(default, rename_all = "kebab-case")]
23pub struct RegexReplacerItem {
24 regex: String,
25 rep: String
26}
27
28impl Default for RegexReplacerItem {
29 fn default() -> Self {
30 RegexReplacerItem{
31 regex:"".to_string(),
32 rep:"".to_string(),
33 }
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
38#[serde(default, rename_all = "kebab-case")]
39pub struct RegexReplacerConfigure {
40 command: Option<String>,
41 items: Option<Vec<RegexReplacerItem>>,
42}
43
44impl Default for RegexReplacerConfigure{
45 fn default() -> Self {
46 RegexReplacerConfigure{command: Option::None, items: Option::None}
47 }
48}
49
50#[test]
51fn test_replace(){
52 let c = (Regex::new("==(?P<c>.+?)==").unwrap(), "<mark>$c</mark>".to_string());
53 let f = replace_all(&c, "==sasasas== s");
54 print!("{}", f);
55}
56
57pub fn replace_all(e: & (Regex, String), s: &str) -> String {
58 e.0.replace_all(s, e.1.as_str()).into_owned()
59}
60
61pub fn handle_each_item(book_item: &mut BookItem, regexes: & Vec<(Regex, String)>) {
62 match book_item {
63 BookItem::Chapter(chapter) => {
64
65 for e in regexes {
66 chapter.content = replace_all(e, chapter.content.as_str());
67 debug!("after regex placer: {} => {}:\n{}", e.0, e.1, chapter.content);
68 }
69
70 for item in &mut chapter.sub_items {
71 handle_each_item(item, regexes);
72 }
73 }
74 _ => {}
75 }
76}
77
78pub struct RegexReplacerPreprocessor {}
79
80impl Preprocessor for RegexReplacerPreprocessor {
81
82 fn name(&self) -> &str {
83 "regex-replacer"
84 }
85
86 fn run(&self, ctx: &PreprocessorContext, mut book: Book) -> Result<Book, Error> {
87
88 let config = ctx.config.get_preprocessor(self.name()).unwrap();
89 let config_string = toml::to_string(config).unwrap();
90 let regex_replacer_configure: RegexReplacerConfigure = toml::from_str(config_string.as_str()).unwrap();
91
92 let mut regexes: Vec<(Regex, String)> = Vec::new();
93
94 if let Some(items) = ®ex_replacer_configure.items {
95 for e in items{
96 let regex = Regex::new(e.regex.as_str()).unwrap();
97 regexes.push((regex, e.rep.clone()));
98 }
99 }
100
101 let ii = &mut book.sections;
102 for section in ii {
103 handle_each_item(section, & regexes);
104 }
105 Ok(book)
106 }
107
108 fn supports_renderer(&self, _renderer: &str) -> bool {
109 _renderer == "html"
110 }
111}
112
113pub fn handle_preprocessor(pre: &dyn Preprocessor) -> Result<(), Error> {
114 debug!("mark start");
115 let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?;
116
117 if ctx.mdbook_version != mdbook::MDBOOK_VERSION {
118 eprintln!(
121 "Warning: The {} plugin was built against version {} of mdbook, \
122 but we're being called from version {}",
123 pre.name(),
124 mdbook::MDBOOK_VERSION,
125 ctx.mdbook_version
126 );
127 }
128
129 let processed_book = pre.run(&ctx, book)?;
130
131 serde_json::to_writer(io::stdout(), &processed_book)?;
132
133 Ok(())
134}
135
136pub fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> ! {
137 let renderer = sub_args.value_of("renderer").expect("Required argument");
138 let supported = pre.supports_renderer(&renderer);
139
140 if supported {
142 process::exit(0);
143 } else {
144 process::exit(1);
145 }
146}