Skip to content

Commit 4aa2ca4

Browse files
committed
Merge branch 'main' of github.com:elastic/docs-builder into add-automated-guide
2 parents 4963f74 + 3c0da5f commit 4aa2ca4

File tree

27 files changed

+1027
-14
lines changed

27 files changed

+1027
-14
lines changed

docs-builder.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "build", "build\build.fsproj
5151
EndProject
5252
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "docs-assembler", "src\docs-assembler\docs-assembler.csproj", "{28350800-B44B-479B-86E2-1D39E321C0B4}"
5353
EndProject
54+
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "authoring", "tests\authoring\authoring.fsproj", "{018F959E-824B-4664-B345-066784478D24}"
55+
EndProject
5456
Global
5557
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5658
Debug|Any CPU = Debug|Any CPU
@@ -89,6 +91,10 @@ Global
8991
{28350800-B44B-479B-86E2-1D39E321C0B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
9092
{28350800-B44B-479B-86E2-1D39E321C0B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
9193
{28350800-B44B-479B-86E2-1D39E321C0B4}.Release|Any CPU.Build.0 = Release|Any CPU
94+
{018F959E-824B-4664-B345-066784478D24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
95+
{018F959E-824B-4664-B345-066784478D24}.Debug|Any CPU.Build.0 = Debug|Any CPU
96+
{018F959E-824B-4664-B345-066784478D24}.Release|Any CPU.ActiveCfg = Release|Any CPU
97+
{018F959E-824B-4664-B345-066784478D24}.Release|Any CPU.Build.0 = Release|Any CPU
9298
EndGlobalSection
9399
GlobalSection(NestedProjects) = preSolution
94100
{4D198E25-C211-41DC-9E84-B15E89BD7048} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A}
@@ -99,5 +105,6 @@ Global
99105
{CD2887E3-BDA9-434B-A5BF-9ED38DE20332} = {245023D2-D3CA-47B9-831D-DAB91A2FFDC7}
100106
{A2A34BBC-CB5E-4100-9529-A12B6ECB769C} = {245023D2-D3CA-47B9-831D-DAB91A2FFDC7}
101107
{28350800-B44B-479B-86E2-1D39E321C0B4} = {BE6011CC-1200-4957-B01F-FCCA10C5CF5A}
108+
{018F959E-824B-4664-B345-066784478D24} = {67B576EE-02FA-4F9B-94BC-3630BC09ECE5}
102109
EndGlobalSection
103110
EndGlobal

docs-builder.sln.DotSettings

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
22
<s:Boolean x:Key="/Default/UserDictionary/Words/=docset/@EntryIndexedValue">True</s:Boolean>
3+
<s:Boolean x:Key="/Default/UserDictionary/Words/=frontmatter/@EntryIndexedValue">True</s:Boolean>
34
<s:Boolean x:Key="/Default/UserDictionary/Words/=linenos/@EntryIndexedValue">True</s:Boolean>
4-
<s:Boolean x:Key="/Default/UserDictionary/Words/=literalinclude/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
5+
<s:Boolean x:Key="/Default/UserDictionary/Words/=literalinclude/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/UserDictionary/Words/=_0060_0060inli/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

docs/migration/freeze/gh-action.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ jobs:
2727
comment-on-asciidoc-change:
2828
permissions:
2929
contents: read
30-
pull_request: write
30+
pull-requests: write
3131
uses: elastic/docs-builder/.github/workflows/comment-on-asciidoc-changes.yml@main
3232
```

docs/testing/index.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,29 @@ The files in this directory are used for testing purposes. Do not edit these fil
55

66
###### [#synthetics-config-file]
77

8-
% [Non Existing Link](./non-existing.md)
8+
% [Non Existing Link](./non-existing.md)
9+
10+
```json
11+
{
12+
"key": "value"
13+
}
14+
```
15+
16+
```json
17+
{
18+
"key": "value"
19+
}
20+
```
21+
22+
1. this is a list
23+
```json
24+
{
25+
"key": "value"
26+
}
27+
```
28+
1. this is a sub-list
29+
```json
30+
{
31+
"key": "value"
32+
}
33+
```
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
namespace Elastic.Markdown.Helpers;
6+
7+
public static class MarkdownStringExtensions
8+
{
9+
public static string StripMarkdown(this string markdown)
10+
{
11+
using var writer = new StringWriter();
12+
Markdig.Markdown.ToPlainText(markdown, writer);
13+
return writer.ToString().TrimEnd('\n');
14+
}
15+
}

src/Elastic.Markdown/IO/MarkdownFile.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,28 @@ public DocumentationGroup? Parent
4242
public string? UrlPathPrefix { get; }
4343
private MarkdownParser MarkdownParser { get; }
4444
public YamlFrontMatter? YamlFrontMatter { get; private set; }
45-
public string? Title { get; private set; }
45+
public string? TitleRaw { get; private set; }
46+
47+
public string? Title
48+
{
49+
get => _title;
50+
private set
51+
{
52+
_title = value?.StripMarkdown();
53+
TitleRaw = value;
54+
}
55+
}
4656
public string? NavigationTitle
4757
{
4858
get => !string.IsNullOrEmpty(_navigationTitle) ? _navigationTitle : Title;
49-
private set => _navigationTitle = value;
59+
private set => _navigationTitle = value?.StripMarkdown();
5060
}
5161

5262
//indexed by slug
53-
private readonly Dictionary<string, PageTocItem> _tableOfContent = new();
63+
private readonly Dictionary<string, PageTocItem> _tableOfContent = new(StringComparer.OrdinalIgnoreCase);
5464
public IReadOnlyDictionary<string, PageTocItem> TableOfContents => _tableOfContent;
5565

56-
private readonly HashSet<string> _additionalLabels = new();
66+
private readonly HashSet<string> _additionalLabels = new(StringComparer.OrdinalIgnoreCase);
5767
public IReadOnlySet<string> AdditionalLabels => _additionalLabels;
5868

5969
public string FilePath { get; }
@@ -64,6 +74,7 @@ public string? NavigationTitle
6474

6575
private bool _instructionsParsed;
6676
private DocumentationGroup? _parent;
77+
private string? _title;
6778

6879
public MarkdownFile[] YieldParents()
6980
{
@@ -156,7 +167,7 @@ private void ReadDocumentInstructions(MarkdownDocument document)
156167
.Select(h => (h.GetData("header") as string, h.GetData("anchor") as string))
157168
.Select(h => new PageTocItem
158169
{
159-
Heading = h.Item1!.Replace("`", "").Replace("*", ""),
170+
Heading = h.Item1!.StripMarkdown(),
160171
Slug = (h.Item2 ?? h.Item1).Slugify()
161172
})
162173
.ToList();

