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
132
133
//! This parser was written for use with [cheesecake](https://github.com/cubetastic33/cheesecake),
//! so the convertor function provided is designed for that. If this function doesn't suit your
//! use-case, you can write your own convertor function to generate HTML from the parsed AST. The
//! text in the generated HTML will be HTML-escaped, so you can safely insert the output into the
//! DOM.
//!
//! # Usage
//! Call `parser::parse` on the input string, and it will return a vector of `Expression`s. Supply
//! this vector to `convertor::to_html` to get an HTML string. If your input text will also have
//! custom emoji, user mentions, role mentions, or channel mentions, then use
//! `convertor::to_html_with_callbacks` instead.
//!
//! Call `parser::parse_with_md_hyperlinks` instead if you want to also parse links with alt text,
//! which is supported in discord embeds (Like `[example](https://example.com)`)
//!
//! ### Note:
//! Newlines are not converted to `Expression::Newline` inside code blocks, so that must be handled
//! in the covertor.
//!
//! # Examples
//!
//! If all you want is to generate the AST, it's really simple:
//! ```
//! use discord_markdown::parser::{parse, Expression::*};
//!
//! fn main() {
//! let ast = parse("> _**example** formatted_ ||string||");
//! assert_eq!(ast, vec![
//! Blockquote(vec![
//! Italics(vec![
//! Bold(vec![Text("example")]),
//! Text(" formatted"),
//! ]),
//! Text(" "),
//! Spoiler(vec![Text("string")]),
//! ]),
//! ]);
//! }
//! ```
//!
//! If you want to generate an HTML string, it's like this:
//! ```
//! use discord_markdown::{parser::parse, convertor::*};
//!
//! fn dummy_callback(x: &str) -> (String, Option<String>) {
//! (x.to_owned(), None)
//! }
//!
//! fn id_to_name(id: &str) -> (String, Option<String>) {
//! (
//! if id == "123456789123456789" {"member"} else {"unknown role"}.to_owned(),
//! Some("#ff0000".to_owned()),
//! )
//! }
//!
//! fn main() {
//! let html = to_html(parse("> _**example** formatted_ ||string||"));
//! assert_eq!(html, "<blockquote><em><strong>example</strong> formatted\
//! </em> <span class=\"spoiler\">string</span></blockquote>");
//!
//! // With role mentions
//! let html = to_html_with_callbacks(
//! parse("<@&123456789123456789>"),
//! dummy_callback,
//! dummy_callback,
//! id_to_name,
//! dummy_callback,
//! );
//! assert_eq!(html, "<div class=\"role\" style=\"color: #ff0000\">@member\
//! <span style=\"background-color: #ff0000\"></span></div>");
//! }
//! ```
//!
//! You can then add styling for `.role` and `.role span` in your stylesheet. Here's some example
//! CSS:
//! ```css
//! .role {
//! background-color: initial;
//! display: inline-block;
//! position: relative;
//! word-break: keep-all;
//! }
//!
//! .role span {
//! border-radius: 4px;
//! height: 100%;
//! width: 100%;
//! opacity: .12;
//! position: absolute;
//! left: 0;
//! top: 0;
//! }
//! ```