From 8a97f41ed83b2ca9b1b67f8355ed1ce84578069d Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Fri, 24 Oct 2025 11:55:06 +0200 Subject: [PATCH 1/3] XRENDERING-766: Macros followed by an empty block with parameters gets wrapped in a span when converted to annotated html * Add several failing test cases. * Attempt fixing some of the identified issues - but it's far from complete. --- .../test/resources/simple/macros/macro38.test | 62 +++++++++++++++++++ .../simple/paragraph/paragraph10.test | 31 ++++++++++ .../resources/simple/verbatim/verbatim9.test | 50 +++++++++++++++ .../impl/InternalWikiScannerContext.java | 5 +- 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test create mode 100644 xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test create mode 100644 xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test new file mode 100644 index 0000000000..de3e168f05 --- /dev/null +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test @@ -0,0 +1,62 @@ +.runTransformations +.#----------------------------------------------------- +.input|xwiki/2.0 +.#----------------------------------------------------- +{{testsimpleinlinemacro/}}(% id="test" %)hi + +(% id="test" %){{testsimpleinlinemacro/}} + +{{testsimpleinlinemacro/}}(% id="test" %) + +Padding + +{{testsimpleinlinemacro/}}(% id="test" %){{testsimpleinlinemacro/}} + +{{testsimpleinlinemacro/}}(% id="test" %) +.#----------------------------------------------------- +.expect|event/1.0 +.#----------------------------------------------------- +beginDocument +beginParagraph +beginMacroMarkerInline [testsimpleinlinemacro] [] +onWord [simpleinlinemacro2] +endMacroMarkerInline [testsimpleinlinemacro] [] +beginFormat [NONE] [[id]=[test]] +onWord [hi] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +beginFormat [NONE] [[id]=[test]] +beginMacroMarkerInline [testsimpleinlinemacro] [] +onWord [simpleinlinemacro3] +endMacroMarkerInline [testsimpleinlinemacro] [] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +beginMacroMarkerInline [testsimpleinlinemacro] [] +onWord [simpleinlinemacro4] +endMacroMarkerInline [testsimpleinlinemacro] [] +beginFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +onWord [Padding] +endParagraph +beginParagraph +beginMacroMarkerInline [testsimpleinlinemacro] [] +onWord [simpleinlinemacro5] +endMacroMarkerInline [testsimpleinlinemacro] [] +beginFormat [NONE] [[id]=[test]] +beginMacroMarkerInline [testsimpleinlinemacro] [] +onWord [simpleinlinemacro6] +endMacroMarkerInline [testsimpleinlinemacro] [] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +beginMacroMarkerInline [testsimpleinlinemacro] [] +onWord [simpleinlinemacro7] +endMacroMarkerInline [testsimpleinlinemacro] [] +beginFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test]] +endParagraph +endDocument \ No newline at end of file diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test b/xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test new file mode 100644 index 0000000000..701c8ab1f2 --- /dev/null +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test @@ -0,0 +1,31 @@ +.#--------------------------------------------------------------------------------------------------------- +.input|xwiki/2.0 +.#--------------------------------------------------------------------------------------------------------- +Paragraph1(% id="test" %) + +Paragraph2 + +Paragraph3(% id="test" %)(%%) + +Paragraph4 +.#--------------------------------------------------------------------------------------------------------- +.expect|event/1.0 +.#--------------------------------------------------------------------------------------------------------- +beginDocument +beginParagraph +onWord [Paragraph1] +beginFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +onWord [Paragraph2] +endParagraph +beginParagraph +onWord [Paragraph3] +beginFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +onWord [Paragraph4] +endParagraph +endDocument diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test b/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test new file mode 100644 index 0000000000..3ae599699e --- /dev/null +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test @@ -0,0 +1,50 @@ +.#--------------------------------------------------------------------------------------------------------- +.input|xwiki/2.0 +.#--------------------------------------------------------------------------------------------------------- +{{{verbatim}}}(% id="test" %)hi + +(% id="test" %){{{verbatim}}}hi + +(% id="test" %){{{verbatim}}} + +{{{verbatim}}}(% id="test" %) + +Padding + +{{{verbatim1}}}(% id="test" %){{{verbatim2}}} +.#--------------------------------------------------------------------------------------------------------- +.expect|event/1.0 +.#--------------------------------------------------------------------------------------------------------- +beginDocument +beginParagraph +onVerbatim [verbatim] [true] +beginFormat [NONE] [[id]=[test]] +onWord [hi] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +beginFormat [NONE] [[id]=[test]] +onVerbatim [verbatim] [true] +onWord [hi] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +beginFormat [NONE] [[id]=[test]] +onVerbatim [verbatim] [true] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +onVerbatim [verbatim] [true] +beginFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test]] +endParagraph +beginParagraph +onWord [Padding] +endParagraph +beginParagraph +onVerbatim [verbatim1] [true] +beginFormat [NONE] [[id]=[test]] +onVerbatim [verbatim2] [true] +endFormat [NONE] [[id]=[test]] +endParagraph +endDocument diff --git a/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java b/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java index 053ab6ef9f..e8a4e74e83 100644 --- a/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java +++ b/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java @@ -599,9 +599,12 @@ protected void checkStyleOpened() fMacroName = macroName; fVerbatimContent = verbatimContent; } - openFormat(); + // First check if we encountered a verbatim or macro that we can now process as inline. + // Then open whatever format we encountered. If the format was before the verbatim or macro, we would have + // immediately recognized both as inline and processed them already. checkVerbatim(true); checkMacro(true); + openFormat(); } private void checkTableCell() From df571856f2b00bb71b02214e91e99c7a3169a1a6 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Tue, 21 Jul 2026 17:30:34 +0200 Subject: [PATCH 2/3] XRENDERING-766: Macros followed by an empty block with parameters gets wrapped in a span when converted to annotated html * Keep empty syntax at the end of a block when the only other block content is a verbatim or macro syntax. * Add a test for the original scenario of the issue. * Adapt the paragraph test to expect the removal of the empty format. * Add some currently failing XHTML roundtrip tests for the empty format. Note: the behavior should probably be changed again, waiting for answers on forum proposal. Co-Authored-By: Claude Opus 5 (1M context) --- .../test/resources/simple/macros/macro38.test | 56 +++++++++++-------- .../test/resources/simple/macros/macro39.test | 30 ++++++++++ .../simple/paragraph/paragraph10.test | 8 +-- .../resources/simple/verbatim/verbatim9.test | 4 +- .../specific/macro/macro1.test | 12 ++++ .../xhtml10/specific/macro/macro12.test | 19 +++++++ .../impl/InternalWikiScannerContext.java | 9 +++ .../wikimodel/test/XWiki20ParserTest.java | 39 +++++++++++++ 8 files changed, 149 insertions(+), 28 deletions(-) create mode 100644 xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test create mode 100644 xwiki-rendering-syntaxes/xwiki-rendering-syntax-annotatedxhtml/src/test/resources/annotatedxhtml10/specific/macro/macro1.test create mode 100644 xwiki-rendering-syntaxes/xwiki-rendering-syntax-xhtml/src/test/resources/xhtml10/specific/macro/macro12.test diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test index de3e168f05..909bbebcfc 100644 --- a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test @@ -1,18 +1,20 @@ .runTransformations .#----------------------------------------------------- -.input|xwiki/2.0 +.# A macro followed by a format must be inline and must not be wrapped in the format (XRENDERING-766). .#----------------------------------------------------- -{{testsimpleinlinemacro/}}(% id="test" %)hi - -(% id="test" %){{testsimpleinlinemacro/}} +.inputexpect|xwiki/2.0 +.#----------------------------------------------------- +{{testsimpleinlinemacro/}}(% id="test1" %)hi -{{testsimpleinlinemacro/}}(% id="test" %) +{{testsimpleinlinemacro/}}(% id="test2" %) Padding -{{testsimpleinlinemacro/}}(% id="test" %){{testsimpleinlinemacro/}} +{{testsimpleinlinemacro/}}(% id="test3" %){{testsimpleinlinemacro/}} + +{{testsimpleinlinemacro/}}(% id="test4" %) -{{testsimpleinlinemacro/}}(% id="test" %) +(% id="test5" %){{testsimpleinlinemacro/}} .#----------------------------------------------------- .expect|event/1.0 .#----------------------------------------------------- @@ -21,42 +23,50 @@ beginParagraph beginMacroMarkerInline [testsimpleinlinemacro] [] onWord [simpleinlinemacro2] endMacroMarkerInline [testsimpleinlinemacro] [] -beginFormat [NONE] [[id]=[test]] +beginFormat [NONE] [[id]=[test1]] onWord [hi] -endFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test1]] endParagraph beginParagraph -beginFormat [NONE] [[id]=[test]] beginMacroMarkerInline [testsimpleinlinemacro] [] onWord [simpleinlinemacro3] endMacroMarkerInline [testsimpleinlinemacro] [] -endFormat [NONE] [[id]=[test]] -endParagraph -beginParagraph -beginMacroMarkerInline [testsimpleinlinemacro] [] -onWord [simpleinlinemacro4] -endMacroMarkerInline [testsimpleinlinemacro] [] -beginFormat [NONE] [[id]=[test]] -endFormat [NONE] [[id]=[test]] +beginFormat [NONE] [[id]=[test2]] +endFormat [NONE] [[id]=[test2]] endParagraph beginParagraph onWord [Padding] endParagraph beginParagraph beginMacroMarkerInline [testsimpleinlinemacro] [] +onWord [simpleinlinemacro4] +endMacroMarkerInline [testsimpleinlinemacro] [] +beginFormat [NONE] [[id]=[test3]] +beginMacroMarkerInline [testsimpleinlinemacro] [] onWord [simpleinlinemacro5] endMacroMarkerInline [testsimpleinlinemacro] [] -beginFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test3]] +endParagraph +beginParagraph beginMacroMarkerInline [testsimpleinlinemacro] [] onWord [simpleinlinemacro6] endMacroMarkerInline [testsimpleinlinemacro] [] -endFormat [NONE] [[id]=[test]] +beginFormat [NONE] [[id]=[test4]] +endFormat [NONE] [[id]=[test4]] endParagraph beginParagraph +beginFormat [NONE] [[id]=[test5]] beginMacroMarkerInline [testsimpleinlinemacro] [] onWord [simpleinlinemacro7] endMacroMarkerInline [testsimpleinlinemacro] [] -beginFormat [NONE] [[id]=[test]] -endFormat [NONE] [[id]=[test]] +endFormat [NONE] [[id]=[test5]] endParagraph -endDocument \ No newline at end of file +endDocument +.#----------------------------------------------------- +.expect|annotatedxhtml/1.0 +.#----------------------------------------------------- +

