Skip to main content

rink_core/output/
doc_string.rs

1use std::fmt;
2
3use serde_derive::Serialize;
4
5use super::fmt::{Span, TokenFmt};
6
7#[derive(Debug, Clone, PartialEq, Serialize)]
8#[serde(transparent)]
9pub struct DocString {
10    pub text: String,
11}
12
13impl DocString {
14    pub fn new(text: impl Into<String>) -> DocString {
15        DocString { text: text.into() }
16    }
17}
18
19impl fmt::Display for DocString {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        self.text.fmt(f)
22    }
23}
24
25#[derive(PartialEq, Eq, Clone, Copy, Debug)]
26enum DocState {
27    Plain,
28    Link,
29    Date,
30}
31
32struct DocParser<'a> {
33    tokens: Vec<Span<'a>>,
34    current: String,
35    state: DocState,
36}
37
38impl<'a> DocParser<'a> {
39    fn finish(&mut self) {
40        if !self.current.is_empty() {
41            let current = std::mem::replace(&mut self.current, String::new());
42            match self.state {
43                DocState::Plain => self.tokens.push(Span::doc_string(current)),
44                DocState::Date => self.tokens.push(Span::date_time(current)),
45                DocState::Link => self.tokens.push(Span::link(current)),
46            }
47            self.state = DocState::Plain;
48        }
49    }
50}
51
52impl<'a> TokenFmt<'a> for DocString {
53    fn to_spans(&'a self) -> Vec<Span<'a>> {
54        let mut parser = DocParser {
55            tokens: vec![],
56            current: String::new(),
57            state: DocState::Plain,
58        };
59
60        for ch in self.text.chars() {
61            match ch {
62                '>' if parser.state == DocState::Link => parser.finish(),
63                _ if parser.state == DocState::Link => parser.current.push(ch),
64                '#' if parser.state == DocState::Date => parser.finish(),
65                _ if parser.state == DocState::Date => parser.current.push(ch),
66                '<' => {
67                    parser.finish();
68                    parser.state = DocState::Link;
69                }
70                '#' => {
71                    parser.finish();
72                    parser.state = DocState::Date;
73                }
74                _ => parser.current.push(ch),
75            }
76        }
77        parser.finish();
78
79        parser.tokens
80    }
81}