Skip to content

Collapse nested character markup to single level (BL-16387)#8019

Open
StephenMcConnel wants to merge 3 commits into
masterfrom
BL-16387-NestedCharMarkup
Open

Collapse nested character markup to single level (BL-16387)#8019
StephenMcConnel wants to merge 3 commits into
masterfrom
BL-16387-NestedCharMarkup

Conversation

@StephenMcConnel

@StephenMcConnel StephenMcConnel commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

For example, ... goes to ....

Devin review


This change is Reviewable

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR extends UpdateCharacterStyleMarkup to flatten one level of same-tag nesting (e.g. <b><b>…</b></b><strong>…</strong>, <em><em>…</em></em><em>…</em>) that can appear in pasted content. A second conditional pass of the <b>/<i><strong>/<em> regex plus a new deduplication regex handles the collapse; <sup> nesting is intentionally left intact because double superscript has a distinct visual effect.

  • Two additional conditional regex passes convert residual nested <b> or <i> tags left over after the first pass, followed by a deduplication regex <(strong|em|u)>([^<>]*)<\1>…</\1> that merges the resulting doubled <strong>/<em>/<u> elements.
  • The existing empty-tag removal regex gains RegexOptions.IgnoreCase for consistency with every other replacement in the method.
  • Two new test methods cover nested same-tag collapse (including the intentional <sup> exception) and multi-tag paragraphs with mixed nesting.

Important Files Changed

Filename Overview
src/BloomExe/Book/Book.cs Adds two extra passes of <b>/<i><strong>/<em> conversion to handle one level of nested old-style tags, then a deduplication regex to collapse <strong><strong>, <em><em>, and <u><u> pairs; also adds RegexOptions.IgnoreCase to the empty-tag removal call. Logic traces correctly for all tested input shapes.
src/BloomTests/Book/BookTests.cs Adds two new test methods covering nested same-tag collapse (<b><b>, <i><i>, <u><u>, <sup><sup>) and multi-tag paragraphs with mixed nesting, including intentional non-collapse of <sup><sup>.

Reviews (6): Last reviewed commit: "Fix ticket number typo in comment: BL-16..." | Re-trigger Greptile

Comment thread src/BloomTests/Book/BookTests.cs
Comment thread src/BloomExe/Book/Book.cs
@StephenMcConnel StephenMcConnel force-pushed the BL-16387-NestedCharMarkup branch 2 times, most recently from b857247 to 6c5d409 Compare June 30, 2026 16:29

@JohnThomson JohnThomson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:lgtm:, but a couple of ideas to consider. If you don't think it's worth it you can merge as-is.

@JohnThomson reviewed 2 files and all commit messages, and made 3 comments.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on StephenMcConnel).


src/BloomExe/Book/Book.cs line 2631 at r2 (raw file):

        /// <summary>
        /// Convert old &lt;b&gt; and &lt;i&gt; to &lt;strong&gt; and &lt;em&gt; respectively.
        /// Also remove instances like &lt;/b&gt;&lt;b&gt; altogether since such markup is redundant.

Comment is rather specific, so needs update.


src/BloomExe/Book/Book.cs line 2695 at r2 (raw file):

                inner = Regex.Replace(
                    inner,
                    @"<(strong|em|sup|u)>(<\1>.*?</\1>)</\1>",

This also only handles things that are doubled right at the boundary. Maybe that's enough, but I'm wondering if we should handle the case that there is text inside the outer element but outside the inner one.

@StephenMcConnel StephenMcConnel force-pushed the BL-16387-NestedCharMarkup branch from 6c5d409 to a3f63e4 Compare July 1, 2026 22:45

@StephenMcConnel StephenMcConnel left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@StephenMcConnel made 2 comments.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on JohnThomson).


src/BloomExe/Book/Book.cs line 2631 at r2 (raw file):

Previously, JohnThomson (John Thomson) wrote…

Comment is rather specific, so needs update.

Done. I added to the comment.


src/BloomExe/Book/Book.cs line 2695 at r2 (raw file):

Previously, JohnThomson (John Thomson) wrote…

This also only handles things that are doubled right at the boundary. Maybe that's enough, but I'm wondering if we should handle the case that there is text inside the outer element but outside the inner one.

Done.

@StephenMcConnel StephenMcConnel force-pushed the BL-16387-NestedCharMarkup branch 2 times, most recently from d677a98 to f8e71d3 Compare July 6, 2026 20:22

@JohnThomson JohnThomson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@JohnThomson reviewed 2 files and all commit messages, made 1 comment, and resolved 1 discussion.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on StephenMcConnel).


src/BloomExe/Book/Book.cs line 2695 at r2 (raw file):

Previously, StephenMcConnel (Steve McConnel) wrote…

Done.

I may be misunderstanding. It looks to me as if both the previous and current versions will convert abc to abc. My point is that neither of them will convert abcdefghi to abcdefghi. And it seems at least plausible that doing so would be a good idea. The inner b doesn't make anything more bold, and may cause unexpected behavior when changing the boldness of things.
I'm open to reasoning that what I'm suggesting is not a good idea, or unnecessary or too difficult.

StephenMcConnel and others added 2 commits July 8, 2026 15:50
For example, <em><em>...</em></em> goes to <em>...</em>.
…e (BL-16387)

Responds to review feedback on PR #8019: the collapse regex previously only
removed markup doubled exactly at the boundary (<b><b>...</b></b>). It now also
collapses cases with text inside the outer element but outside the inner one,
e.g. <b>abc<b>def</b>ghi</b> -> <b>abcdefghi</b>, since the inner tag adds no
formatting and can cause surprises when toggling the style.

Also drop <sup> from the collapse set: nested superscript is semantically
meaningful, so those are left as-is (attributes are still stripped from the
inner tag).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@StephenMcConnel StephenMcConnel force-pushed the BL-16387-NestedCharMarkup branch from f8e71d3 to 6da1954 Compare July 8, 2026 22:22
The nested-markup cleanup comment referenced BL-16378; the correct ticket for
this work is BL-16387.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@StephenMcConnel StephenMcConnel left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@StephenMcConnel made 1 comment.
Reviewable status: 0 of 2 files reviewed, 1 unresolved discussion (waiting on JohnThomson).


src/BloomExe/Book/Book.cs line 2695 at r2 (raw file):

Previously, JohnThomson (John Thomson) wrote…

I may be misunderstanding. It looks to me as if both the previous and current versions will convert abc to abc. My point is that neither of them will convert abcdefghi to abcdefghi. And it seems at least plausible that doing so would be a good idea. The inner b doesn't make anything more bold, and may cause unexpected behavior when changing the boldness of things.
I'm open to reasoning that what I'm suggesting is not a good idea, or unnecessary or too difficult.

Your attempt to illustrate your point didn't come through: you have to escape html markers like &lt;b&gt;.

I've updated the regex to handle what you want. It now collapses a same-tag pair even when there's text on either side of the inner tag, so <strong>abc<strong>def</strong>ghi</strong> goes to <strong>abcdefghi</strong> (and likewise for <em>/<u>).
After thinking about it, I dropped <sup> from this collapsing, since nested superscript is semantically meaningful (a superscript of a superscript renders higher and smaller), so collapsing these would change how the text displays.

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.

3 participants