-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for inline anchors in Markdown parsing (#331)
* Add support for inline anchors in Markdown parsing Introduced a parser for inline anchors using `$$$` syntax and updated related components to handle and render them as HTML anchor tags. Enhanced heading slug generation to exclude inline anchors, and added comprehensive tests to ensure correct behavior. * add documentation for inline anchors * dotnet format * add inline anchors to additional labels on markdown file so they can be resolved * added tests linking to inline anchors * dotnet format
- Loading branch information
Showing
9 changed files
with
342 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Licensed to Elasticsearch B.V under one or more agreements. | ||
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. | ||
// See the LICENSE file in the project root for more information | ||
|
||
using Slugify; | ||
|
||
namespace Elastic.Markdown.Helpers; | ||
|
||
public static class SlugExtensions | ||
{ | ||
private static readonly SlugHelper _slugHelper = new(); | ||
|
||
|
||
public static string Slugify(this string? text) => _slugHelper.GenerateSlug(text); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/Elastic.Markdown/Myst/InlineParsers/InlineAnchorParser.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// Licensed to Elasticsearch B.V under one or more agreements. | ||
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. | ||
// See the LICENSE file in the project root for more information | ||
|
||
using Elastic.Markdown.Helpers; | ||
using Markdig; | ||
using Markdig.Extensions.SmartyPants; | ||
using Markdig.Helpers; | ||
using Markdig.Parsers; | ||
using Markdig.Parsers.Inlines; | ||
using Markdig.Renderers; | ||
using Markdig.Renderers.Html; | ||
using Markdig.Renderers.Html.Inlines; | ||
using Markdig.Syntax.Inlines; | ||
|
||
namespace Elastic.Markdown.Myst.InlineParsers; | ||
|
||
public static class InlineAnchorBuilderExtensions | ||
{ | ||
public static MarkdownPipelineBuilder UseInlineAnchors(this MarkdownPipelineBuilder pipeline) | ||
{ | ||
pipeline.Extensions.AddIfNotAlready<InlineAnchorBuilderExtension>(); | ||
return pipeline; | ||
} | ||
} | ||
|
||
public class InlineAnchorBuilderExtension : IMarkdownExtension | ||
{ | ||
public void Setup(MarkdownPipelineBuilder pipeline) => | ||
pipeline.InlineParsers.InsertAfter<EmphasisInlineParser>(new InlineAnchorParser()); | ||
|
||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) => | ||
renderer.ObjectRenderers.InsertAfter<EmphasisInlineRenderer>(new InlineAnchorRenderer()); | ||
} | ||
|
||
public class InlineAnchorParser : InlineParser | ||
{ | ||
public InlineAnchorParser() | ||
{ | ||
OpeningCharacters = ['$']; | ||
} | ||
|
||
public override bool Match(InlineProcessor processor, ref StringSlice slice) | ||
{ | ||
var startPosition = processor.GetSourcePosition(slice.Start, out var line, out var column); | ||
var c = slice.CurrentChar; | ||
|
||
var span = slice.AsSpan(); | ||
if (!span.StartsWith("$$$")) | ||
return false; | ||
|
||
var closingStart = span[3..].IndexOf('$'); | ||
if (closingStart <= 0) | ||
return false; | ||
|
||
//not ending with three dollar signs | ||
if (!span[(closingStart + 3)..].StartsWith("$$$")) | ||
return false; | ||
|
||
processor.Inline = new InlineAnchor { Anchor = span[3..(closingStart + 3)].ToString().Slugify() }; | ||
|
||
var sliceEnd = slice.Start + closingStart + 6; | ||
while (slice.Start != sliceEnd) | ||
slice.SkipChar(); | ||
|
||
return true; | ||
} | ||
|
||
|
||
} | ||
|
||
public class InlineAnchor : LeafInline | ||
{ | ||
public required string Anchor { get; init; } | ||
} | ||
|
||
public class InlineAnchorRenderer : HtmlObjectRenderer<InlineAnchor> | ||
{ | ||
protected override void Write(HtmlRenderer renderer, InlineAnchor obj) => | ||
renderer.Write("<a id=\"").Write(obj.Anchor).Write("\"></a>"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.