nmd_core/codex/modifier/
standard_heading_modifier.rs1use regex::Regex;
2
3use crate::codex::modifier::constants::{CHAPTER_STYLE_PATTERN, CHAPTER_TAGS_PATTERN};
4
5use super::base_modifier::BaseModifier;
6use super::constants::MAX_HEADING_LEVEL;
7use super::ModifiersBucket;
8use super::ModifierIdentifier;
9
10#[derive(Debug, PartialEq, Clone)]
11pub enum StandardHeading {
12
13 HeadingGeneralCompactVersion(u32),
14 HeadingGeneralExtendedVersion(u32),
15 MinorHeading,
16 MajorHeading,
17 SameHeading,
18
19}
20
21impl StandardHeading {
22 pub fn ordered() -> Vec<Self> {
23 let mut heading_modifiers: Vec<Self> = vec![Self::MinorHeading, Self::MajorHeading, Self::SameHeading];
24
25 for i in (1..=MAX_HEADING_LEVEL).rev() {
26 heading_modifiers.push(Self::HeadingGeneralExtendedVersion(i));
27 heading_modifiers.push(Self::HeadingGeneralCompactVersion(i));
28 }
29
30 heading_modifiers
31 }
32
33 pub fn heading_level(content: &str) -> Option<u32> {
34 let heading_modifiers = Self::ordered();
35
36 for heading_modifier in heading_modifiers {
37 let regex = Regex::new(&heading_modifier.modifier_pattern()).unwrap();
38
39 if regex.is_match(content) {
40 match heading_modifier {
41 Self::HeadingGeneralExtendedVersion(level) => return Option::Some(level),
42 Self::HeadingGeneralCompactVersion(level) => return Option::Some(level),
43 _ => panic!("unexpected modifier: {:?}", heading_modifier)
44 }
45 }
46 }
47
48 Option::None
49 }
50
51 pub fn str_is_heading(content: &str) -> bool {
52 Self::heading_level(content).is_some()
53 }
54
55 pub fn identifier(&self) -> ModifierIdentifier {
56 match *self {
57 Self::HeadingGeneralExtendedVersion(level) => {
58
59 if level == 0 || level > MAX_HEADING_LEVEL {
60 panic!("{level} is an invalid heading level.")
61 }
62
63 format!(r"heading-{}-extended-version", level)
64 },
65 Self::HeadingGeneralCompactVersion(level) => {
66
67 if level == 0 || level > MAX_HEADING_LEVEL {
68 panic!("{level} is an invalid heading level.")
69 }
70
71 format!(r"heading-{}-compact-version", level)
72 },
73 StandardHeading::MinorHeading => String::from("minor-heading"),
74 StandardHeading::MajorHeading => String::from("major-heading"),
75 StandardHeading::SameHeading => String::from("same-heading"),
76 }
77 }
78
79 pub fn modifier_pattern(&self) -> String {
80 let specific_pattern = match *self {
81 Self::HeadingGeneralExtendedVersion(level) => {
82
83 if level == 0 || level > MAX_HEADING_LEVEL {
84 panic!("{level} is an invalid heading level.")
85 }
86
87 format!(r"(?m:^#{{{}}}\s+(.*))", level)
88 },
89 Self::HeadingGeneralCompactVersion(level) => {
90
91 if level == 0 || level > MAX_HEADING_LEVEL {
92 panic!("{level} is an invalid heading level.")
93 }
94
95 format!(r"(?m:^#({})\s+(.*))", level)
96 },
97 StandardHeading::MinorHeading => String::from(r"(?m:^#-\s+(.*))"),
98 StandardHeading::MajorHeading => String::from(r"(?m:^#\+\s+(.*))"),
99 StandardHeading::SameHeading => String::from(r"(?m:^#=\s+(.*))"),
100 };
101
102 format!("{}{}{}", specific_pattern, CHAPTER_TAGS_PATTERN, CHAPTER_STYLE_PATTERN)
103 }
104
105 pub fn incompatible_modifiers(&self) -> ModifiersBucket {
106 ModifiersBucket::None
107 }
108}
109
110impl Into<BaseModifier> for StandardHeading {
111 fn into(self) -> BaseModifier {
112 BaseModifier::new(self.modifier_pattern(), Regex::new(&self.modifier_pattern()).unwrap(), self.incompatible_modifiers())
113 }
114}