Upstream xoofx/markdig state of the touched files before baa95a9ca3
This commit is contained in:
1 parent
cf9456728c
commit
40eebc0cd8
5 files changed
+89
-74
No files matched your search
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
title: Auto-identifiers
|
||||||
|
---
|
||||||
|
|
||||||
|
# Auto-identifiers
|
||||||
|
|
||||||
|
Enable with `.UseAutoIdentifiers()` (included in `UseAdvancedExtensions()`).
|
||||||
|
|
||||||
|
This extension automatically generates `id` attributes for all headings, similar to [Pandoc auto identifiers](https://pandoc.org/MANUAL.html#extension-auto_identifiers). This is essential for linking to specific sections.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
Every heading gets an `id` attribute derived from its text content:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Getting Started
|
||||||
|
```
|
||||||
|
|
||||||
|
Renders as:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h2 id="getting-started">Getting Started</h2>
|
||||||
|
```
|
||||||
|
|
||||||
|
You can then link to it:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
See [Getting Started](#getting-started).
|
||||||
|
```
|
||||||
|
|
||||||
|
## ID generation rules
|
||||||
|
|
||||||
|
1. Convert to lowercase
|
||||||
|
2. Remove anything that is not a letter, number, space, or hyphen
|
||||||
|
3. Replace spaces with hyphens
|
||||||
|
4. Remove leading/trailing hyphens
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
|
||||||
|
{.table}
|
||||||
|
| Heading | Generated ID |
|
||||||
|
|---|---|
|
||||||
|
| `# Hello World` | `hello-world` |
|
||||||
|
| `## C# Tips & Tricks` | `c-tips--tricks` |
|
||||||
|
| `### 2. Installation` | `2-installation` |
|
||||||
|
|
||||||
|
## Duplicate handling
|
||||||
|
|
||||||
|
If two headings produce the same ID, a numeric suffix is appended:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Section
|
||||||
|
## Section
|
||||||
|
## Section
|
||||||
|
```
|
||||||
|
|
||||||
|
Produces: `section`, `section-1`, `section-2`.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
`UseAutoIdentifiers` accepts an `AutoIdentifierOptions` flags enum:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using Markdig.Extensions.AutoIdentifiers;
|
||||||
|
|
||||||
|
var pipeline = new MarkdownPipelineBuilder()
|
||||||
|
.UseAutoIdentifiers(AutoIdentifierOptions.GitHub)
|
||||||
|
.Build();
|
||||||
|
```
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
|
||||||
|
{.table}
|
||||||
|
| Option | Description |
|
||||||
|
|---|---|
|
||||||
|
| `AutoIdentifierOptions.Default` | Standard auto-identifier behavior |
|
||||||
|
| `AutoIdentifierOptions.GitHub` | GitHub-compatible ID generation |
|
||||||
|
| `AutoIdentifierOptions.AutoLink` | Also create a self-link anchor |
|
||||||
|
| `AutoIdentifierOptions.AllowOnlyAscii` | Strip non-ASCII characters from IDs |
|
||||||
|
|
||||||
|
## Combining with generic attributes
|
||||||
|
|
||||||
|
You can override the auto-generated ID using [Generic attributes](generic-attributes.md):
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## My Heading {#custom-id}
|
||||||
|
```
|
||||||
|
|
||||||
|
The explicit `#custom-id` takes precedence over the auto-generated one.
|
||||||
@@ -21,29 +21,4 @@ public class TestAutoLinks
|
|||||||
|
|
||||||
Assert.That(html, Is.EqualTo(expected).IgnoreWhiteSpace);
|
Assert.That(html, Is.EqualTo(expected).IgnoreWhiteSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/xoofx/markdig/issues/668
|
|
||||||
// A heading's implicit "AutoLink" reference (registered by the AutoIdentifiers extension) must not
|
|
||||||
// resolve when its label is nested inside another still-open link bracket, otherwise it silently
|
|
||||||
// breaks the outer, explicitly authored link.
|
|
||||||
[Test]
|
|
||||||
public void TestAutoIdentifierHeadingLinkDoesNotHijackNestedLinkLabel()
|
|
||||||
{
|
|
||||||
var markdown = "# Testing Markdown\n\n" +
|
|
||||||
"### Header\n\n" +
|
|
||||||
"[Testing [Header]](https://www.bing.com)\n\n" +
|
|
||||||
"[Testing [test]](https://www.google.com)\n";
|
|
||||||
var expected = "<h1 id=\"testing-markdown\">Testing Markdown</h1>\n" +
|
|
||||||
"<h3 id=\"header\">Header</h3>\n" +
|
|
||||||
"<p><a href=\"https://www.bing.com\">Testing [Header]</a></p>\n" +
|
|
||||||
"<p><a href=\"https://www.google.com\">Testing [test]</a></p>";
|
|
||||||
|
|
||||||
var pipeline = new MarkdownPipelineBuilder()
|
|
||||||
.UseAutoLinks()
|
|
||||||
.UseAutoIdentifiers()
|
|
||||||
.Build();
|
|
||||||
var html = Markdown.ToHtml(markdown, pipeline);
|
|
||||||
|
|
||||||
Assert.That(html, Is.EqualTo(expected).IgnoreWhiteSpace);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -24,12 +24,4 @@ public class HeadingLinkReferenceDefinition : LinkReferenceDefinition
|
|||||||
/// Gets or sets the heading related to this link reference definition.
|
/// Gets or sets the heading related to this link reference definition.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public HeadingBlock Heading { get; set; }
|
public HeadingBlock Heading { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <remarks>
|
|
||||||
/// This reference definition is created implicitly for every heading, so it must not resolve when its
|
|
||||||
/// label is nested inside another still-open link bracket, e.g. <c>[Some text [HeadingText]](url)</c>.
|
|
||||||
/// Otherwise it would silently break the outer, explicitly authored link.
|
|
||||||
/// </remarks>
|
|
||||||
internal override bool AllowResolutionInsideOpenLink => false;
|
|
||||||
}
|
}
|
||||||
@@ -150,14 +150,6 @@ public class LinkInlineParser : InlineParser
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implicitly generated reference definitions (e.g. automatic heading anchors from the auto-identifier
|
|
||||||
// extension) must not hijack a bracket pair nested inside another still-open link, otherwise they would
|
|
||||||
// silently break the outer, explicitly authored link (see https://github.com/xoofx/markdig/issues/668).
|
|
||||||
if (!linkRef.AllowResolutionInsideOpenLink && HasActiveAncestorLink(parent))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Inline? link = null;
|
Inline? link = null;
|
||||||
// Try to use a callback directly defined on the LinkReferenceDefinition
|
// Try to use a callback directly defined on the LinkReferenceDefinition
|
||||||
if (linkRef.CreateLinkInline != null)
|
if (linkRef.CreateLinkInline != null)
|
||||||
@@ -438,24 +430,6 @@ public class LinkInlineParser : InlineParser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether the given link delimiter is nested inside another link/image delimiter that is
|
|
||||||
/// still active, i.e. it may still be resolved into a real link/image once fully parsed.
|
|
||||||
/// </summary>
|
|
||||||
private static bool HasActiveAncestorLink(LinkDelimiterInline delimiter)
|
|
||||||
{
|
|
||||||
var inline = delimiter.Parent;
|
|
||||||
while (inline != null)
|
|
||||||
{
|
|
||||||
if (inline is LinkDelimiterInline { IsActive: true })
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
inline = inline.Parent;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MarkParentAsInactive(Inline? inline)
|
private static void MarkParentAsInactive(Inline? inline)
|
||||||
{
|
{
|
||||||
while (inline != null)
|
while (inline != null)
|
||||||
|
|||||||
@@ -136,21 +136,6 @@ public class LinkReferenceDefinition : LeafBlock
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public CreateLinkInlineDelegate? CreateLinkInline { get; set; }
|
public CreateLinkInlineDelegate? CreateLinkInline { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this reference definition is allowed to resolve into a link when its
|
|
||||||
/// label is nested inside another link or image bracket that is still open (and may still become a valid
|
|
||||||
/// link/image once fully parsed).
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is <c>true</c> for regular, user-authored reference definitions so that CommonMark's "links cannot
|
|
||||||
/// contain links" resolution order is preserved. Implicitly generated reference definitions (e.g. the
|
|
||||||
/// automatic heading anchors created by the auto-identifier extension) override this to <c>false</c> so
|
|
||||||
/// they don't silently hijack a bracket pair that is part of a larger, still-open link label, such as
|
|
||||||
/// <c>[Some text [HeadingText]](https://example.com)</c> (see
|
|
||||||
/// https://github.com/xoofx/markdig/issues/668).
|
|
||||||
/// </remarks>
|
|
||||||
internal virtual bool AllowResolutionInsideOpenLink => true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to the parse the specified text into a definition.
|
/// Tries to the parse the specified text into a definition.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in new issue
Block a user