Skip to content

Recognize multi-line unattached attributes #108

Open
black-desk wants to merge 3 commits into
hellux:masterfrom
black-desk:multi-line-attributes
Open

Recognize multi-line unattached attributes #108
black-desk wants to merge 3 commits into
hellux:masterfrom
black-desk:multi-line-attributes

Conversation

@black-desk
Copy link
Copy Markdown

No description provided.

Comment thread src/block.rs Outdated
Copy link
Copy Markdown
Owner

@hellux hellux left a comment

Choose a reason for hiding this comment

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

Thanks for looking into this.

Comment thread tests/html.rs Outdated
Comment thread tests/html.rs Outdated
Comment thread src/block.rs Outdated
Comment thread src/block.rs Outdated
@black-desk black-desk force-pushed the multi-line-attributes branch 3 times, most recently from bef8cc7 to 499e59c Compare April 29, 2026 08:53
test rendering of attributes that span multiple lines and are not
attached to any element

Assisted-by: Claude:glm-5.1
Signed-off-by: Chen Linxuan <me@black-desk.cn>
When an attribute block spans multiple lines (e.g. `{ .a\n }`), the
block parser only checked the first line with attr::valid() and
classified it as a paragraph since the attribute was incomplete on that
line alone. Add a post-check in parse_block() that re-examines
multi-line paragraphs starting with `{` to see if the combined text
forms a valid attribute block.

Assisted-by: Claude:glm-5.1
Signed-off-by: Chen Linxuan <me@black-desk.cn>
@black-desk black-desk force-pushed the multi-line-attributes branch from 499e59c to 4fa293b Compare April 29, 2026 08:55
When a paragraph starts with an incomplete attribute (e.g. `{#id
.class` without closing `}`), detect whether subsequent lines complete
it. If the completed attribute is followed by more content, split the
block: emit the attribute event first, then let the caller parse the
remaining lines as a separate paragraph block.

This resolves the multi-line block attributes test case from hellux#53.

Assisted-by: Claude Code:glm-5.1
Signed-off-by: Chen Linxuan <me@black-desk.cn>
@black-desk black-desk force-pushed the multi-line-attributes branch from 4fa293b to 09658a0 Compare April 29, 2026 08:57
@black-desk black-desk requested a review from hellux April 29, 2026 09:21
Copy link
Copy Markdown
Owner

@hellux hellux left a comment

Choose a reason for hiding this comment

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

There is a fuzzer that can be used to detect some bugs, it can be run with make afl. It can take a while to find some rare things so the CI step sometimes misses things because it only runs for one minute.

However, running it locally I found some errors after a few minutes, there seems to be an issue with multi-line attrs before a header, e.g:

# header 1

- list

{.attrs
 }
# header 2

yields

<section id="header-1">
<h1>header 1</h1>
<ul>
<li>
list
</li>
</section> <!-- this should be swapped -->
</ul> <!-- with this -->
<section id="header-2">
<h1>header 2</h1> <!-- missing class="attrs" -->
</section>

The open_sections part does some manipulation of the events that may not interact with the multi-line attributes correctly.

Comment thread tests/parse_events.rs
"{ .a }\n", //
),
(Attributes(attrs![(AttributeKind::Class, "a")]), "{ .a }\n"),
);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This case is covered in attr_block_dangling above.

A paragraph
.
<p id="id" class="class" style="color:red">A paragraph</p>
```
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This test already exists in the the djot_attributes.test file (test_html_ut symlinks it from reference implementation) so no need to add it here.

Comment thread tests/parse_events.rs
" }\n", //
),
(Attributes(attrs![(AttributeKind::Class, "a")]), "{ .a\n }"),
);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

May also try attributes in nested quotes:

> {#id .class
>   style="color:red"}

This seems to crash now because we get the > as part of the attributes:

panicked at src/lib.rs:2646:30:
should be valid: 12

Comment thread tests/parse_events.rs
),
(Str("A paragraph".into()), "A paragraph"),
(End(Paragraph), ""),
);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This should also work with nested blocks:

> {#id .class
>  style="color:red"}
> A paragraph

but also crashes atm.

Comment thread tests/parse_events.rs
" }\n", //
),
(Attributes(attrs![(AttributeKind::Class, "a")]), "{ .a\n }"),
);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

May also try non-indented continuation. As per the syntax reference:

Block attributes have the same syntax as inline attributes, but if they don’t fit on one line, subsequent lines must be indented.

So

{.a
 }

should be parsed as attributes, while

{.a
}

should not. Right now they seem to parsed as attributes with or without indentation.

Comment thread tests/parse_events.rs
),
(Str("A paragraph".into()), "A paragraph"),
(End(Paragraph), ""),
);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Should also not allow non indented continuation, i.e.

{#id .class
style="color:red"}
A paragraph

should not be parsed as attributes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants