ide/
markdown_remove.rs

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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! Removes markdown from strings.
use pulldown_cmark::{Event, Parser, Tag};

/// Removes all markdown, keeping the text and code blocks
///
/// Currently limited in styling, i.e. no ascii tables or lists
pub(crate) fn remove_markdown(markdown: &str) -> String {
    let mut out = String::new();
    out.reserve_exact(markdown.len());
    let parser = Parser::new(markdown);

    for event in parser {
        match event {
            Event::Text(text) | Event::Code(text) => out.push_str(&text),
            Event::SoftBreak => out.push(' '),
            Event::HardBreak | Event::Rule | Event::End(Tag::CodeBlock(_)) => out.push('\n'),
            Event::End(Tag::Paragraph) => out.push_str("\n\n"),
            Event::Start(_)
            | Event::End(_)
            | Event::Html(_)
            | Event::FootnoteReference(_)
            | Event::TaskListMarker(_) => (),
        }
    }

    if let Some(mut p) = out.rfind(|c| c != '\n') {
        while !out.is_char_boundary(p + 1) {
            p += 1;
        }
        out.drain(p + 1..);
    }

    out
}

#[cfg(test)]
mod tests {
    use expect_test::expect;

    use super::*;

    #[test]
    fn smoke_test() {
        let res = remove_markdown(
            r##"
A function or function pointer.

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.

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.

```rust
fn standalone_function() {
    // code
}

pub fn public_thing(argument: bool) -> String {
    // code
    # "".to_string()
}

struct Thing {
    foo: i32,
}

impl Thing {
    pub fn new() -> Self {
        Self {
            foo: 42,
        }
    }
}
```

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.

```rust
fn generic_function<T: Clone>(x: T) -> (T, T, T) {
    (x.clone(), x.clone(), x.clone())
}

fn generic_where<T>(x: T) -> T
    where T: std::ops::Add<Output = T> + Copy
{
    x + x + x
}
```

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.

Along with being made public via `pub`, `fn` can also have an [`extern`] added for use in
FFI.

For more information on the various types of functions and how they're used, consult the [Rust
book] or the [Reference].

[`impl`]: keyword.impl.html
[`extern`]: keyword.extern.html
[Rust book]: ../book/ch03-03-how-functions-work.html
[Reference]: ../reference/items/functions.html
"##,
        );
        expect![[r#"
            A function or function pointer.

            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.

            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.

            fn standalone_function() {
                // code
            }

            pub fn public_thing(argument: bool) -> String {
                // code
                # "".to_string()
            }

            struct Thing {
                foo: i32,
            }

            impl Thing {
                pub fn new() -> Self {
                    Self {
                        foo: 42,
                    }
                }
            }

            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.

            fn generic_function<T: Clone>(x: T) -> (T, T, T) {
                (x.clone(), x.clone(), x.clone())
            }

            fn generic_where<T>(x: T) -> T
                where T: std::ops::Add<Output = T> + Copy
            {
                x + x + x
            }

            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.

            Along with being made public via pub, fn can also have an extern added for use in FFI.

            For more information on the various types of functions and how they're used, consult the Rust book or the Reference."#]].assert_eq(&res);
    }

    #[test]
    fn on_char_boundary() {
        expect!["a┘"].assert_eq(&remove_markdown("```text\na┘\n```"));
        expect!["وقار"].assert_eq(&remove_markdown("```\nوقار\n```\n"));
    }
}