1pub mod elements;
2pub mod output;
3pub mod parsers;
4
5use derive_more::Display;
6use elements::*;
7use parsers::{vimwiki, IResult, Span};
8
9pub trait FromLanguage<'a>: Sized {
11 type Error;
12
13 fn from_language(language: Language<'a>) -> Result<Self, Self::Error>;
15}
16
17#[derive(Copy, Clone, Debug, Eq, PartialEq, Display)]
38pub enum Language<'a> {
39 Vimwiki(&'a str),
40 Markdown(&'a str),
41 Mediawiki(&'a str),
42}
43
44impl<'a> Language<'a> {
45 pub fn from_vimwiki_str(inner: &'a str) -> Self {
47 Self::Vimwiki(inner)
48 }
49
50 pub fn from_markdown_str(inner: &'a str) -> Self {
52 Self::Markdown(inner)
53 }
54
55 pub fn from_mediawiki_str(inner: &'a str) -> Self {
57 Self::Mediawiki(inner)
58 }
59
60 pub fn is_vimwiki(&self) -> bool {
62 matches!(self, Self::Vimwiki(_))
63 }
64
65 pub fn is_markdown(&self) -> bool {
67 matches!(self, Self::Markdown(_))
68 }
69
70 pub fn is_mediawiki(&self) -> bool {
72 matches!(self, Self::Mediawiki(_))
73 }
74
75 pub fn as_inner(&self) -> &str {
76 match self {
77 Self::Vimwiki(x) => x,
78 Self::Markdown(x) => x,
79 Self::Mediawiki(x) => x,
80 }
81 }
82
83 pub fn parse<F: FromLanguage<'a>>(&self) -> Result<F, F::Error> {
85 FromLanguage::from_language(*self)
86 }
87}
88
89macro_rules! impl_from_language {
90 ($t:ty, $f:expr) => {
91 impl<'a> FromLanguage<'a> for $t {
92 type Error = parsers::Error<'a>;
93
94 fn from_language(l: Language<'a>) -> Result<Self, Self::Error> {
95 match l {
96 Language::Vimwiki(x) => Ok($f(Span::from(x))?.1),
97 _ => Err(parsers::Error::unsupported()),
98 }
99 }
100 }
101 };
102}
103
104impl_from_language!(Page<'a>, vimwiki::page);
106impl_from_language!(Located<BlockElement<'a>>, vimwiki::blocks::block_element);
107impl_from_language!(
108 Located<InlineElementContainer<'a>>,
109 vimwiki::blocks::inline::inline_element_container
110);
111impl_from_language!(
112 Located<InlineElement<'a>>,
113 vimwiki::blocks::inline::inline_element
114);
115
116impl_from_language!(
118 Located<Blockquote<'a>>,
119 vimwiki::blocks::blockquotes::blockquote
120);
121
122impl_from_language!(
124 Located<CodeInline<'a>>,
125 vimwiki::blocks::inline::code::code_inline
126);
127
128impl_from_language!(
130 Located<Comment<'a>>,
131 vimwiki::blocks::inline::comments::comment
132);
133impl_from_language!(
134 Located<LineComment<'a>>,
135 vimwiki::blocks::inline::comments::line_comment
136);
137impl_from_language!(
138 Located<MultiLineComment<'a>>,
139 vimwiki::blocks::inline::comments::multi_line_comment
140);
141
142impl_from_language!(
144 Located<DefinitionList<'a>>,
145 vimwiki::blocks::definitions::definition_list
146);
147impl_from_language!(Located<Divider>, vimwiki::blocks::dividers::divider);
152
153impl_from_language!(Located<Header<'a>>, vimwiki::blocks::headers::header);
155
156impl_from_language!(Located<Link<'a>>, vimwiki::blocks::inline::links::link);
158
159impl_from_language!(Located<List<'a>>, vimwiki::blocks::lists::list);
161impl_from_language!(Located<ListItem<'a>>, parse_list_item);
162fn parse_list_item<'a>(input: Span<'a>) -> IResult<Located<ListItem<'a>>> {
163 nom::combinator::map(
164 vimwiki::blocks::lists::list_item,
165 |(_, item): (usize, Located<ListItem>)| item,
166 )(input)
167}
168
169impl_from_language!(
171 Located<MathInline<'a>>,
172 vimwiki::blocks::inline::math::math_inline
173);
174impl_from_language!(Located<MathBlock<'a>>, vimwiki::blocks::math::math_block);
175
176impl_from_language!(
178 Located<Paragraph<'a>>,
179 vimwiki::blocks::paragraphs::paragraph
180);
181
182impl_from_language!(
184 Located<Placeholder<'a>>,
185 vimwiki::blocks::placeholders::placeholder
186);
187
188impl_from_language!(Located<CodeBlock<'a>>, vimwiki::blocks::code::code_block);
190
191impl_from_language!(Located<Table<'a>>, vimwiki::blocks::tables::table);
193
194impl_from_language!(Located<Tags<'a>>, vimwiki::blocks::inline::tags::tags);
196
197impl_from_language!(
199 Located<Text<'a>>,
200 vimwiki::blocks::inline::typefaces::text
201);
202impl_from_language!(
203 Located<DecoratedText<'a>>,
204 vimwiki::blocks::inline::typefaces::decorated_text
205);
206impl_from_language!(
207 Located<Keyword>,
208 vimwiki::blocks::inline::typefaces::keyword
209);
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 mod vimwiki {
217 use super::*;
218
219 #[test]
220 fn parse_to_page() {
221 let input = Language::from_vimwiki_str("some text");
222 let _result: Page = input.parse().expect("Failed to parse");
223 }
224
225 #[test]
226 fn parse_to_located_block_element() {
227 let input = Language::from_vimwiki_str("some text");
228 let _result: Located<BlockElement> =
229 input.parse().expect("Failed to parse");
230 }
231
232 #[test]
233 fn parse_to_located_inline_element_container() {
234 let input = Language::from_vimwiki_str("some text");
235 let _result: Located<InlineElementContainer> =
236 input.parse().expect("Failed to parse");
237 }
238
239 #[test]
240 fn parse_to_located_inline_element() {
241 let input = Language::from_vimwiki_str("some text");
242 let _result: Located<InlineElement> =
243 input.parse().expect("Failed to parse");
244 }
245
246 #[test]
247 fn parse_to_located_blockquote() {
248 let input = Language::from_vimwiki_str("> some text");
249 let _result: Located<Blockquote> =
250 input.parse().expect("Failed to parse");
251 }
252
253 #[test]
254 fn parse_to_located_code_inline() {
255 let input = Language::from_vimwiki_str("`code`");
256 let _result: Located<CodeInline> =
257 input.parse().expect("Failed to parse");
258 }
259
260 #[test]
261 fn parse_to_located_comment() {
262 let input = Language::from_vimwiki_str("%% some comment");
263 let _result: Located<Comment> =
264 input.parse().expect("Failed to parse");
265 }
266
267 #[test]
268 fn parse_to_located_line_comment() {
269 let input = Language::from_vimwiki_str("%% some comment");
270 let _result: Located<LineComment> =
271 input.parse().expect("Failed to parse");
272 }
273
274 #[test]
275 fn parse_to_located_multi_line_comment() {
276 let input = Language::from_vimwiki_str("%%+ some comment +%%");
277 let _result: Located<MultiLineComment> =
278 input.parse().expect("Failed to parse");
279 }
280
281 #[test]
282 fn parse_to_located_definition_list() {
283 let input = Language::from_vimwiki_str("term:: definition");
284 let _result: Located<DefinitionList> =
285 input.parse().expect("Failed to parse");
286 }
287
288 #[test]
289 fn parse_to_located_divider() {
290 let input = Language::from_vimwiki_str("----");
291 let _result: Located<Divider> =
292 input.parse().expect("Failed to parse");
293 }
294
295 #[test]
296 fn parse_to_located_header() {
297 let input = Language::from_vimwiki_str("= header =");
298 let _result: Located<Header> =
299 input.parse().expect("Failed to parse");
300 }
301
302 #[test]
303 fn parse_to_located_link() {
304 let input = Language::from_vimwiki_str("[[link]]");
305 let _result: Located<Link> =
306 input.parse().expect("Failed to parse");
307 }
308
309 #[test]
310 fn parse_to_located_list() {
311 let input = Language::from_vimwiki_str("- some list item");
312 let _result: Located<List> =
313 input.parse().expect("Failed to parse");
314 }
315
316 #[test]
317 fn parse_to_located_math_inline() {
318 let input = Language::from_vimwiki_str("$math$");
319 let _result: Located<MathInline> =
320 input.parse().expect("Failed to parse");
321 }
322
323 #[test]
324 fn parse_to_located_math_block() {
325 let input = Language::from_vimwiki_str("{{$\nmath\n}}$");
326 let _result: Located<MathBlock> =
327 input.parse().expect("Failed to parse");
328 }
329
330 #[test]
331 fn parse_to_located_paragraph() {
332 let input = Language::from_vimwiki_str("some text");
333 let _result: Located<Paragraph> =
334 input.parse().expect("Failed to parse");
335 }
336
337 #[test]
338 fn parse_to_located_placeholder() {
339 let input = Language::from_vimwiki_str("%title some text");
340 let _result: Located<Placeholder> =
341 input.parse().expect("Failed to parse");
342 }
343
344 #[test]
345 fn parse_to_located_code_block() {
346 let input = Language::from_vimwiki_str("{{{\nsome code\n}}}");
347 let _result: Located<CodeBlock> =
348 input.parse().expect("Failed to parse");
349 }
350
351 #[test]
352 fn parse_to_located_table() {
353 let input = Language::from_vimwiki_str("|cell|");
354 let _result: Located<Table> =
355 input.parse().expect("Failed to parse");
356 }
357
358 #[test]
359 fn parse_to_located_tags() {
360 let input = Language::from_vimwiki_str(":tag:");
361 let _result: Located<Tags> =
362 input.parse().expect("Failed to parse");
363 }
364
365 #[test]
366 fn parse_to_located_text() {
367 let input = Language::from_vimwiki_str("some text");
368 let _result: Located<Text> =
369 input.parse().expect("Failed to parse");
370 }
371
372 #[test]
373 fn parse_to_located_decorated_text() {
374 let input = Language::from_vimwiki_str("*some text*");
375 let _result: Located<DecoratedText> =
376 input.parse().expect("Failed to parse");
377 }
378
379 #[test]
380 fn parse_to_located_keyword() {
381 let input = Language::from_vimwiki_str("TODO");
382 let _result: Located<Keyword> =
383 input.parse().expect("Failed to parse");
384 }
385 }
386}