markdown_utils/
transformers.rs1pub fn transform_line_by_line_skipping_codeblocks(
2 text: &str,
3 func: &dyn Fn(String) -> String,
4) -> String {
5 let mut lines: Vec<String> = vec![];
6
7 let mut current_fenced_codeblock_delimiter: String = "".to_string();
8 for line in text.lines() {
9 let mut next_line: String = line.to_string();
10 if current_fenced_codeblock_delimiter == "" {
11 let trimmed_line = line.trim();
12 if trimmed_line.starts_with("```") || trimmed_line.starts_with("~~~") {
13 current_fenced_codeblock_delimiter =
15 trimmed_line[0..3].to_string();
16 } else if !line.starts_with(" ") || line.starts_with(" ") {
17 next_line = func(next_line.to_string())
22 }
23 } else if line.trim_start().starts_with(
24 ¤t_fenced_codeblock_delimiter
25 ) {
26 current_fenced_codeblock_delimiter = "".to_string();
27 }
28 lines.push(next_line);
29 }
30 lines.join("\n")
31}
32
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use rstest::rstest;
38
39 fn prepend_upper_a_transformer(line: String) -> String {
40 format!("A{}", line)
41 }
42
43 #[rstest]
44 #[case(
45 &"foo\nbar\n\nbaz",
46 prepend_upper_a_transformer,
47 "Afoo\nAbar\nA\nAbaz",
48 )]
49 #[case(
50 &concat!(
51 "foo\n```\nfoo\n```\n~~~\nfoo\n~~~\n\n foo",
52 "\n foo\n\nbar\n\nbaz",
53 ),
54 prepend_upper_a_transformer,
55 concat!(
56 "Afoo\n```\nfoo\n```\n~~~\nfoo\n~~~\nA\n foo",
57 "\nA foo\nA\nAbar\nA\nAbaz",
58 ).to_string(),
59 )]
60 fn transform_line_by_line_skipping_codeblocks_test(
61 #[case] text: &str,
62 #[case] func: impl Fn(String) -> String,
63 #[case] expected: String,
64 ) {
65 assert_eq!(
66 transform_line_by_line_skipping_codeblocks(
67 text,
68 &func,
69 ),
70 expected,
71 );
72 }
73}