1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use super::Nesting;
use crate::types::parameters::Text;
use std::{
fmt::{self, Display, Formatter, Write},
ops::Deref,
};
pub const ESCAPED_TEXT_CHARACTERS: [char; 19] = [
'_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{',
'}', '.', '!', '\\',
];
pub const ESCAPED_CODE_CHARACTERS: [char; 2] = ['`', '\\'];
pub const ESCAPED_LINK_CHARACTERS: [char; 2] = [')', '\\'];
pub trait Formattable {
#[doc(hidden)]
fn format(
&self,
formatter: &mut Formatter,
nesting: Nesting,
) -> fmt::Result;
}
impl_primitives!(Formattable);
impl_tuples!(Formattable);
impl Formattable for char {
fn format(&self, formatter: &mut Formatter, _: Nesting) -> fmt::Result {
if ESCAPED_TEXT_CHARACTERS.contains(self) {
formatter.write_char('\\')?;
}
formatter.write_char(*self)
}
}
impl Formattable for &'_ str {
fn format(
&self,
formatter: &mut Formatter,
nesting: Nesting,
) -> fmt::Result {
self.chars()
.try_for_each(|character| character.format(formatter, nesting))
}
}
impl Formattable for String {
fn format(
&self,
formatter: &mut Formatter,
nesting: Nesting,
) -> fmt::Result {
self.as_str().format(formatter, nesting)
}
}
impl<T: Formattable> Formattable for &'_ [T] {
fn format(
&self,
formatter: &mut Formatter,
nesting: Nesting,
) -> fmt::Result {
self.iter().try_for_each(|x| x.format(formatter, nesting))
}
}
impl<T: Formattable> Formattable for Vec<T> {
fn format(
&self,
formatter: &mut Formatter,
nesting: Nesting,
) -> fmt::Result {
self.as_slice().format(formatter, nesting)
}
}
impl<T: Formattable + ?Sized> Formattable for Box<T> {
fn format(
&self,
formatter: &mut Formatter,
nesting: Nesting,
) -> fmt::Result {
self.deref().format(formatter, nesting)
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
#[must_use = "MarkdownV2 needs to be turned into a `Text` instance"]
pub struct MarkdownV2<T>(T);
struct Displayable<T>(MarkdownV2<T>);
pub const fn markdown_v2<T: Formattable>(content: T) -> MarkdownV2<T> {
MarkdownV2(content)
}
impl<T: Formattable> Formattable for MarkdownV2<T> {
fn format(
&self,
formatter: &mut Formatter,
nesting: Nesting,
) -> fmt::Result {
self.0.format(formatter, nesting)
}
}
impl<T: Formattable> Display for Displayable<T> {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
self.0.format(formatter, Nesting::default())
}
}
impl<T: Formattable> From<MarkdownV2<T>> for Text {
fn from(markup: MarkdownV2<T>) -> Self {
let message = Displayable(markup).to_string();
Self::with_markdown_v2(message)
}
}