1use pulldown_cmark::{Event, Parser, Tag};
3
4pub(crate) fn remove_markdown(markdown: &str) -> String {
8 let mut out = String::new();
9 out.reserve_exact(markdown.len());
10 let parser = Parser::new(markdown);
11
12 for event in parser {
13 match event {
14 Event::Text(text) | Event::Code(text) => out.push_str(&text),
15 Event::SoftBreak => out.push(' '),
16 Event::HardBreak | Event::Rule | Event::End(Tag::CodeBlock(_)) => out.push('\n'),
17 Event::End(Tag::Paragraph) => out.push_str("\n\n"),
18 Event::Start(_)
19 | Event::End(_)
20 | Event::Html(_)
21 | Event::FootnoteReference(_)
22 | Event::TaskListMarker(_) => (),
23 }
24 }
25
26 if let Some(mut p) = out.rfind(|c| c != '\n') {
27 while !out.is_char_boundary(p + 1) {
28 p += 1;
29 }
30 out.drain(p + 1..);
31 }
32
33 out
34}
35
36#[cfg(test)]
37mod tests {
38 use expect_test::expect;
39
40 use super::*;
41
42 #[test]
43 fn smoke_test() {
44 let res = remove_markdown(
45 r##"
46A function or function pointer.
47
48Functions are the primary way code is executed within Rust. Function blocks, usually just
49called functions, can be defined in a variety of different places and be assigned many
50different attributes and modifiers.
51
52Standalone functions that just sit within a module not attached to anything else are common,
53but most functions will end up being inside [`impl`] blocks, either on another type itself, or
54as a trait impl for that type.
55
56```rust
57fn standalone_function() {
58 // code
59}
60
61pub fn public_thing(argument: bool) -> String {
62 // code
63 # "".to_string()
64}
65
66struct Thing {
67 foo: i32,
68}
69
70impl Thing {
71 pub fn new() -> Self {
72 Self {
73 foo: 42,
74 }
75 }
76}
77```
78
79In addition to presenting fixed types in the form of `fn name(arg: type, ..) -> return_type`,
80functions can also declare a list of type parameters along with trait bounds that they fall
81into.
82
83```rust
84fn generic_function<T: Clone>(x: T) -> (T, T, T) {
85 (x.clone(), x.clone(), x.clone())
86}
87
88fn generic_where<T>(x: T) -> T
89 where T: std::ops::Add<Output = T> + Copy
90{
91 x + x + x
92}
93```
94
95Declaring trait bounds in the angle brackets is functionally identical to using a `where`
96clause. It's up to the programmer to decide which works better in each situation, but `where`
97tends to be better when things get longer than one line.
98
99Along with being made public via `pub`, `fn` can also have an [`extern`] added for use in
100FFI.
101
102For more information on the various types of functions and how they're used, consult the [Rust
103book] or the [Reference].
104
105[`impl`]: keyword.impl.html
106[`extern`]: keyword.extern.html
107[Rust book]: ../book/ch03-03-how-functions-work.html
108[Reference]: ../reference/items/functions.html
109"##,
110 );
111 expect![[r#"
112 A function or function pointer.
113
114 Functions are the primary way code is executed within Rust. Function blocks, usually just called functions, can be defined in a variety of different places and be assigned many different attributes and modifiers.
115
116 Standalone functions that just sit within a module not attached to anything else are common, but most functions will end up being inside impl blocks, either on another type itself, or as a trait impl for that type.
117
118 fn standalone_function() {
119 // code
120 }
121
122 pub fn public_thing(argument: bool) -> String {
123 // code
124 # "".to_string()
125 }
126
127 struct Thing {
128 foo: i32,
129 }
130
131 impl Thing {
132 pub fn new() -> Self {
133 Self {
134 foo: 42,
135 }
136 }
137 }
138
139 In addition to presenting fixed types in the form of fn name(arg: type, ..) -> return_type, functions can also declare a list of type parameters along with trait bounds that they fall into.
140
141 fn generic_function<T: Clone>(x: T) -> (T, T, T) {
142 (x.clone(), x.clone(), x.clone())
143 }
144
145 fn generic_where<T>(x: T) -> T
146 where T: std::ops::Add<Output = T> + Copy
147 {
148 x + x + x
149 }
150
151 Declaring trait bounds in the angle brackets is functionally identical to using a where clause. It's up to the programmer to decide which works better in each situation, but where tends to be better when things get longer than one line.
152
153 Along with being made public via pub, fn can also have an extern added for use in FFI.
154
155 For more information on the various types of functions and how they're used, consult the Rust book or the Reference."#]].assert_eq(&res);
156 }
157
158 #[test]
159 fn on_char_boundary() {
160 expect!["a┘"].assert_eq(&remove_markdown("```text\na┘\n```"));
161 expect!["وقار"].assert_eq(&remove_markdown("```\nوقار\n```\n"));
162 }
163}