467275: add generated ids to headings

Change-Id: I651d3bc6ec7f58cbceddc5d93fca22fc5bbeb615
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=467275
diff --git a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkAsserts.java b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkAsserts.java
index 7b730d2..83513ff 100644
--- a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkAsserts.java
+++ b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkAsserts.java
@@ -24,6 +24,7 @@
 import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
 import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
 import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentHandler;
+import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
 import org.eclipse.mylyn.wikitext.core.util.XmlStreamWriter;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -33,7 +34,12 @@
 public class CommonMarkAsserts {
 
 	public static void assertContent(String expectedHtml, String input) {
-		String html = parseToHtml(input);
+		String html = parseToHtml(new CommonMarkLanguage(), input);
+		assertHtmlEquals(expectedHtml, html);
+	}
+
+	public static void assertContent(MarkupLanguage language, String expectedHtml, String input) {
+		String html = parseToHtml(language, input);
 		assertHtmlEquals(expectedHtml, html);
 	}
 
@@ -58,10 +64,10 @@
 		}
 	}
 
-	private static String parseToHtml(String input) {
+	private static String parseToHtml(MarkupLanguage markupLanguage, String input) {
 		StringWriter out = new StringWriter();
 		DocumentBuilder builder = createDocumentBuilder(out);
-		MarkupParser parser = new MarkupParser(new CommonMarkLanguage(), builder);
+		MarkupParser parser = new MarkupParser(markupLanguage, builder);
 		try {
 			parser.parse(new StringReader(input));
 		} catch (IOException e) {
diff --git a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkIdGenerationStrategyTest.java b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkIdGenerationStrategyTest.java
new file mode 100644
index 0000000..3e89a82
--- /dev/null
+++ b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkIdGenerationStrategyTest.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2015 David Green.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     David Green - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.wikitext.commonmark;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class CommonMarkIdGenerationStrategyTest {
+
+	private final CommonMarkIdGenerationStrategy strategy = new CommonMarkIdGenerationStrategy();
+
+	@Test
+	public void simple() {
+		assertId("abc", "abc");
+		assertId("abc123", "abc123");
+		assertId("a_bc", "a_bc");
+	}
+
+	@Test
+	public void mixedCase() {
+		assertId("abc", "AbC");
+	}
+
+	@Test
+	public void whitespace() {
+		assertId("a-bc", "a bc");
+		assertId("a-bc", "a  \tbc");
+		assertId("abc", " abc");
+		assertId("abc", "abc ");
+	}
+
+	@Test
+	public void allWhitespace() {
+		assertId("", "   \t");
+	}
+
+	@Test
+	public void hyphenated() {
+		assertId("a-b", "a-b");
+		assertId("ab", "-ab");
+		assertId("ab", "ab-");
+	}
+
+	@Test
+	public void punctuationAndSpecialCharacters() {
+		assertId("a-b", "a.b");
+		assertId("a-b", "a....b");
+		assertId("a-b", "a,b");
+		assertId("a-b", "a;b");
+		assertId("a-b", "a*b");
+		assertId("a-b", "a&b");
+		assertId("ab", ".ab");
+	}
+
+	private void assertId(String expected, String headingText) {
+		assertEquals(expected, strategy.generateId(headingText));
+	}
+}
diff --git a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextTest.java b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextTest.java
index 2bfd628..122574a 100644
--- a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextTest.java
+++ b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextTest.java
@@ -64,4 +64,13 @@
 		assertEquals("/uri", uriWithTitle.getUri());
 	}
 
+	@Test
+	public void generateHeadingId() {
+		ProcessingContext processingContext = ProcessingContext.empty();
+		assertEquals("a", processingContext.generateHeadingId(1, "a"));
+		assertEquals("a2", processingContext.generateHeadingId(1, "a"));
+		assertEquals("a3", processingContext.generateHeadingId(2, "a"));
+		assertEquals("h1-3", processingContext.generateHeadingId(1, null));
+		assertEquals("h1-4", processingContext.generateHeadingId(1, ""));
+	}
 }
diff --git a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlockTest.java b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlockTest.java
index 8fad88b..513c879 100644
--- a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlockTest.java
+++ b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlockTest.java
@@ -41,16 +41,17 @@
 
 	@Test
 	public void basic() {
-		assertContent("<h2>One Two</h2>", "## One Two");
-		assertContent("<h2>One Two</h2>", "## One Two #####   ");
-		assertContent("<h2>One Two#</h2>", "## One Two#");
-		assertContent("<p>One</p><h1>two</h1><p>Three</p>", "One\n# two\nThree");
+		assertContent("<h2 id=\"one-two\">One Two</h2>", "## One Two");
+		assertContent("<h2 id=\"one-two\">One Two</h2>", "## One Two #####   ");
+		assertContent("<h2 id=\"one-two\">One Two#</h2>", "## One Two#");
+		assertContent("<p>One</p><h1 id=\"two\">two</h1><p>Three</p>", "One\n# two\nThree");
 		assertContent("<h2></h2>", "##");
 		assertContent("<h2></h2>", "## ##");
 	}
 
 	@Test
 	public void withNestedInlines() {
-		assertContent("<h2>One <em>Two</em> \\<strong>three</strong></h2>", "## One *Two* \\\\__three__ ##");
+		assertContent("<h2 id=\"one-two-three\">One <em>Two</em> \\<strong>three</strong></h2>",
+				"## One *Two* \\\\__three__ ##");
 	}
 }
