Skip to content

Commit ab1dcee

Browse files
Merge ClassInfo::open and ClassInfo::link_closing_tag fields into closing_tags
Improve documentation Improve code
1 parent 713cd50 commit ab1dcee

File tree

1 file changed

+49
-49
lines changed

1 file changed

+49
-49
lines changed

src/librustdoc/html/highlight.rs

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -138,32 +138,30 @@ fn can_merge(class1: Option<Class>, class2: Option<Class>, text: &str) -> bool {
138138
#[derive(Debug)]
139139
struct ClassInfo {
140140
class: Class,
141-
/// Set to true only when an item was written inside this tag.
142-
open: bool,
143-
/// Set to true when leaving the current item. The closing tag will be
144-
/// written if:
141+
/// If `Some`, then it means the tag was opened and needs to be closed.
142+
closing_tag: Option<&'static str>,
143+
/// Set to `true` by `exit_elem` to signal that all the elements of this class have been pushed.
145144
///
146-
/// 1. `self.open` is true
147-
/// 2. Only when the first non-mergeable item is pushed.
145+
/// The class will be closed and removed from the stack when the next non-mergeable item is
146+
/// pushed. When it is removed, the closing tag will be written if (and only if)
147+
/// `self.closing_tag` is `Some`.
148148
pending_exit: bool,
149-
/// If `true`, it means it's `</a>`, otherwise it's `</span>`.
150-
link_closing_tag: bool,
151149
}
152150

153151
impl ClassInfo {
154-
fn new(class: Class, pending_exit: bool) -> Self {
155-
Self { class, open: pending_exit, pending_exit, link_closing_tag: false }
152+
fn new(class: Class, closing_tag: Option<&'static str>) -> Self {
153+
Self { class, closing_tag, pending_exit: closing_tag.is_some() }
156154
}
157155

158156
fn close_tag<W: Write>(&self, out: &mut W) {
159-
if self.open {
160-
if self.link_closing_tag {
161-
out.write_str("</a>").unwrap();
162-
} else {
163-
out.write_str("</span>").unwrap();
164-
}
157+
if let Some(closing_tag) = self.closing_tag {
158+
out.write_str(closing_tag).unwrap();
165159
}
166160
}
161+
162+
fn is_open(&self) -> bool {
163+
self.closing_tag.is_some()
164+
}
167165
}
168166

169167
/// This represents the stack of HTML elements. For example a macro expansion
@@ -187,7 +185,7 @@ impl ClassStack {
187185
out: &mut W,
188186
href_context: &Option<HrefContext<'_, '_>>,
189187
new_class: Class,
190-
pending_exit: bool,
188+
closing_tag: Option<&'static str>,
191189
) {
192190
if let Some(current_class) = self.open_classes.last_mut() {
193191
if can_merge(Some(current_class.class), Some(new_class), "") {
@@ -198,22 +196,22 @@ impl ClassStack {
198196
self.open_classes.pop();
199197
}
200198
}
201-
let mut class_info = ClassInfo::new(new_class, pending_exit);
202-
if pending_exit {
203-
class_info.open = true;
204-
} else if matches!(new_class, Class::Decoration(_) | Class::Original) {
205-
// We open it right away to ensure it always come at the expected location.
206-
// FIXME: Should we instead add a new boolean field to `ClassInfo` to force a non-open
207-
// tags to be added if another one comes before it's open?
208-
write!(out, "<span class=\"{}\">", new_class.as_html()).unwrap();
209-
class_info.open = true;
210-
} else if new_class.get_span().is_some()
211-
&& let Some(closing_tag) =
212-
string_without_closing_tag(out, "", Some(class_info.class), href_context, false)
213-
&& !closing_tag.is_empty()
214-
{
215-
class_info.open = true;
216-
class_info.link_closing_tag = closing_tag == "</a>";
199+
let mut class_info = ClassInfo::new(new_class, closing_tag);
200+
if closing_tag.is_none() {
201+
if matches!(new_class, Class::Decoration(_) | Class::Original) {
202+
// Even if a whitespace characters follows, we need to open the class right away
203+
// as these characters are part of the element.
204+
// FIXME: Should we instead add a new boolean field to `ClassInfo` to force a
205+
// non-open tag to be added if another one comes before it's open?
206+
write!(out, "<span class=\"{}\">", new_class.as_html()).unwrap();
207+
class_info.closing_tag = Some("</span>");
208+
} else if new_class.get_span().is_some()
209+
&& let Some(closing_tag) =
210+
string_without_closing_tag(out, "", Some(class_info.class), href_context, false)
211+
&& !closing_tag.is_empty()
212+
{
213+
class_info.closing_tag = Some(closing_tag);
214+
}
217215
}
218216

219217
self.open_classes.push(class_info);
@@ -242,20 +240,17 @@ impl ClassStack {
242240

243241
fn last_class_is_open(&self) -> bool {
244242
if let Some(last) = self.open_classes.last() {
245-
last.open
243+
last.is_open()
246244
} else {
247245
// If there is no class, then it's already open.
248246
true
249247
}
250248
}
251249

252250
fn close_last_if_needed<W: Write>(&mut self, out: &mut W) {
253-
if let Some(last) = self.open_classes.last()
254-
&& last.pending_exit
255-
&& last.open
251+
if let Some(last) = self.open_classes.pop_if(|class| class.pending_exit && class.is_open())
256252
{
257253
last.close_tag(out);
258-
self.open_classes.pop();
259254
}
260255
}
261256

@@ -284,11 +279,11 @@ impl ClassStack {
284279
if !class_s.is_empty() {
285280
write!(out, "<span class=\"{class_s}\">").unwrap();
286281
}
287-
current_class_info.open = true;
282+
current_class_info.closing_tag = Some("</span>");
288283
}
289284
}
290285

291-
let current_class_is_open = self.open_classes.last().is_some_and(|c| c.open);
286+
let current_class_is_open = self.open_classes.last().is_some_and(|c| c.is_open());
292287
let can_merge = can_merge(class, current_class, &text);
293288
let should_open_tag = !current_class_is_open || !can_merge;
294289

@@ -312,14 +307,20 @@ impl ClassStack {
312307
} else if let Some(class) = class
313308
&& !can_merge
314309
{
315-
self.enter_elem(out, href_context, class, true);
310+
self.enter_elem(out, href_context, class, Some("</span>"));
316311
// Otherwise, we consider the actual `Class` to have been open.
317312
} else if let Some(current_class_info) = self.open_classes.last_mut() {
318-
current_class_info.open = true;
313+
current_class_info.closing_tag = Some("</span>");
319314
}
320315
}
321316
}
322317

318+
/// This method closes all open tags and returns the list of `Class` which were not already
319+
/// closed (ie `pending_exit` set to `true`).
320+
///
321+
/// It is used when starting a macro expansion: we need to close all HTML tags and then to
322+
/// reopen them inside the newly created expansion HTML tag. Same goes when we close the
323+
/// expansion.
323324
fn empty_stack<W: Write>(&mut self, out: &mut W) -> Vec<Class> {
324325
let mut classes = Vec::with_capacity(self.open_classes.len());
325326

@@ -387,7 +388,7 @@ impl<'a, F: Write> TokenHandler<'a, '_, F> {
387388
let classes = self.class_stack.empty_stack(self.out);
388389

389390
// We start the expansion tag.
390-
self.class_stack.enter_elem(self.out, &self.href_context, Class::Expansion, false);
391+
self.class_stack.enter_elem(self.out, &self.href_context, Class::Expansion, None);
391392
self.push_token_without_backline_check(
392393
Some(Class::Expansion),
393394
Cow::Owned(format!(
@@ -401,9 +402,9 @@ impl<'a, F: Write> TokenHandler<'a, '_, F> {
401402
false,
402403
);
403404

404-
// We re-open all tags.
405+
// We re-open all tags that didn't have `pending_exit` set to `true`.
405406
for class in classes.into_iter().rev() {
406-
self.class_stack.enter_elem(self.out, &self.href_context, class, false);
407+
self.class_stack.enter_elem(self.out, &self.href_context, class, None);
407408
}
408409
}
409410

@@ -413,7 +414,7 @@ impl<'a, F: Write> TokenHandler<'a, '_, F> {
413414
Cow::Owned(format!("<span class=expanded>{}</span>", expanded_code.code)),
414415
false,
415416
);
416-
self.class_stack.enter_elem(self.out, &self.href_context, Class::Original, false);
417+
self.class_stack.enter_elem(self.out, &self.href_context, Class::Original, None);
417418
}
418419

419420
fn close_expansion(&mut self) {
@@ -423,7 +424,7 @@ impl<'a, F: Write> TokenHandler<'a, '_, F> {
423424
// We re-open all tags without expansion-related ones.
424425
for class in classes.into_iter().rev() {
425426
if !matches!(class, Class::Expansion | Class::Original) {
426-
self.class_stack.enter_elem(self.out, &self.href_context, class, false);
427+
self.class_stack.enter_elem(self.out, &self.href_context, class, None);
427428
}
428429
}
429430
}
@@ -604,7 +605,7 @@ pub(super) fn write_code(
604605
token_handler.out,
605606
&token_handler.href_context,
606607
class,
607-
false,
608+
None,
608609
);
609610
}
610611
Highlight::ExitSpan => {
@@ -706,7 +707,6 @@ impl Class {
706707
| Self::Lifetime
707708
| Self::QuestionMark
708709
| Self::Decoration(_)
709-
// | Self::Backline(_)
710710
| Self::Original
711711
| Self::Expansion => None,
712712
}

0 commit comments

Comments
 (0)