src/Elastic.Markdown/Myst/CodeBlocks/EnhancedCodeBlockHtmlRenderer.cs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Elastic.Markdown.Diagnostics;
66
using Elastic.Markdown.Myst.Directives;
77
using Elastic.Markdown.Slices.Directives;
8+
using Markdig.Helpers;
89
using Markdig.Renderers;
910
using Markdig.Renderers.Html;
1011
using Markdig.Syntax;
@@ -14,15 +15,85 @@ namespace Elastic.Markdown.Myst.CodeBlocks;
1415

1516
public class EnhancedCodeBlockHtmlRenderer : HtmlObjectRenderer<EnhancedCodeBlock>
1617
{
18+
private const int TabWidth = 4;
1719

1820
private static void RenderRazorSlice<T>(RazorSlice<T> slice, HtmlRenderer renderer, EnhancedCodeBlock block)
1921
{
2022
var html = slice.RenderAsync().GetAwaiter().GetResult();
2123
var blocks = html.Split("[CONTENT]", 2, StringSplitOptions.RemoveEmptyEntries);
2224
renderer.Write(blocks[0]);
23-
renderer.WriteLeafRawLines(block, true, true, false);
25+
RenderCodeBlockLines(renderer, block);
2426
renderer.Write(blocks[1]);
2527
}
28+
29+
/// <summary>
30+
/// Renders the code block lines while also removing the common indentation level.
31+
/// Required because EnableTrackTrivia preserves extra indentation.
32+
/// </summary>
33+
private static void RenderCodeBlockLines(HtmlRenderer renderer, EnhancedCodeBlock block)
34+
{
35+
var commonIndent = GetCommonIndent(block);
36+
for (var i = 0; i < block.Lines.Count; i++)
37+
{
38+
var line = block.Lines.Lines[i];
39+
var slice = line.Slice;
40+
var indent = CountIndentation(slice);
41+
if (indent >= commonIndent)
42+
slice.Start += commonIndent;
43+
RenderCodeBlockLine(renderer, block, slice, i);
44+
}
45+
}
46+
47+
private static void RenderCodeBlockLine(HtmlRenderer renderer, EnhancedCodeBlock block, StringSlice slice, int lineNumber)
48+
{
49+
renderer.WriteEscape(slice);
50+
RenderCallouts(renderer, block, lineNumber);
51+
renderer.WriteLine();
52+
}
53+
54+
private static void RenderCallouts(HtmlRenderer renderer, EnhancedCodeBlock block, int lineNumber)
55+
{
56+
var callOuts = FindCallouts(block.CallOuts ?? [], lineNumber + 1);
57+
foreach (var callOut in callOuts)
58+
renderer.Write($"<span class=\"code-callout\">{callOut.Index}</span>");
59+
}
60+
61+
private static IEnumerable<CallOut> FindCallouts(
62+
IEnumerable<CallOut> callOuts,
63+
int lineNumber
64+
) => callOuts.Where(callOut => callOut.Line == lineNumber);
65+
66+
private static int GetCommonIndent(EnhancedCodeBlock block)
67+
{
68+
var commonIndent = int.MaxValue;
69+
for (var i = 0; i < block.Lines.Count; i++)
70+
{
71+
var line = block.Lines.Lines[i].Slice;
72+
if (line.IsEmptyOrWhitespace())
73+
continue;
74+
var indent = CountIndentation(line);
75+
commonIndent = Math.Min(commonIndent, indent);
76+
}
77+
return commonIndent;
78+
}
79+
80+
81+
private static int CountIndentation(StringSlice slice)
82+
{
83+
var indentCount = 0;
84+
for (var i = slice.Start; i <= slice.End; i++)
85+
{
86+
var c = slice.Text[i];
87+
if (c == ' ')
88+
indentCount++;
89+
else if (c == '\t')
90+
indentCount += TabWidth;
91+
else
92+
break;
93+
}
94+
return indentCount;
95+
}
96+
2697
protected override void Write(HtmlRenderer renderer, EnhancedCodeBlock block)
2798
{
2899
var callOuts = block.UniqueCallOuts;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using Markdig;
6+
using Markdig.Helpers;
7+
using Markdig.Parsers;
8+
using Markdig.Parsers.Inlines;
9+
using Markdig.Renderers;
10+
using Markdig.Renderers.Html;
11+
using Markdig.Renderers.Html.Inlines;
12+
using Markdig.Syntax.Inlines;
13+
14+
namespace Elastic.Markdown.Myst.InlineParsers;
15+
16+
public static class HardBreakBuilderExtensions
17+
{
18+
public static MarkdownPipelineBuilder UseHardBreaks(this MarkdownPipelineBuilder pipeline)
19+
{
20+
pipeline.Extensions.AddIfNotAlready<HardBreakBuilderExtension>();
21+
return pipeline;
22+
}
23+
}
24+
25+
public class HardBreakBuilderExtension : IMarkdownExtension
26+
{
27+
public void Setup(MarkdownPipelineBuilder pipeline) =>
28+
pipeline.InlineParsers.InsertBefore<EmphasisInlineParser>(new HardBreakParser());
29+
30+
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) =>
31+
renderer.ObjectRenderers.InsertAfter<EmphasisInlineRenderer>(new HardBreakRenderer());
32+
}
33+
34+
public class HardBreakParser : InlineParser
35+
{
36+
public HardBreakParser() => OpeningCharacters = ['<'];
37+
38+
public override bool Match(InlineProcessor processor, ref StringSlice slice)
39+
{
40+
var span = slice.AsSpan();
41+
if (!span.StartsWith("<br"))
42+
return false;
43+
44+
var closingStart = span[3..].IndexOf('>');
45+
// we allow
46+
if (closingStart != 0)
47+
return false;
48+
49+
processor.Inline = new HardBreak();
50+
51+
var sliceEnd = slice.Start + 4; //<br + >
52+
while (slice.Start != sliceEnd)
53+
slice.SkipChar();
54+
55+
return true;
56+
}
57+
}
58+
59+
public class HardBreak : LeafInline;
60+
61+
public class HardBreakRenderer : HtmlObjectRenderer<HardBreak>
62+
{
63+
protected override void Write(HtmlRenderer renderer, HardBreak obj) =>
64+
renderer.Write("<br>");
65+
}

src/Elastic.Markdown/Myst/MarkdownParser.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ public class MarkdownParser(
5151
.UseGridTables()
5252
.UsePipeTables()
5353
.UseDirectives()
54+
.UseDefinitionLists()
5455
.UseEnhancedCodeBlocks()
5556
.DisableHtml()
57+
.UseHardBreaks()
5658
.Build();
5759

5860
public ConfigurationFile Configuration { get; } = configuration;
@@ -107,6 +109,4 @@ public MarkdownDocument Parse(string yaml, IFileInfo parent, YamlFrontMatter? ma
107109
var markdownDocument = Markdig.Markdown.Parse(yaml, Pipeline, context);
108110
return markdownDocument;
109111
}
110-
111-
112112
}

src/Elastic.Markdown/Slices/HtmlWriter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public async Task<string> RenderLayout(MarkdownFile markdown, Cancel ctx = defau
5656
var slice = Index.Create(new IndexViewModel
5757
{
5858
Title = markdown.Title ?? "[TITLE NOT SET]",
59+
TitleRaw = markdown.TitleRaw ?? "[TITLE NOT SET]",
5960
MarkdownHtml = html,
6061
PageTocItems = markdown.TableOfContents.Values.ToList(),
6162
Tree = DocumentationSet.Tree,

0 commit comments

Comments
 (0)