diff --git a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlockTest.java b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlockTest.java
index b17f606..c843623 100644
--- a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlockTest.java
+++ b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlockTest.java
@@ -38,9 +38,9 @@
 
 	@Test
 	public void process() {
-		assertContent("<h2>Heading Text</h2>", "Heading Text\n-------");
-		assertContent("<h1>Heading Text</h1>", "Heading Text\n=");
-		assertContent("<h1>Heading Text</h1>", "Heading Text\n====");
-		assertContent("<h1>Heading <em>Text</em></h1>", "Heading *Text*\n====");
+		assertContent("<h2 id=\"heading-text\">Heading Text</h2>", "Heading Text\n-------");
+		assertContent("<h1 id=\"heading-text\">Heading Text</h1>", "Heading Text\n=");
+		assertContent("<h1 id=\"heading-text\">Heading Text</h1>", "Heading Text\n====");
+		assertContent("<h1 id=\"heading-text\">Heading <em>Text</em></h1>", "Heading *Text*\n====");
 	}
 }
diff --git a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParserTest.java b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParserTest.java
index 8b4a0e3..3020257 100644
--- a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParserTest.java
+++ b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParserTest.java
@@ -14,6 +14,7 @@
 import static org.junit.Assert.assertEquals;
 
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.mylyn.internal.wikitext.commonmark.Line;
@@ -52,6 +53,14 @@
 				new Characters(line, 4, 9, "two three"));
 	}
 
