Skip to content

Commit be9a27f

Browse files
committed
Generalize link markers and use for inline footnotes
The resulting implementation for the footnotes extension is much nicer. It also cleans up LinkInfo and makes images less of a special case. Additionally, this allow inline parsing of markers that are not part of links - could have done this without this change but noticed it here and decided to fix it.
1 parent 72d6fa7 commit be9a27f

19 files changed

Lines changed: 212 additions & 183 deletions

File tree

commonmark-ext-footnotes/src/main/java/org/commonmark/ext/footnotes/FootnotesExtension.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ public void extend(Parser.Builder parserBuilder) {
6060
.customBlockParserFactory(new FootnoteBlockParser.Factory())
6161
.linkProcessor(new FootnoteLinkProcessor());
6262
if (inlineFootnotes) {
63-
parserBuilder.customInlineContentParserFactory(new InlineFootnoteMarkerParser.Factory())
64-
.postProcessor(new InlineFootnoteMarkerRemover());
63+
parserBuilder.linkMarker('^');
6564
}
6665
}
6766

commonmark-ext-footnotes/src/main/java/org/commonmark/ext/footnotes/internal/FootnoteLinkProcessor.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ public class FootnoteLinkProcessor implements LinkProcessor {
1919
@Override
2020
public LinkResult process(LinkInfo linkInfo, Scanner scanner, InlineParserContext context) {
2121

22-
var beforeBracket = linkInfo.openingBracket().getPrevious();
23-
if (beforeBracket instanceof InlineFootnoteMarker) {
24-
beforeBracket.unlink();
25-
return LinkResult.wrapTextIn(new InlineFootnote(), linkInfo.afterTextBracket());
22+
if (linkInfo.marker() != null && linkInfo.marker().getLiteral().equals("^")) {
23+
// An inline footnote like ^[footnote text]. Note that we only get the marker here if the option is enabled
24+
// on the extension.
25+
return LinkResult.wrapTextIn(new InlineFootnote(), linkInfo.afterTextBracket()).includeMarker();
2626
}
2727

2828
if (linkInfo.destination() != null) {
@@ -53,6 +53,6 @@ public LinkResult process(LinkInfo linkInfo, Scanner scanner, InlineParserContex
5353
// For footnotes, we only ever consume the text part of the link, not the label part (if any)
5454
var position = linkInfo.afterTextBracket();
5555
// If the marker is `![`, we don't want to include the `!`, so start from bracket
56-
return LinkResult.replaceWith(new FootnoteReference(label), position).startFromBracket();
56+
return LinkResult.replaceWith(new FootnoteReference(label), position);
5757
}
5858
}

commonmark-ext-footnotes/src/main/java/org/commonmark/ext/footnotes/internal/InlineFootnoteMarker.java

Lines changed: 0 additions & 6 deletions
This file was deleted.

commonmark-ext-footnotes/src/main/java/org/commonmark/ext/footnotes/internal/InlineFootnoteMarkerParser.java

Lines changed: 0 additions & 40 deletions
This file was deleted.

commonmark-ext-footnotes/src/main/java/org/commonmark/ext/footnotes/internal/InlineFootnoteMarkerRemover.java

Lines changed: 0 additions & 29 deletions
This file was deleted.

commonmark-ext-footnotes/src/test/java/org/commonmark/ext/footnotes/FootnotesTest.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package org.commonmark.ext.footnotes;
22

33
import org.commonmark.Extension;
4-
import org.commonmark.ext.footnotes.internal.InlineFootnoteMarker;
54
import org.commonmark.node.*;
65
import org.commonmark.parser.IncludeSourceSpans;
76
import org.commonmark.parser.Parser;
@@ -246,7 +245,6 @@ public void testInlineFootnote() {
246245
assertText("Test ", doc.getFirstChild().getFirstChild());
247246
var fn = find(doc, InlineFootnote.class);
248247
assertText("inline footnote", fn.getFirstChild());
249-
assertNull(tryFind(doc, InlineFootnoteMarker.class));
250248
}
251249

252250
{
@@ -257,12 +255,8 @@ public void testInlineFootnote() {
257255
{
258256
var doc = parser.parse("Test ^[not inline footnote");
259257
assertNull(tryFind(doc, InlineFootnote.class));
260-
assertNull(tryFind(doc, InlineFootnoteMarker.class));
261258
var t = doc.getFirstChild().getFirstChild();
262-
// This is not ideal; text nodes aren't merged after post-processing
263-
assertText("Test ", t);
264-
assertText("^", t.getNext());
265-
assertText("[not inline footnote", t.getNext().getNext());
259+
assertText("Test ^[not inline footnote", t);
266260
}
267261

268262
{
@@ -277,6 +271,14 @@ public void testInlineFootnote() {
277271
var code = fn.getFirstChild().getNext();
278272
assertEquals("bla]", ((Code) code).getLiteral());
279273
}
274+
275+
{
276+
var doc = parser.parse("^[with a [link](url)]");
277+
var fn = find(doc, InlineFootnote.class);
278+
assertText("with a ", fn.getFirstChild());
279+
var link = fn.getFirstChild().getNext();
280+
assertEquals("url", ((Link) link).getDestination());
281+
}
280282
}
281283

282284
@Test

commonmark/src/main/java/org/commonmark/internal/Bracket.java

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
import org.commonmark.parser.beta.Position;
55

66
/**
7-
* Opening bracket for links (<code>[</code>) or images (<code>![</code>).
7+
* Opening bracket for links ({@code [}), images ({@code ![}), or links with other markers.
88
*/
99
public class Bracket {
1010

1111
/**
12-
* The node of {@code !} if present, null otherwise.
12+
* The node of a marker such as {@code !} if present, null otherwise.
1313
*/
14-
public final Text bangNode;
14+
public final Text markerNode;
1515

1616
/**
17-
* The position of {@code !} if present, null otherwise.
17+
* The position of the marker if present, null otherwise.
1818
*/
19-
public final Position bangPosition;
19+
public final Position markerPosition;
2020

2121
/**
2222
* The node of {@code [}.
@@ -33,11 +33,6 @@ public class Bracket {
3333
*/
3434
public final Position contentPosition;
3535

36-
/**
37-
* Whether this is an image or link.
38-
*/
39-
public final boolean image;
40-
4136
/**
4237
* Previous bracket.
4338
*/
@@ -59,20 +54,19 @@ public class Bracket {
5954
public boolean bracketAfter = false;
6055

6156
static public Bracket link(Text bracketNode, Position bracketPosition, Position contentPosition, Bracket previous, Delimiter previousDelimiter) {
62-
return new Bracket(null, null, bracketNode, bracketPosition, contentPosition, previous, previousDelimiter, false);
57+
return new Bracket(null, null, bracketNode, bracketPosition, contentPosition, previous, previousDelimiter);
6358
}
6459

65-
static public Bracket image(Text bangNode, Position bangPosition, Text bracketNode, Position bracketPosition, Position contentPosition, Bracket previous, Delimiter previousDelimiter) {
66-
return new Bracket(bangNode, bangPosition, bracketNode, bracketPosition, contentPosition, previous, previousDelimiter, true);
60+
static public Bracket withMarker(Text markerNode, Position markerPosition, Text bracketNode, Position bracketPosition, Position contentPosition, Bracket previous, Delimiter previousDelimiter) {
61+
return new Bracket(markerNode, markerPosition, bracketNode, bracketPosition, contentPosition, previous, previousDelimiter);
6762
}
6863

69-
private Bracket(Text bangNode, Position bangPosition, Text bracketNode, Position bracketPosition, Position contentPosition, Bracket previous, Delimiter previousDelimiter, boolean image) {
70-
this.bangNode = bangNode;
71-
this.bangPosition = bangPosition;
64+
private Bracket(Text markerNode, Position markerPosition, Text bracketNode, Position bracketPosition, Position contentPosition, Bracket previous, Delimiter previousDelimiter) {
65+
this.markerNode = markerNode;
66+
this.markerPosition = markerPosition;
7267
this.bracketNode = bracketNode;
7368
this.bracketPosition = bracketPosition;
7469
this.contentPosition = contentPosition;
75-
this.image = image;
7670
this.previous = previous;
7771
this.previousDelimiter = previousDelimiter;
7872
}

commonmark/src/main/java/org/commonmark/internal/DocumentParser.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public class DocumentParser implements ParserState {
7474
private final List<InlineContentParserFactory> inlineContentParserFactories;
7575
private final List<DelimiterProcessor> delimiterProcessors;
7676
private final List<LinkProcessor> linkProcessors;
77+
private final Set<Character> linkMarkers;
7778
private final IncludeSourceSpans includeSourceSpans;
7879
private final DocumentBlockParser documentBlockParser;
7980
private final Definitions definitions = new Definitions();
@@ -83,12 +84,13 @@ public class DocumentParser implements ParserState {
8384

8485
public DocumentParser(List<BlockParserFactory> blockParserFactories, InlineParserFactory inlineParserFactory,
8586
List<InlineContentParserFactory> inlineContentParserFactories, List<DelimiterProcessor> delimiterProcessors,
86-
List<LinkProcessor> linkProcessors, IncludeSourceSpans includeSourceSpans) {
87+
List<LinkProcessor> linkProcessors, Set<Character> linkMarkers, IncludeSourceSpans includeSourceSpans) {
8788
this.blockParserFactories = blockParserFactories;
8889
this.inlineParserFactory = inlineParserFactory;
8990
this.inlineContentParserFactories = inlineContentParserFactories;
9091
this.delimiterProcessors = delimiterProcessors;
9192
this.linkProcessors = linkProcessors;
93+
this.linkMarkers = linkMarkers;
9294
this.includeSourceSpans = includeSourceSpans;
9395

9496
this.documentBlockParser = new DocumentBlockParser();
@@ -466,7 +468,7 @@ private BlockStartImpl findBlockStart(BlockParser blockParser) {
466468
* Walk through a block & children recursively, parsing string content into inline content where appropriate.
467469
*/
468470
private void processInlines() {
469-
var context = new InlineParserContextImpl(inlineContentParserFactories, delimiterProcessors, linkProcessors, definitions);
471+
var context = new InlineParserContextImpl(inlineContentParserFactories, delimiterProcessors, linkProcessors, linkMarkers, definitions);
470472
var inlineParser = inlineParserFactory.create(context);
471473

472474
for (var blockParser : allBlockParsers) {

commonmark/src/main/java/org/commonmark/internal/InlineParserContextImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,25 @@
77
import org.commonmark.parser.delimiter.DelimiterProcessor;
88

99
import java.util.List;
10+
import java.util.Set;
1011

1112
public class InlineParserContextImpl implements InlineParserContext {
1213

1314
private final List<InlineContentParserFactory> inlineContentParserFactories;
1415
private final List<DelimiterProcessor> delimiterProcessors;
1516
private final List<LinkProcessor> linkProcessors;
17+
private final Set<Character> linkMarkers;
1618
private final Definitions definitions;
1719

1820
public InlineParserContextImpl(List<InlineContentParserFactory> inlineContentParserFactories,
1921
List<DelimiterProcessor> delimiterProcessors,
2022
List<LinkProcessor> linkProcessors,
23+
Set<Character> linkMarkers,
2124
Definitions definitions) {
2225
this.inlineContentParserFactories = inlineContentParserFactories;
2326
this.delimiterProcessors = delimiterProcessors;
2427
this.linkProcessors = linkProcessors;
28+
this.linkMarkers = linkMarkers;
2529
this.definitions = definitions;
2630
}
2731

@@ -40,6 +44,11 @@ public List<LinkProcessor> getCustomLinkProcessors() {
4044
return linkProcessors;
4145
}
4246

47+
@Override
48+
public Set<Character> getCustomLinkMarkers() {
49+
return linkMarkers;
50+
}
51+
4352
@Override
4453
public LinkReferenceDefinition getLinkReferenceDefinition(String label) {
4554
return definitions.getDefinition(LinkReferenceDefinition.class, label);

0 commit comments

Comments
 (0)