Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions slicec/src/parsers/comments/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,20 @@ InlineLink: LinkTag = {
}

Section: Message = {
<l: @L> <inline_message: (":" <Message?>)?> newline <message_lines: MessageLines?> <r: @R> => {
<l: @L> <inline_message: (":" <Message>)?> newline <message_lines: MessageLines?> <r: @R> => {
let span = Span::new(l, r, comment_parser.file_name);
construct_section_message(inline_message.flatten(), message_lines, span)
construct_section_message(inline_message, message_lines, span)
},
}

MessageLines: Message = {
<l: @L> <m: (<Message?> newline)+> <r: @R> => {
<l: @L> <m: (<Message> newline)+> <r: @R> => {
let span = Span::new(l, r, comment_parser.file_name);
sanitize_message_lines(m, span)
}
}

Message = MessageComponent+;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a grammar level, these two constructs should be equivalent:
(MessageComponent+)? (match 1 more components, but also accept 0 components)
MessageComponent* (match 0 or more components)

But in addition to being a simpler rule, it also simplifies the types.
The 1st expression gives Option<Vec<...>>, whereas the 2nd gives just Vec<...>.

Message = MessageComponent*;

MessageComponent: MessageComponent = {
<text: text> => MessageComponent::Text(text.to_owned()),
Expand Down
27 changes: 10 additions & 17 deletions slicec/src/parsers/comments/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ fn construct_section_message(
) -> Message {
let mut value = message_lines.map(|m| m.value).unwrap_or_default();

if let Some(mut message) = inline_message {
if let Some(mut message) = inline_message.filter(|m| !m.is_empty()) {
// Remove any leading whitespace from the inline portion of the message.
if let Some(MessageComponent::Text(text)) = message.first_mut() {
*text = text.trim_start().to_owned();
Expand All @@ -86,19 +86,17 @@ fn construct_section_message(
}

/// Removes any common leading whitespace from the provided lines and returns the result.
/// Each element in the vector represents one line of the message.
/// `None` means the line existed but was empty, `Some(message)` means the line had a message.
/// Each element in the outermost vector represents one line of the message. These lines may be empty.
///
/// Note that the message's span is not updated to reflect the stripping of common leading whitespace.
fn sanitize_message_lines(lines: Vec<Option<Vec<MessageComponent>>>, span: Span) -> Message {
fn sanitize_message_lines(lines: Vec<Vec<MessageComponent>>, span: Span) -> Message {
Comment thread
InsertCreativityHere marked this conversation as resolved.
Resolved
// First compute the amount of leading whitespace that is common to every line.
let mut common_leading_whitespace = usize::MAX;
for line in &lines {
// We only check lines that have a message on them (eg: they're non-empty).
if let Some(message) = &line {
if let Some(message) = line.first() {
// To check the start of the line, we check the first message component.
// It's safe to unwrap because we know the line was non-empty in this block.
match message.first().unwrap() {
match message {
MessageComponent::Text(text) => {
// Determine how many whitespace characters are at the beginning of this line,
// then take the minimum of this and the amount of whitespace on all the other lines so far.
Expand All @@ -118,18 +116,13 @@ fn sanitize_message_lines(lines: Vec<Option<Vec<MessageComponent>>>, span: Span)
// Now that we know the common leading whitespace, we iterate through the lines again and remove the whitespace.
let value = lines
.into_iter()
.flat_map(|line| match line {
.flat_map(|mut line| {
// If the message had text, we remove the common leading whitespace and append a newline at the end.
Some(mut message) => {
if let MessageComponent::Text(text) = message.first_mut().unwrap() {
text.replace_range(..common_leading_whitespace, "");
}
message.push(MessageComponent::Text("\n".to_owned()));
message
if let Some(MessageComponent::Text(text)) = line.first_mut() {
text.replace_range(..common_leading_whitespace, "");
}

// If the line was empty, we create a new message that only contains a newline character.
None => vec![MessageComponent::Text("\n".to_owned())],
line.push(MessageComponent::Text("\n".to_owned()));
line
})
.collect();

Expand Down