rink_core/output/
doc_string.rs1use 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}