simpleinlinemacro2hi

simpleinlinemacro3

Padding

simpleinlinemacro4simpleinlinemacro5

simpleinlinemacro6

simpleinlinemacro7

+.#----------------------------------------------------- +.input|xhtml/1.0 +.#----------------------------------------------------- +

simpleinlinemacro2hi

simpleinlinemacro3

Padding

simpleinlinemacro4simpleinlinemacro5

simpleinlinemacro6

simpleinlinemacro7

diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test new file mode 100644 index 0000000000..774d83514e --- /dev/null +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test @@ -0,0 +1,30 @@ +.#----------------------------------------------------- +.inputexpect|xwiki/2.1 +.# Stored XWiki syntax of an inline macro (here a mention) followed by CKEditor's "xwiki-macro-inline-enforcer". +.# CKEditor appends this span (holding a non-breaking space) after an inline macro so the rendering round-trip of +.# the macro content keeps the macro inline instead of turning it into a block; CKEditor removes the span again +.# afterwards. The macro must therefore be emitted *before* the enforcer format and must never be wrapped inside +.# it - otherwise removing the enforcer span would delete the macro too (XWIKI-21973 / XRENDERING-766). +.# NOTE: the input line below ends with a space (the enforcer content); it is preserved as the format content so the +.# enforcer format is non-empty. +.#----------------------------------------------------- +{{mention reference="XWiki.Admin" style="FULL_NAME" anchor="XWiki-Admin-7qc"/}}(% id="xwiki-macro-inline-enforcer" %) +.#----------------------------------------------------- +.expect|event/1.0 +.#----------------------------------------------------- +beginDocument +beginParagraph +onMacroInline [mention] [reference=XWiki.Admin|style=FULL_NAME|anchor=XWiki-Admin-7qc] +beginFormat [NONE] [[id]=[xwiki-macro-inline-enforcer]] +onSpace +endFormat [NONE] [[id]=[xwiki-macro-inline-enforcer]] +endParagraph +endDocument +.#----------------------------------------------------- +.expect|annotatedxhtml/1.0 +.#----------------------------------------------------- +

 

