1mod parser;
2
3pub use parser::*;
4use std::collections::HashMap;
5
6use crate::code_ast::types::CodeContent;
7use crate::common::Span;
8use cowstr::CowStr;
9use serde::{Deserialize, Serialize};
10use std::io::{BufWriter, Write};
11
12#[derive(Debug, PartialEq, Default)]
13pub struct RawDocument {
14 pub(crate) src: Vec<ElementInfo>,
15 pub(crate) input: CowStr,
16 pub(crate) meta: Option<CowStr>,
17 pub(crate) references: HashMap<CowStr, Reference>,
18}
19
20impl RawDocument {
21 pub fn new(input: &str) -> Self {
22 Self {
23 src: vec![],
24 input: CowStr::from(input),
25 meta: None,
26 references: Default::default(),
27 }
28 }
29}
30
31#[derive(Debug, PartialEq, Clone)]
32pub enum Reference {
33 Math(CowStr),
34 Code(CowStr),
35 Command(CowStr, Vec<Parameter>),
36}
37
38#[derive(Debug, PartialEq, Clone)]
39pub enum Element {
40 Markdown(CowStr),
41 Special(Option<CowStr>, Special),
42}
43
44#[derive(Debug, PartialEq, Clone)]
45pub enum Special {
46 Math {
47 inner: CowStr,
48 is_block: bool,
49 },
50 CodeInline {
51 inner: CowStr,
52 },
53 CodeBlock {
54 lvl: usize,
55 inner: CodeContent,
56 attributes: Vec<CowStr>,
57 },
58 Command {
59 function: CowStr,
60 parameters: Vec<Parameter>,
61 body: Option<Vec<ElementInfo>>,
62 },
63 Verbatim {
64 inner: CowStr,
65 },
66}
67
68#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
69pub struct CodeAttr {
70 pub key: Option<CowStr>,
71 pub value: CowStr,
72}
73
74#[derive(Debug, PartialEq, Clone)]
75pub struct ElementInfo {
76 pub(crate) element: Element,
77 pub(crate) span: Span,
78}
79
80#[derive(Debug, PartialEq, Clone)]
81pub struct Parameter {
82 pub key: Option<CowStr>,
83 pub value: Value,
84 pub span: Span,
85}
86
87impl Parameter {
88 pub fn with_value(value: Value, pos: Span) -> Self {
89 Self {
90 key: None,
91 value,
92 span: pos,
93 }
94 }
95
96 pub fn with_key<C: Into<CowStr>>(key: C, value: Value, pos: Span) -> Self {
97 Self {
98 key: Some(key.into()),
99 value,
100 span: pos,
101 }
102 }
103}
104
105#[derive(Debug, PartialEq, Clone)]
106pub enum Value {
107 Flag(CowStr),
108 Content(Vec<ElementInfo>),
109 String(CowStr),
110}
111
112impl ToString for Value {
113 fn to_string(&self) -> String {
114 match self {
115 Value::Flag(k) => format!("Flag: {k}"),
116 Value::Content(_) => "Content".to_string(),
117 Value::String(s) => s.to_string(),
118 }
119 }
120}
121
122#[derive(Clone)]
123pub struct Child {
124 pub elem: Special,
125 pub span: Span,
126 pub label: Option<CowStr>,
127 pub identifier: usize,
128}
129
130pub struct ComposedMarkdown {
131 pub src: CowStr,
132 pub children: Vec<Child>,
133}
134
135impl From<Vec<ElementInfo>> for ComposedMarkdown {
136 fn from(value: Vec<ElementInfo>) -> Self {
137 let mut writer = BufWriter::new(Vec::new());
138 let mut children = Vec::new();
139
140 let mut code_idx = 0;
141 let mut command_idx = 0;
142 let mut math_idx = 0;
143 let mut extra_idx = 0;
144
145 for elem in value.into_iter() {
146 match elem.element {
147 Element::Markdown(s) => {
148 writer.write_all(s.as_bytes()).unwrap();
149 }
150 Element::Special(label, inner) => {
151 let idx = code_idx + command_idx + math_idx + extra_idx;
152
153 let identifier = match inner {
154 Special::Math { .. } => {
155 math_idx += 1;
156 math_idx - 1
157 }
158 Special::CodeBlock { lvl, .. } => {
159 if lvl > 1 {
160 code_idx += 1;
161 code_idx - 1
162 } else {
163 extra_idx += 1;
164 0
165 }
166 }
167 Special::Command { .. } => {
168 command_idx += 1;
169 command_idx - 1
170 }
171 Special::Verbatim { .. } => {
172 extra_idx += 1;
173 0
174 }
175 Special::CodeInline { .. } => {
176 extra_idx += 1;
177 0
178 }
179 };
180
181 children.push(Child {
182 elem: inner,
183 span: elem.span,
184 label,
185 identifier,
186 });
187 write!(&mut writer, "<elem-{}>", idx).unwrap() }
189 }
190 }
191
192 ComposedMarkdown {
193 src: CowStr::from(String::from_utf8(writer.into_inner().unwrap()).unwrap()),
194 children,
195 }
196 }
197}