zhlint/hyper/markdown/
context.rs1use std::{cmp::{max, min}, ops::Range};
2
3#[derive(Debug, Clone)]
4pub struct Pair {
5 pub start_range: Range<usize>,
6 pub start_content: String,
7 pub end_range: Range<usize>,
8 pub end_content: String,
9}
10
11#[derive(Debug, PartialEq, Clone)]
12pub enum InlineType {
13 Text,
14 MarkPair,
15 SingleMark,
16 SingleMarkCode,
17 SingleMarkConnect,
18}
19
20#[derive(Debug, Clone)]
21pub struct InlineMark {
22 pub pair: Pair,
23 pub meta: InlineType,
24}
25
26#[derive(Debug)]
27pub struct BlockMark {
28 pub pair: Pair,
29 pub inline_marks: Vec<InlineMark>,
30}
31
32#[derive(Debug)]
33pub struct Context<'a> {
34 pub str: &'a str,
35 pub blocks: Vec<BlockMark>,
36 pub errors: Vec<String>,
37 pub unresolved_block: Option<BlockMark>,
38 pub cur_index: usize,
39}
40
41#[derive(PartialEq)]
42enum RangeVsPair {
43 Ahead,
44 Inside,
45 Behind,
46 None,
47}
48
49fn update_pair_range(pair: &mut Pair, range: Range<usize>) -> RangeVsPair {
50 if range.start >= pair.start_range.start && range.end <= pair.end_range.end {
51 pair.start_range.end = min(range.start, pair.start_range.end);
52 pair.end_range.start = max(range.end, pair.end_range.start);
53 RangeVsPair::Inside
54 } else if range.start < pair.start_range.start {
55 RangeVsPair::Ahead
56 } else if range.end > pair.end_range.end {
57 RangeVsPair::Behind
58 } else {
59 RangeVsPair::None
60 }
61}
62
63fn determine_pair_content(str: &str, pair: &mut Pair) {
64 pair.start_content = str[pair.start_range.clone()].to_string();
65 pair.end_content = str[pair.end_range.clone()].to_string();
66}
67
68impl<'a> Context<'a> {
69 pub fn new(str: &str) -> Context {
70 Context {
71 str,
72 blocks: Vec::new(),
73 errors: Vec::new(),
74 unresolved_block: None,
75 cur_index: 0,
76 }
77 }
78 pub fn get_unresolved_inlines(&mut self) -> Vec<&mut InlineMark> {
79 self.unresolved_block.as_mut().map(|block| {
80 block.inline_marks.iter_mut().filter(|inline|
81 inline.pair.end_range.end >= self.cur_index
82 ).collect()
83 }).unwrap_or_default()
84 }
85 pub fn handle_block(&mut self, range: Range<usize>) {
86 let current_block = BlockMark {
88 pair: Pair {
89 start_range: range.clone(), start_content: String::new(), end_range: range.clone(), end_content: String::new(), },
94 inline_marks: Vec::new(),
95 };
96 if self.unresolved_block.is_some() {
97 let mut unresolved_block = self.unresolved_block.take().unwrap();
98 determine_pair_content(self.str, &mut unresolved_block.pair);
99 self.blocks.push(unresolved_block);
100 }
101 self.unresolved_block = Some(current_block);
102 }
104 pub fn update_unresolved_range(&mut self, range: Range<usize>) {
105 if let Some(last_block) = &mut self.unresolved_block {
106 update_pair_range(&mut last_block.pair, range.clone());
107 if self.cur_index > last_block.pair.start_range.start && self.cur_index < range.start {
108 let connect_range = Range { start: self.cur_index, end: range.start };
110 let connect_mark = InlineMark {
111 pair: Pair {
112 start_range: connect_range.clone(),
113 start_content: self.str[connect_range.clone()].to_string(),
114 end_range: Range { start: range.start, end: range.start },
115 end_content: String::new(),
116 },
117 meta: InlineType::SingleMarkConnect,
118 };
119 last_block.inline_marks.push(connect_mark);
120 }
121 let str = self.str;
122 let mut new_cur_index = range.end;
123 for inline in self.get_unresolved_inlines() {
124 if inline.meta == InlineType::MarkPair && update_pair_range(&mut inline.pair, range.clone()) == RangeVsPair::Behind {
125 determine_pair_content(str, &mut inline.pair);
126 new_cur_index = inline.pair.end_range.end;
127 }
128 }
129 self.cur_index = new_cur_index;
130 }
131 }
132 pub fn handle_inline(&mut self, range: Range<usize>, inline_type: InlineType) {
133 self.update_unresolved_range(range.clone());
143 if let Some(last_block) = &mut self.unresolved_block {
144 match inline_type {
145 InlineType::Text => {
146 }
148 InlineType::MarkPair => {
149 let inline_mark = InlineMark {
150 pair: Pair {
151 start_range: range.clone(), start_content: String::new(), end_range: range.clone(), end_content: String::new(), },
156 meta: inline_type,
157 };
158 last_block.inline_marks.push(inline_mark);
159 }
160 InlineType::SingleMarkCode => {
161 let inline_mark = InlineMark {
162 pair: Pair {
163 start_range: range.clone(),
164 start_content: self.str[range.clone()].to_string(),
165 end_range: Range { start: range.end, end: range.end },
166 end_content: String::new(),
167 },
168 meta: inline_type,
169 };
170 self.unresolved_block.as_mut().unwrap().inline_marks.push(inline_mark);
171 }
172 InlineType::SingleMark => {
173 let inline_mark = InlineMark {
174 pair: Pair {
175 start_range: range.clone(),
176 start_content: self.str[range.clone()].to_string(),
177 end_range: Range { start: range.end, end: range.end },
178 end_content: String::new(),
179 },
180 meta: inline_type,
181 };
182 self.unresolved_block.as_mut().unwrap().inline_marks.push(inline_mark);
183 }
184 InlineType::SingleMarkConnect => {
185 }
187 }
188 }
189 }
191 pub fn finalize(&mut self) {
192 if let Some(mut last_block) = self.unresolved_block.take() {
193 determine_pair_content(self.str, &mut last_block.pair);
194 self.blocks.push(last_block);
195 }
196 }
197}
198
199#[derive(Debug)]
200pub struct ParseResult {
201 pub blocks: Vec<BlockMark>,
202 pub errors: Vec<String>, }