+.#----------------------------------------------------- +.input|xhtml/1.0 +.#----------------------------------------------------- +

 

diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test b/xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test index 701c8ab1f2..b497e044b6 100644 --- a/xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/paragraph/paragraph10.test @@ -1,4 +1,8 @@ .#--------------------------------------------------------------------------------------------------------- +.# An empty format (parameters only) at the very end of a paragraph is currently dropped. Unlike a format right +.# after a still-pending macro or verbatim element (see XRENDERING-766), plain inline content followed by a trailing +.# empty parameter format does not preserve that format. +.#--------------------------------------------------------------------------------------------------------- .input|xwiki/2.0 .#--------------------------------------------------------------------------------------------------------- Paragraph1(% id="test" %) @@ -14,16 +18,12 @@ Paragraph4 beginDocument beginParagraph onWord [Paragraph1] -beginFormat [NONE] [[id]=[test]] -endFormat [NONE] [[id]=[test]] endParagraph beginParagraph onWord [Paragraph2] endParagraph beginParagraph onWord [Paragraph3] -beginFormat [NONE] [[id]=[test]] -endFormat [NONE] [[id]=[test]] endParagraph beginParagraph onWord [Paragraph4] diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test b/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test index 3ae599699e..05959bf6f1 100644 --- a/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test @@ -1,5 +1,7 @@ .#--------------------------------------------------------------------------------------------------------- -.input|xwiki/2.0 +.# Verbatim text followed by a format must be inline and must not be wrapped in the format (XRENDERING-766). +.#--------------------------------------------------------------------------------------------------------- +.inputexpect|xwiki/2.0 .#--------------------------------------------------------------------------------------------------------- {{{verbatim}}}(% id="test" %)hi diff --git a/xwiki-rendering-syntaxes/xwiki-rendering-syntax-annotatedxhtml/src/test/resources/annotatedxhtml10/specific/macro/macro1.test b/xwiki-rendering-syntaxes/xwiki-rendering-syntax-annotatedxhtml/src/test/resources/annotatedxhtml10/specific/macro/macro1.test new file mode 100644 index 0000000000..8bcba24374 --- /dev/null +++ b/xwiki-rendering-syntaxes/xwiki-rendering-syntax-annotatedxhtml/src/test/resources/annotatedxhtml10/specific/macro/macro1.test @@ -0,0 +1,12 @@ +.#----------------------------------------------------- +.input|xhtml/1.0 +.# An inline macro followed by the CKEditor "xwiki-macro-inline-enforcer" span (a parameter format holding a +.# non-breaking space, used to keep the macro inline) must round-trip with the macro *before* the span and never +.# wrapped inside it. If the macro were wrapped, CKEditor's removal of the enforcer span would delete the macro too +.# (XWIKI-21973 / XRENDERING-766). +.#----------------------------------------------------- +

 