+	@Test
+	public void toStringContent() {
+		InlineParser parser = new InlineParser(new CodeSpan(), new AllCharactersSpan());
+		String stringContent = parser.toStringContent(ProcessingContext.empty(),
+				new TextSegment(Collections.singletonList(new Line(1, 0, "one `two` three"))));
+		assertEquals("one two three", stringContent);
+	}
+
 	private void assertParse(String content, Inline... inlines) {
 		List<Inline> expected = Arrays.asList(inlines);
 		List<Inline> actual = createInlines().parse(ProcessingContext.empty(),
diff --git a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/spec/CommonMarkSpecTest.java b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/spec/CommonMarkSpecTest.java
index dbfb1ef..a92768c 100644
--- a/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/spec/CommonMarkSpecTest.java
+++ b/org.eclipse.mylyn.wikitext.commonmark.tests/src/org/eclipse/mylyn/internal/wikitext/commonmark/spec/CommonMarkSpecTest.java
@@ -30,6 +30,8 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.eclipse.mylyn.wikitext.commonmark.CommonMarkLanguage;
+import org.eclipse.mylyn.wikitext.core.parser.markup.IdGenerationStrategy;
 import org.eclipse.mylyn.wikitext.core.util.LocationTrackingReader;
 import org.junit.Before;
 import org.junit.Test;
@@ -100,7 +102,14 @@
 	@Test
 	public void test() {
 		try {
-			assertContent(expectation.expected, expectation.input);
+			CommonMarkLanguage language = new CommonMarkLanguage() {
+
+				@Override
+				public IdGenerationStrategy getIdGenerationStrategy() {
+					return null;
+				}
+			};
+			assertContent(language, expectation.expected, expectation.input);
 		} catch (AssertionError e) {
 			System.out.println(lineNumber + ", // " + heading);
 			System.out.flush();
diff --git a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkIdGenerationStrategy.java b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkIdGenerationStrategy.java
new file mode 100644
index 0000000..d3e0b3a
--- /dev/null
+++ b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/CommonMarkIdGenerationStrategy.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2015 David Green.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     David Green - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.internal.wikitext.commonmark;
+
+import java.util.Locale;
+
+import org.eclipse.mylyn.wikitext.core.parser.markup.IdGenerationStrategy;
+
+import com.google.common.base.CharMatcher;
+
+public class CommonMarkIdGenerationStrategy extends IdGenerationStrategy {
+
+	private final CharMatcher hyphenMatcher = CharMatcher.is('-');
+
+	@Override
+	public String generateId(String headingText) {
+		String id = headingText.toLowerCase(Locale.ENGLISH).replaceAll("[^a-z0-9_]", "-");
+		id = hyphenMatcher.trimAndCollapseFrom(id, '-');
+		return id;
+	}
+
+}
diff --git a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContext.java b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContext.java
index 5b36aa1..0b0c912 100644
--- a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContext.java
+++ b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContext.java
@@ -13,6 +13,8 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import org.eclipse.mylyn.wikitext.core.parser.IdGenerator;
+
 import com.google.common.collect.ImmutableMap;
 
 public class ProcessingContext {
@@ -54,8 +56,11 @@
 
 	private final ImmutableMap<String, NamedUriWithTitle> links;
 
-	ProcessingContext(ImmutableMap<String, NamedUriWithTitle> links) {
+	private final IdGenerator idGenerator;
+
+	ProcessingContext(ImmutableMap<String, NamedUriWithTitle> links, IdGenerator idGenerator) {
 		this.links = checkNotNull(links);
+		this.idGenerator = checkNotNull(idGenerator);
 	}
 
 	public boolean isEmpty() {
@@ -65,4 +70,8 @@
 	public NamedUriWithTitle namedUriWithTitle(String name) {
 		return links.get(name.toLowerCase());
 	}
+
+	public String generateHeadingId(int headingLevel, String headingText) {
+		return idGenerator.newId("h" + headingLevel, headingText);
+	}
 }
diff --git a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextBuilder.java b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextBuilder.java
index 8cd11de..0c10a85 100644
--- a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextBuilder.java
+++ b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/ProcessingContextBuilder.java
@@ -16,6 +16,8 @@
 import java.util.Map;
 
 import org.eclipse.mylyn.internal.wikitext.commonmark.ProcessingContext.NamedUriWithTitle;
+import org.eclipse.mylyn.wikitext.core.parser.IdGenerator;
+import org.eclipse.mylyn.wikitext.core.parser.markup.IdGenerationStrategy;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
@@ -24,6 +26,8 @@
 
 	private final Map<String, NamedUriWithTitle> linkByName = new HashMap<>();
 
+	private IdGenerationStrategy idGenerationStrategy = new CommonMarkIdGenerationStrategy();
+
 	public ProcessingContextBuilder referenceDefinition(String name, String href, String title) {
 		if (!Strings.isNullOrEmpty(name)) {
 			String key = name.toLowerCase(Locale.ROOT);
@@ -34,8 +38,28 @@
 		return this;
 	}
 
+	public ProcessingContextBuilder idGenerationStrategy(IdGenerationStrategy idGenerationStrategy) {
+		this.idGenerationStrategy = idGenerationStrategy;
+		return this;
+	}
+
 	public ProcessingContext build() {
-		return new ProcessingContext(ImmutableMap.copyOf(linkByName));
+		return new ProcessingContext(ImmutableMap.copyOf(linkByName), idGenerator());
+	}
+
+	private IdGenerator idGenerator() {
+		if (idGenerationStrategy == null) {
+			return new IdGenerator() {
+
+				@Override
+				public String newId(String type, String text) {
+					return null;
+				}
+			};
+		}
+		IdGenerator generator = new IdGenerator();
+		generator.setGenerationStrategy(idGenerationStrategy);
+		return generator;
 	}
 
 	ProcessingContextBuilder() {
diff --git a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlock.java b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlock.java
index e52d02c..1bf2e28 100644
--- a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlock.java
+++ b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/AtxHeaderBlock.java
@@ -38,16 +38,30 @@
 		lineSequence.advance();
 
 		builder.setLocator(currentLine.toLocator());
-		builder.beginHeading(headingLevel(matcher), new HeadingAttributes());
 
 		int contentOffset = matcher.start(2);
 		int contentEnd = matcher.end(2);
+		int headingLevel = headingLevel(matcher);
 		if (contentEnd > contentOffset) {
 			Line headerContent = currentLine.segment(contentOffset, contentEnd - contentOffset);
-			new InlineContent().emit(context, builder, new TextSegment(Collections.singletonList(headerContent)));
+			TextSegment textSegment = new TextSegment(Collections.singletonList(headerContent));
+
+			HeadingAttributes attributes = new HeadingAttributes();
+
+			InlineContent inlineContent = new InlineContent();
+			String headingText = inlineContent.toStringContent(context, textSegment);
+			attributes.setId(context.generateHeadingId(headingLevel, headingText));
+
+			builder.beginHeading(headingLevel, attributes);
+
+			inlineContent.emit(context, builder, textSegment);
+
+			builder.endHeading();
+		} else {
+			builder.beginHeading(headingLevel, new HeadingAttributes());
+			builder.endHeading();
 		}
 
-		builder.endHeading();
 	}
 
 	private int headingLevel(Matcher matcher) {
diff --git a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlock.java b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlock.java
index 9d1449e..f9ed8dc 100644
--- a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlock.java
+++ b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/blocks/SetextHeaderBlock.java
@@ -42,9 +42,18 @@
 
 		builder.setLocator(currentLine.toLocator());
 		int headingLevel = headingLevel(matcher);
-		builder.beginHeading(headingLevel, new HeadingAttributes());
 
-		new InlineContent().emit(context, builder, new TextSegment(Collections.singletonList(currentLine)));
+		TextSegment textSegment = new TextSegment(Collections.singletonList(currentLine));
+
+		InlineContent inlineContent = new InlineContent();
+		HeadingAttributes attributes = new HeadingAttributes();
+
+		String headingText = inlineContent.toStringContent(context, textSegment);
+		attributes.setId(context.generateHeadingId(headingLevel, headingText));
+
+		builder.beginHeading(headingLevel, attributes);
+
+		inlineContent.emit(context, builder, textSegment);
 
 		builder.endHeading();
 
diff --git a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParser.java b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParser.java
index ef11970..2e3f4fd 100644
--- a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParser.java
+++ b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/internal/wikitext/commonmark/inlines/InlineParser.java
@@ -41,6 +41,11 @@
 		emit(builder, inlines);
 	}
 
+	public String toStringContent(ProcessingContext context, TextSegment textSegment) {
+		List<Inline> inlines = parse(context, textSegment);
+		return toStringContent(inlines);
+	}
+
 	public static void emit(DocumentBuilder builder, List<Inline> inlines) {
 		for (Inline inline : inlines) {
 			builder.setLocator(inline.getLocator());
diff --git a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/wikitext/commonmark/CommonMarkLanguage.java b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/wikitext/commonmark/CommonMarkLanguage.java
index 3f39c6d..b750c54 100644
--- a/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/wikitext/commonmark/CommonMarkLanguage.java
+++ b/org.eclipse.mylyn.wikitext.commonmark/src/org/eclipse/mylyn/wikitext/commonmark/CommonMarkLanguage.java
@@ -13,12 +13,14 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import org.eclipse.mylyn.internal.wikitext.commonmark.CommonMark;
+import org.eclipse.mylyn.internal.wikitext.commonmark.CommonMarkIdGenerationStrategy;
 import org.eclipse.mylyn.internal.wikitext.commonmark.LineSequence;
 import org.eclipse.mylyn.internal.wikitext.commonmark.ProcessingContext;
 import org.eclipse.mylyn.internal.wikitext.commonmark.ProcessingContextBuilder;
 import org.eclipse.mylyn.internal.wikitext.commonmark.SourceBlocks;
 import org.eclipse.mylyn.wikitext.core.parser.DocumentBuilder;
 import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
+import org.eclipse.mylyn.wikitext.core.parser.markup.IdGenerationStrategy;
 import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
 
 public class CommonMarkLanguage extends MarkupLanguage {
@@ -48,8 +50,14 @@
 		}
 	}
 
+	@Override
+	public IdGenerationStrategy getIdGenerationStrategy() {
+		return new CommonMarkIdGenerationStrategy();
+	}
+
 	private ProcessingContext createContext(SourceBlocks sourceBlocks, String markupContent) {
-		ProcessingContextBuilder contextBuilder = ProcessingContext.builder();
+		ProcessingContextBuilder contextBuilder = ProcessingContext.builder()
+				.idGenerationStrategy(getIdGenerationStrategy());
 		sourceBlocks.createContext(contextBuilder, LineSequence.create(markupContent));
 		return contextBuilder.build();
 	}