@@ -33,48 +33,80 @@ pub(crate) struct HrefContext<'a, 'b, 'c> {
33
33
34
34
/// Decorations are represented as a map from CSS class to vector of character ranges.
35
35
/// Each range will be wrapped in a span with that class.
36
+ #[derive(Default)]
36
37
pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>);
37
38
38
- /// Highlights `src`, returning the HTML output.
39
- pub(crate) fn render_with_highlighting(
39
+ #[derive(Eq, PartialEq, Clone, Copy)]
40
+ pub(crate) enum Tooltip {
41
+ Ignore,
42
+ CompileFail,
43
+ ShouldPanic,
44
+ Edition(Edition),
45
+ None,
46
+ }
47
+
48
+ /// Highlights `src` as an inline example, returning the HTML output.
49
+ pub(crate) fn render_example_with_highlighting(
40
50
src: &str,
41
51
out: &mut Buffer,
42
- class: Option<&str> ,
52
+ tooltip: Tooltip ,
43
53
playground_button: Option<&str>,
44
- tooltip: Option<(Option<Edition>, &str)>,
45
- edition: Edition,
46
- extra_content: Option<Buffer>,
47
- href_context: Option<HrefContext<'_, '_, '_>>,
48
- decoration_info: Option<DecorationInfo>,
49
54
) {
50
- debug!("highlighting: ================\n{}\n==============", src);
51
- if let Some((edition_info, class)) = tooltip {
55
+ let class = match tooltip {
56
+ Tooltip::Ignore => " ignore",
57
+ Tooltip::CompileFail => " compile_fail",
58
+ Tooltip::ShouldPanic => " should_panic",
59
+ Tooltip::Edition(_) => " edition",
60
+ Tooltip::None => "",
61
+ };
62
+
63
+ if tooltip != Tooltip::None {
52
64
write!(
53
65
out,
54
- "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>",
66
+ "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
55
67
class,
56
- if let Some (edition_info) = edition_info {
68
+ if let Tooltip::Edition (edition_info) = tooltip {
57
69
format!(" data-edition=\"{}\"", edition_info)
58
70
} else {
59
71
String::new()
60
72
},
61
73
);
62
74
}
63
75
64
- write_header(out, class, extra_content );
65
- write_code(out, src, edition, href_context, decoration_info );
76
+ write_header(out, &format!("rust-example-rendered{}", class), None );
77
+ write_code(out, src, None, None );
66
78
write_footer(out, playground_button);
67
79
}
68
80
69
- fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) {
81
+ /// Highlights `src` as a macro, returning the HTML output.
82
+ pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
83
+ write_header(out, "macro", None);
84
+ write_code(out, src, None, None);
85
+ write_footer(out, None);
86
+ }
87
+
88
+ /// Highlights `src` as a source code page, returning the HTML output.
89
+ pub(crate) fn render_source_with_highlighting(
90
+ src: &str,
91
+ out: &mut Buffer,
92
+ line_numbers: Buffer,
93
+ href_context: HrefContext<'_, '_, '_>,
94
+ decoration_info: DecorationInfo,
95
+ ) {
96
+ write_header(out, "", Some(line_numbers));
97
+ write_code(out, src, Some(href_context), Some(decoration_info));
98
+ write_footer(out, None);
99
+ }
100
+
101
+ fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) {
70
102
write!(out, "<div class=\"example-wrap\">");
71
103
if let Some(extra) = extra_content {
72
104
out.push_buffer(extra);
73
105
}
74
- if let Some(class) = class {
75
- write!(out, "<pre class=\"rust {}\">", class);
76
- } else {
106
+ if class.is_empty() {
77
107
write!(out, "<pre class=\"rust\">");
108
+ } else {
109
+ write!(out, "<pre class=\"rust {}\">", class);
78
110
}
79
111
write!(out, "<code>");
80
112
}
@@ -93,7 +125,6 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
93
125
fn write_code(
94
126
out: &mut Buffer,
95
127
src: &str,
96
- edition: Edition,
97
128
href_context: Option<HrefContext<'_, '_, '_>>,
98
129
decoration_info: Option<DecorationInfo>,
99
130
) {
@@ -102,7 +133,6 @@ fn write_code(
102
133
let mut closing_tags: Vec<&'static str> = Vec::new();
103
134
Classifier::new(
104
135
&src,
105
- edition,
106
136
href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
107
137
decoration_info,
108
138
)
@@ -220,7 +250,7 @@ impl<'a> Iterator for TokenIter<'a> {
220
250
}
221
251
222
252
/// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
223
- fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
253
+ fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> {
224
254
let ignore: &[&str] =
225
255
if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
226
256
if ignore.iter().any(|k| *k == text) {
@@ -229,7 +259,7 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool)
229
259
Some(match text {
230
260
"ref" | "mut" => Class::RefKeyWord,
231
261
"false" | "true" => Class::Bool,
232
- _ if Symbol::intern(text).is_reserved(|| edition ) => Class::KeyWord,
262
+ _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021 ) => Class::KeyWord,
233
263
_ => return None,
234
264
})
235
265
}
@@ -311,7 +341,6 @@ struct Classifier<'a> {
311
341
in_attribute: bool,
312
342
in_macro: bool,
313
343
in_macro_nonterminal: bool,
314
- edition: Edition,
315
344
byte_pos: u32,
316
345
file_span: Span,
317
346
src: &'a str,
@@ -321,20 +350,14 @@ struct Classifier<'a> {
321
350
impl<'a> Classifier<'a> {
322
351
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
323
352
/// file span which will be used later on by the `span_correspondance_map`.
324
- fn new(
325
- src: &str,
326
- edition: Edition,
327
- file_span: Span,
328
- decoration_info: Option<DecorationInfo>,
329
- ) -> Classifier<'_> {
353
+ fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
330
354
let tokens = PeekIter::new(TokenIter { src });
331
355
let decorations = decoration_info.map(Decorations::new);
332
356
Classifier {
333
357
tokens,
334
358
in_attribute: false,
335
359
in_macro: false,
336
360
in_macro_nonterminal: false,
337
- edition,
338
361
byte_pos: 0,
339
362
file_span,
340
363
src,
@@ -354,7 +377,6 @@ impl<'a> Classifier<'a> {
354
377
let start = self.byte_pos as usize;
355
378
let mut pos = start;
356
379
let mut has_ident = false;
357
- let edition = self.edition;
358
380
359
381
loop {
360
382
let mut nb = 0;
@@ -376,7 +398,7 @@ impl<'a> Classifier<'a> {
376
398
377
399
if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
378
400
if *token == TokenKind::Ident {
379
- let class = get_real_ident_class(text, edition, true);
401
+ let class = get_real_ident_class(text, true);
380
402
(class, text)
381
403
} else {
382
404
// Doesn't matter which Class we put in here...
@@ -634,7 +656,7 @@ impl<'a> Classifier<'a> {
634
656
sink(Highlight::Token { text, class: None });
635
657
return;
636
658
}
637
- TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
659
+ TokenKind::Ident => match get_real_ident_class(text, false) {
638
660
None => match text {
639
661
"Option" | "Result" => Class::PreludeTy,
640
662
"Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
0 commit comments