+.#----------------------------------------------------- +.expect|annotatedxhtml/1.0 +.#----------------------------------------------------- +

 

diff --git a/xwiki-rendering-syntaxes/xwiki-rendering-syntax-xhtml/src/test/resources/xhtml10/specific/macro/macro12.test b/xwiki-rendering-syntaxes/xwiki-rendering-syntax-xhtml/src/test/resources/xhtml10/specific/macro/macro12.test new file mode 100644 index 0000000000..79dd4fb15b --- /dev/null +++ b/xwiki-rendering-syntaxes/xwiki-rendering-syntax-xhtml/src/test/resources/xhtml10/specific/macro/macro12.test @@ -0,0 +1,19 @@ +.#----------------------------------------------------- +.input|xhtml/1.0 +.# An inline macro followed by CKEditor's "xwiki-macro-inline-enforcer" span must be parsed as an inline macro that +.# is *not* wrapped in the enforcer format: the onMacroInline event comes before beginFormat, not inside it. If the +.# macro were wrapped, CKEditor's removal of the enforcer span would delete the macro too (XWIKI-21973 / +.# XRENDERING-766). The enforcer span carries a non-breaking space, which is why it keeps the macro inline. +.#----------------------------------------------------- +

 

+.#----------------------------------------------------- +.expect|event/1.0 +.#----------------------------------------------------- +beginDocument +beginParagraph +onMacroInline [mention] [reference=XWiki.Admin|style=FULL_NAME|anchor=XWiki-Admin-7qcxlk] +beginFormat [NONE] [[id]=[xwiki-macro-inline-enforcer]] +onSpace +endFormat [NONE] [[id]=[xwiki-macro-inline-enforcer]] +endParagraph +endDocument diff --git a/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java b/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java index e8a4e74e83..59c5bfbeb8 100644 --- a/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java +++ b/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java @@ -630,6 +630,15 @@ private void checkVerbatim(boolean inline) public void closeBlock() { + // When a format followed a still-pending macro or verbatim element, that element cannot be standalone: it + // is inline content followed by an (empty) format. Emit both inside a paragraph, which the switch below + // closes again. Otherwise, the pending format would leak into the next block or be silently lost. + if ((fMacroName != null || fVerbatimContent != null) && isNoBlockElements() + && !WikiFormat.EMPTY.equals(fNewFormat)) + { + checkStyleOpened(); + } + checkVerbatim(false); checkMacro(false); diff --git a/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java b/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java index 5566b564e7..b897f90bae 100644 --- a/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java +++ b/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java @@ -703,6 +703,45 @@ void testMacro() throws WikiParserException "
"); } + /** + * A macro at the start of a line followed by a format must be inline, and the format must not wrap the macro, + * see XRENDERING-766. + */ + @Test + void testMacroFollowedByFormat() throws WikiParserException + { + // The format must not wrap the macro, only the content after it. + test("{{macro/}}(% id='test' %)hi", + "

