Skip to main content

sevenmark_parser/
context.rs

1use crate::error::SevenMarkError;
2
3macro_rules! context_setters {
4    ($($name:ident => $field:ident),*) => {
5        $(
6            paste::paste! {
7                /// [<$name:upper>] 컨텍스트로 전환
8                pub fn [<set_ $name _context>](&mut self) {
9                    self.$field = true;
10                }
11
12                /// [<$name:upper>] 컨텍스트 해제
13                pub fn [<unset_ $name _context>](&mut self) {
14                    self.$field = false;
15                }
16            }
17        )*
18    };
19}
20
21#[derive(Debug, Clone)]
22pub struct ParseContext<'i> {
23    pub recursion_depth: usize,
24    pub trim_depth: usize,
25    pub inside_header: bool,
26    pub inside_bold: bool,
27    pub inside_italic: bool,
28    pub inside_strikethrough: bool,
29    pub inside_subscript: bool,
30    pub inside_superscript: bool,
31    pub inside_underline: bool,
32    pub inside_footnote: bool,
33    pub inside_media_element: bool,
34    pub original_input: &'i [u8],
35    pub max_recursion_depth: usize,
36    pub section_counter: usize,
37    pub footnote_counter: usize,
38}
39
40impl<'i> ParseContext<'i> {
41    /// 새 컨텍스트 생성
42    pub fn new(input: &'i str) -> Self {
43        Self {
44            recursion_depth: 0,
45            trim_depth: 0,
46            inside_header: false,
47            inside_bold: false,
48            inside_italic: false,
49            inside_strikethrough: false,
50            inside_subscript: false,
51            inside_superscript: false,
52            inside_underline: false,
53            inside_footnote: false,
54            inside_media_element: false,
55            original_input: input.as_bytes(),
56            max_recursion_depth: 16,
57            section_counter: 1,
58            footnote_counter: 1,
59        }
60    }
61
62    /// 현재 위치가 라인 시작인지 확인
63    pub fn is_at_line_start(&self, position: usize) -> bool {
64        position == 0 || self.original_input.get(position - 1) == Some(&b'\n')
65    }
66
67    /// 재귀 깊이 증가 (in-place)
68    pub fn increase_depth(&mut self) -> Result<(), SevenMarkError> {
69        let new_depth = self.recursion_depth + 1;
70        if new_depth > self.max_recursion_depth {
71            return Err(SevenMarkError::RecursionDepthExceeded {
72                depth: new_depth,
73                max_depth: self.max_recursion_depth,
74            });
75        }
76        self.recursion_depth = new_depth;
77        Ok(())
78    }
79
80    /// 재귀 깊이 감소 (in-place)
81    pub fn decrease_depth(&mut self) {
82        self.recursion_depth = self.recursion_depth.saturating_sub(1);
83    }
84
85    /// 최대 재귀 깊이에 도달했는지 확인
86    pub fn is_at_max_depth(&self) -> bool {
87        self.recursion_depth >= self.max_recursion_depth
88    }
89
90    /// 현재 재귀 깊이 반환
91    pub fn current_depth(&self) -> usize {
92        self.recursion_depth
93    }
94
95    /// 남은 재귀 깊이 반환
96    pub fn remaining_depth(&self) -> usize {
97        self.max_recursion_depth
98            .saturating_sub(self.recursion_depth)
99    }
100
101    /// 다음 섹션 인덱스 반환 및 카운터 증가
102    pub fn next_section_index(&mut self) -> usize {
103        let idx = self.section_counter;
104        self.section_counter += 1;
105        idx
106    }
107
108    /// 다음 각주 인덱스 반환 및 카운터 증가
109    pub fn next_footnote_index(&mut self) -> usize {
110        let idx = self.footnote_counter;
111        self.footnote_counter += 1;
112        idx
113    }
114
115    /// trim_depth 증가
116    pub fn increase_trim_depth(&mut self) {
117        self.trim_depth += 1;
118    }
119
120    /// trim_depth 감소
121    pub fn decrease_trim_depth(&mut self) {
122        self.trim_depth = self.trim_depth.saturating_sub(1);
123    }
124
125    /// trim 컨텍스트 안에 있는지 확인
126    pub fn is_trimming(&self) -> bool {
127        self.trim_depth > 0
128    }
129
130    context_setters! {
131        header => inside_header,
132        bold => inside_bold,
133        italic => inside_italic,
134        strikethrough => inside_strikethrough,
135        subscript => inside_subscript,
136        superscript => inside_superscript,
137        underline => inside_underline,
138        footnote => inside_footnote,
139        media_element => inside_media_element
140    }
141}