diff --git a/docs/_docset.yml b/docs/_docset.yml index 8ab198efe..31b325c65 100644 --- a/docs/_docset.yml +++ b/docs/_docset.yml @@ -16,6 +16,7 @@ subs: ech: "Elastic Cloud Hosted" serverless-full: "Elastic Cloud Serverless" ecloud: "Elastic Cloud" + dbuild: "docs-builder" features: primary-nav: false diff --git a/docs/contribute/locally.md b/docs/contribute/locally.md index 15d1ce815..e1cb48ab2 100644 --- a/docs/contribute/locally.md +++ b/docs/contribute/locally.md @@ -145,7 +145,7 @@ cd docs-content ``` ::::: -:::::{step} Run docs-builder +:::::{step} Run {{dbuild}} Run the `docs-builder` binary with the `serve` command to build and serve the content set to [http://localhost:3000](http://localhost:3000). If necessary, specify the path to the `docset.yml` file that you want to build with `-p`. diff --git a/src/Elastic.Markdown/IO/MarkdownFile.cs b/src/Elastic.Markdown/IO/MarkdownFile.cs index 6e1c21eec..19c33c1a0 100644 --- a/src/Elastic.Markdown/IO/MarkdownFile.cs +++ b/src/Elastic.Markdown/IO/MarkdownFile.cs @@ -289,15 +289,25 @@ public static List GetAnchors( .OfType() .Where(step => !string.IsNullOrEmpty(step.Title)) .Where(step => !IsNestedInOtherDirective(step)) - .Select(step => new + .Select(step => { - TocItem = new PageTocItem + var processedTitle = step.Title; + // Apply substitutions to step titles + if (subs.Count > 0 && processedTitle.AsSpan().ReplaceSubstitutions(subs, set.Context.Collector, out var replacement)) { - Heading = step.Title, - Slug = step.Anchor, - Level = step.HeadingLevel // Use dynamic heading level - }, - step.Line + processedTitle = replacement; + } + + return new + { + TocItem = new PageTocItem + { + Heading = processedTitle, + Slug = step.Anchor, + Level = step.HeadingLevel // Use dynamic heading level + }, + step.Line + }; }); var toc = headingTocs diff --git a/src/Elastic.Markdown/Myst/Directives/Stepper/StepView.cshtml b/src/Elastic.Markdown/Myst/Directives/Stepper/StepView.cshtml index e6712b38c..78f2d698d 100644 --- a/src/Elastic.Markdown/Myst/Directives/Stepper/StepView.cshtml +++ b/src/Elastic.Markdown/Myst/Directives/Stepper/StepView.cshtml @@ -6,32 +6,32 @@ { case 1:

- @Model.Title + @Model.RenderTitle()

break; case 2:

- @Model.Title + @Model.RenderTitle()

break; case 3:

- @Model.Title + @Model.RenderTitle()

break; case 4:

- @Model.Title + @Model.RenderTitle()

break; case 5:
- @Model.Title + @Model.RenderTitle()
break; default:
- @Model.Title + @Model.RenderTitle()
break; } diff --git a/src/Elastic.Markdown/Myst/Directives/Stepper/StepViewModel.cs b/src/Elastic.Markdown/Myst/Directives/Stepper/StepViewModel.cs index 2efcb442e..b7f17cdd8 100644 --- a/src/Elastic.Markdown/Myst/Directives/Stepper/StepViewModel.cs +++ b/src/Elastic.Markdown/Myst/Directives/Stepper/StepViewModel.cs @@ -2,6 +2,12 @@ // 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 Elastic.Markdown.IO; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; +using Microsoft.AspNetCore.Html; + namespace Elastic.Markdown.Myst.Directives.Stepper; public class StepViewModel : DirectiveViewModel @@ -9,4 +15,38 @@ public class StepViewModel : DirectiveViewModel public required string Title { get; init; } public required string Anchor { get; init; } public required int HeadingLevel { get; init; } + + /// + /// Renders the title with full markdown processing (substitutions, links, emphasis, etc.) + /// + public HtmlString RenderTitle() + { + // Parse the title as markdown with full pipeline (including substitutions) + var directiveBlock = (DirectiveBlock)DirectiveBlock; + + // Get the YamlFrontMatter from the original document to support local substitutions + var originalContext = directiveBlock.GetData("context") as ParserContext; + var yamlFrontMatter = originalContext?.YamlFrontMatter; + + var context = new ParserContext(new ParserState(directiveBlock.Build) + { + MarkdownSourcePath = directiveBlock.CurrentFile, + YamlFrontMatter = yamlFrontMatter, + DocumentationFileLookup = (path) => null!, + CrossLinkResolver = null! + }); + + var document = Markdig.Markdown.Parse(Title, MarkdownParser.Pipeline, context); + + if (document.FirstOrDefault() is not Markdig.Syntax.ParagraphBlock firstBlock) + return new(Title); + + // Use the HTML renderer to render the inline content with full processing + var subscription = DocumentationObjectPoolProvider.HtmlRendererPool.Get(); + _ = subscription.HtmlRenderer.WriteLeafInline(firstBlock); + + var result = subscription.RentedStringBuilder?.ToString() ?? Title; + DocumentationObjectPoolProvider.HtmlRendererPool.Return(subscription); + return new(result); + } } diff --git a/src/Elastic.Markdown/Myst/Directives/Stepper/StepperBlock.cs b/src/Elastic.Markdown/Myst/Directives/Stepper/StepperBlock.cs index 4f8645ff0..e539c8376 100644 --- a/src/Elastic.Markdown/Myst/Directives/Stepper/StepperBlock.cs +++ b/src/Elastic.Markdown/Myst/Directives/Stepper/StepperBlock.cs @@ -26,6 +26,7 @@ public class StepBlock(DirectiveBlockParser parser, ParserContext context) : Dir public override void FinalizeAndValidate(ParserContext context) { Title = Arguments ?? string.Empty; + Anchor = Prop("anchor") ?? Title.Slugify(); // Calculate heading level based on preceding heading