" + + "hi

"); + + // A format before the macro wraps the macro, though. + test("(% id='test' %){{macro/}}", + "

" + + "

"); + + // A trailing format makes the macro inline and produces an empty format after it. + test("{{macro/}}(% id='test' %)", + "

" + + "

"); + + // The trailing format must not leak into the following paragraph. + test("{{macro/}}(% id='test' %)\n\nPadding", + "

" + + "

\n" + + "

Padding

"); + + // Only the second macro must be wrapped in the format. + test("{{macro/}}(% id='test' %){{macro/}}", + "

" + + "

"); + + // The same applies to verbatim content. + test("{{{verbatim}}}(% id='test' %)", + "

verbatim" + + "

"); + } + @Test void testMacroParameterEscaping() throws WikiParserException { From 0f408746fd6a7b36771cc62560fad9f2cfd1dac3 Mon Sep 17 00:00:00 2001 From: Michael Hamann Date: Thu, 23 Jul 2026 17:10:31 +0200 Subject: [PATCH 3/3] XRENDERING-766: Macros followed by an empty block with parameters gets wrapped in a span when converted to annotated html * Implement a less breaking option: continue discarding empty format at the end of blocks, still fix: * Format wrongly wraps the macro before it. * Empty format wraps the following paragraph Co-Authored-By: Claude Opus 5 (1M context) --- .../test/resources/simple/macros/macro38.test | 40 +++++++++++++------ .../test/resources/simple/macros/macro39.test | 2 +- .../resources/simple/verbatim/verbatim9.test | 29 ++++++++++---- .../impl/InternalWikiScannerContext.java | 10 +++-- .../wikimodel/test/XWiki20ParserTest.java | 17 ++++---- 5 files changed, 65 insertions(+), 33 deletions(-) diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test index 909bbebcfc..227ef7d518 100644 --- a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro38.test @@ -1,8 +1,14 @@ .runTransformations .#----------------------------------------------------- -.# A macro followed by a format must be inline and must not be wrapped in the format (XRENDERING-766). +.# A non-empty format after a macro must keep the macro inline without wrapping it in the format +.# (XRENDERING-766): see test1, test3 and test5. A format before a macro still wraps it (test5). +.# An *empty* format right after a macro (test2, test4) carries no content: the format is dropped and the +.# macro is emitted as a standalone block, exactly as if the format were not there. The dropped format must +.# not leak into the following block either - test2 is followed by "Padding", which must stay unformatted. +.# The xwiki/2.0 input therefore does not round-trip (the empty formats disappear), so input and output are +.# specified separately. .#----------------------------------------------------- -.inputexpect|xwiki/2.0 +.input|xwiki/2.0 .#----------------------------------------------------- {{testsimpleinlinemacro/}}(% id="test1" %)hi @@ -27,13 +33,11 @@ beginFormat [NONE] [[id]=[test1]] onWord [hi] endFormat [NONE] [[id]=[test1]] endParagraph +beginMacroMarkerStandalone [testsimpleinlinemacro] [] beginParagraph -beginMacroMarkerInline [testsimpleinlinemacro] [] onWord [simpleinlinemacro3] -endMacroMarkerInline [testsimpleinlinemacro] [] -beginFormat [NONE] [[id]=[test2]] -endFormat [NONE] [[id]=[test2]] endParagraph +endMacroMarkerStandalone [testsimpleinlinemacro] [] beginParagraph onWord [Padding] endParagraph @@ -47,13 +51,11 @@ onWord [simpleinlinemacro5] endMacroMarkerInline [testsimpleinlinemacro] [] endFormat [NONE] [[id]=[test3]] endParagraph +beginMacroMarkerStandalone [testsimpleinlinemacro] [] beginParagraph -beginMacroMarkerInline [testsimpleinlinemacro] [] onWord [simpleinlinemacro6] -endMacroMarkerInline [testsimpleinlinemacro] [] -beginFormat [NONE] [[id]=[test4]] -endFormat [NONE] [[id]=[test4]] endParagraph +endMacroMarkerStandalone [testsimpleinlinemacro] [] beginParagraph beginFormat [NONE] [[id]=[test5]] beginMacroMarkerInline [testsimpleinlinemacro] [] @@ -63,10 +65,24 @@ endFormat [NONE] [[id]=[test5]] endParagraph endDocument .#----------------------------------------------------- +.expect|xwiki/2.0 +.#----------------------------------------------------- +{{testsimpleinlinemacro/}}(% id="test1" %)hi + +{{testsimpleinlinemacro/}} + +Padding + +{{testsimpleinlinemacro/}}(% id="test3" %){{testsimpleinlinemacro/}} + +{{testsimpleinlinemacro/}} + +(% id="test5" %){{testsimpleinlinemacro/}} +.#----------------------------------------------------- .expect|annotatedxhtml/1.0 .#----------------------------------------------------- -

simpleinlinemacro2hi

simpleinlinemacro3

Padding

simpleinlinemacro4simpleinlinemacro5

simpleinlinemacro6

simpleinlinemacro7

+

simpleinlinemacro2hi

simpleinlinemacro3

Padding

simpleinlinemacro4simpleinlinemacro5

simpleinlinemacro6

simpleinlinemacro7

.#----------------------------------------------------- .input|xhtml/1.0 .#----------------------------------------------------- -

simpleinlinemacro2hi

simpleinlinemacro3

Padding

simpleinlinemacro4simpleinlinemacro5

simpleinlinemacro6

simpleinlinemacro7

+

simpleinlinemacro2hi

simpleinlinemacro3

Padding

simpleinlinemacro4simpleinlinemacro5

simpleinlinemacro6

simpleinlinemacro7

diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test index 774d83514e..d9bafc154c 100644 --- a/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/macros/macro39.test @@ -8,7 +8,7 @@ .# NOTE: the input line below ends with a space (the enforcer content); it is preserved as the format content so the .# enforcer format is non-empty. .#----------------------------------------------------- -{{mention reference="XWiki.Admin" style="FULL_NAME" anchor="XWiki-Admin-7qc"/}}(% id="xwiki-macro-inline-enforcer" %) +{{mention reference="XWiki.Admin" style="FULL_NAME" anchor="XWiki-Admin-7qc"/}}(% id="xwiki-macro-inline-enforcer" %) .#----------------------------------------------------- .expect|event/1.0 .#----------------------------------------------------- diff --git a/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test b/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test index 05959bf6f1..724ba4c6bb 100644 --- a/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test +++ b/xwiki-rendering-integration-tests/src/test/resources/simple/verbatim/verbatim9.test @@ -1,7 +1,12 @@ .#--------------------------------------------------------------------------------------------------------- -.# Verbatim text followed by a format must be inline and must not be wrapped in the format (XRENDERING-766). +.# A non-empty format after verbatim text must keep the verbatim inline without wrapping it in the format +.# (XRENDERING-766). A format before verbatim still wraps it. An *empty* format right after verbatim carries +.# no content: the format is dropped and the verbatim is emitted as a standalone block, exactly as if the +.# format were not there. The dropped format must not leak into the following block either - the fourth case +.# is followed by "Padding", which must stay unformatted. The xwiki/2.0 input therefore does not round-trip +.# (the empty format disappears), so input and output are specified separately. .#--------------------------------------------------------------------------------------------------------- -.inputexpect|xwiki/2.0 +.input|xwiki/2.0 .#--------------------------------------------------------------------------------------------------------- {{{verbatim}}}(% id="test" %)hi @@ -35,11 +40,7 @@ beginFormat [NONE] [[id]=[test]] onVerbatim [verbatim] [true] endFormat [NONE] [[id]=[test]] endParagraph -beginParagraph -onVerbatim [verbatim] [true] -beginFormat [NONE] [[id]=[test]] -endFormat [NONE] [[id]=[test]] -endParagraph +onVerbatim [verbatim] [false] beginParagraph onWord [Padding] endParagraph @@ -50,3 +51,17 @@ onVerbatim [verbatim2] [true] endFormat [NONE] [[id]=[test]] endParagraph endDocument +.#--------------------------------------------------------------------------------------------------------- +.expect|xwiki/2.0 +.#--------------------------------------------------------------------------------------------------------- +{{{verbatim}}}(% id="test" %)hi + +(% id="test" %){{{verbatim}}}hi + +(% id="test" %){{{verbatim}}} + +{{{verbatim}}} + +Padding + +{{{verbatim1}}}(% id="test" %){{{verbatim2}}} diff --git a/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java b/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java index 59c5bfbeb8..af761588a6 100644 --- a/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java +++ b/xwiki-rendering-wikimodel/src/main/java/org/xwiki/rendering/wikimodel/impl/InternalWikiScannerContext.java @@ -630,13 +630,15 @@ private void checkVerbatim(boolean inline) public void closeBlock() { - // When a format followed a still-pending macro or verbatim element, that element cannot be standalone: it - // is inline content followed by an (empty) format. Emit both inside a paragraph, which the switch below - // closes again. Otherwise, the pending format would leak into the next block or be silently lost. + // A format that trails a still-pending macro or verbatim element has no content: the element is emitted as + // a standalone block below, and the empty format is dropped here so it does not leak into the next block. + // The macro/verbatim condition is required: it excludes the checkStyleOpened() -> beginParagraph() -> + // closeBlock() re-entrant call (which temporarily clears these fields), where the pending format must be + // preserved so that it can wrap the following inline content. if ((fMacroName != null || fVerbatimContent != null) && isNoBlockElements() && !WikiFormat.EMPTY.equals(fNewFormat)) { - checkStyleOpened(); + fNewFormat = WikiFormat.EMPTY; } checkVerbatim(false); diff --git a/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java b/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java index b897f90bae..387e94efaa 100644 --- a/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java +++ b/xwiki-rendering-wikimodel/src/test/java/org/xwiki/rendering/wikimodel/test/XWiki20ParserTest.java @@ -720,15 +720,14 @@ void testMacroFollowedByFormat() throws WikiParserException "

" + "

"); - // A trailing format makes the macro inline and produces an empty format after it. + // A trailing format with no content is dropped, and the macro becomes a standalone block (as if the + // empty format were not there). test("{{macro/}}(% id='test' %)", - "

" - + "

"); + "
");
 
-        // The trailing format must not leak into the following paragraph.
+        // The dropped empty format must not leak into the following paragraph.
         test("{{macro/}}(% id='test' %)\n\nPadding",
-            "

" - + "

\n" + "
\n"
                 + "

Padding

"); // Only the second macro must be wrapped in the format. @@ -736,10 +735,10 @@ void testMacroFollowedByFormat() throws WikiParserException "

" + "

"); - // The same applies to verbatim content. + // The same applies to verbatim content: an empty trailing format is dropped and the verbatim becomes + // a standalone block. test("{{{verbatim}}}(% id='test' %)", - "

verbatim" - + "

"); + "
verbatim
"); } @Test