Skip to content

Commit 8e2adbc

Browse files
authored
Support console family of code highlighters. (#375)
* Support `console` family of code highlighters. This adds support for the often used `console` language family and highlights the first line using a new custom highlighter. The rest of the code will be highlighted using json. * add console syntax documentation
1 parent 34e8b38 commit 8e2adbc

File tree

10 files changed

+112
-3
lines changed

10 files changed

+112
-3
lines changed

docs/syntax/code.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,38 @@ will output:
9191
var apiKey = new ApiKey("<API_KEY>"); // However this is
9292
var client = new ElasticsearchClient("<CLOUD_ID>", apiKey);
9393
```
94+
95+
96+
## Console output
97+
98+
We document alot of API endpoints at Elastic for this you can use `console` as language. The term console relates to the dev console in kibana which users can link to directly from these code snippets.
99+
100+
:::{note}
101+
We are still actively developing this special block and it's features
102+
:::
103+
104+
````markdown
105+
```console
106+
GET /mydocuments/_search
107+
{
108+
"from": 1,
109+
"query": {
110+
"match_all" {}
111+
}
112+
}
113+
```
114+
````
115+
116+
Will render as:
117+
118+
```console
119+
GET /mydocuments/_search
120+
{
121+
"from": 1,
122+
"query": {
123+
"match_all" {}
124+
}
125+
}
126+
```
127+
128+
The first line is highlighted as a dev console string and the remainder as json.

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ public class EnhancedCodeBlock(BlockParser parser, ParserContext context)
2727
public bool InlineAnnotations { get; set; }
2828

2929
public string Language { get; set; } = "unknown";
30+
31+
public string? Caption { get; set; }
32+
33+
public string? ApiCallHeader { get; set; }
3034
}

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,27 @@ private static void RenderRazorSlice<T>(RazorSlice<T> slice, HtmlRenderer render
3333
private static void RenderCodeBlockLines(HtmlRenderer renderer, EnhancedCodeBlock block)
3434
{
3535
var commonIndent = GetCommonIndent(block);
36+
var hasCode = false;
3637
for (var i = 0; i < block.Lines.Count; i++)
3738
{
3839
var line = block.Lines.Lines[i];
3940
var slice = line.Slice;
41+
//ensure we never emit an empty line at beginning or start
42+
if ((i == 0 || i == block.Lines.Count - 1) && line.Slice.IsEmptyOrWhitespace())
43+
continue;
4044
var indent = CountIndentation(slice);
4145
if (indent >= commonIndent)
4246
slice.Start += commonIndent;
47+
48+
if (!hasCode)
49+
{
50+
renderer.Write($"<code class=\"language-{block.Language}\">");
51+
hasCode = true;
52+
}
4353
RenderCodeBlockLine(renderer, block, slice, i);
4454
}
55+
if (hasCode)
56+
renderer.Write($"</code>");
4557
}
4658

4759
private static void RenderCodeBlockLine(HtmlRenderer renderer, EnhancedCodeBlock block, StringSlice slice, int lineNumber)
@@ -102,7 +114,8 @@ protected override void Write(HtmlRenderer renderer, EnhancedCodeBlock block)
102114
{
103115
CrossReferenceName = string.Empty,// block.CrossReferenceName,
104116
Language = block.Language,
105-
Caption = string.Empty
117+
Caption = block.Caption,
118+
ApiCallHeader = block.ApiCallHeader
106119
});
107120

108121
RenderRazorSlice(slice, renderer, block);

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ public override bool Close(BlockProcessor processor, Block block)
7878
: codeBlock.Info
7979
) ?? "unknown";
8080

81+
var language = codeBlock.Language;
82+
codeBlock.Language = language switch
83+
{
84+
"console" => "json",
85+
"console-response" => "json",
86+
"console-result" => "json",
87+
"sh" => "bash",
88+
"yml" => "yaml",
89+
"terminal" => "bash",
90+
_ => codeBlock.Language
91+
};
92+
8193
var lines = codeBlock.Lines;
8294
var callOutIndex = 0;
8395

@@ -86,6 +98,14 @@ public override bool Close(BlockProcessor processor, Block block)
8698
{
8799
originatingLine++;
88100
var line = lines.Lines[index];
101+
if (index == 0 && language == "console")
102+
{
103+
codeBlock.ApiCallHeader = line.ToString();
104+
var s = new StringSlice("");
105+
lines.Lines[index] = new StringLine(ref s);
106+
continue;
107+
}
108+
89109
var span = line.Slice.AsSpan();
90110

91111
if (span.ReplaceSubstitutions(context.FrontMatter?.Properties, out var replacement))

src/Elastic.Markdown/Myst/Directives/DirectiveHtmlRenderer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ private void WriteLiteralIncludeBlock(HtmlRenderer renderer, IncludeBlock block)
213213
{
214214
CrossReferenceName = null,
215215
Language = block.Language,
216-
Caption = null
216+
Caption = null,
217+
ApiCallHeader = null
217218
});
218219
RenderRazorSlice(slice, renderer, content);
219220
}

src/Elastic.Markdown/Slices/Directives/Code.cshtml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
<a class="headerlink" href="@Model.CrossReferenceName" title="Link to this code">¶</a>
99
</div>
1010
}
11-
<pre><code class="[email protected]">[CONTENT]</code></pre>
11+
<pre>
12+
@if (!string.IsNullOrEmpty(Model.ApiCallHeader))
13+
{
14+
<code class="language-apiheader">@Model.ApiCallHeader</code>
15+
}
16+
[CONTENT]
17+
</pre>
1218
</div>
1319
</div>

src/Elastic.Markdown/Slices/Directives/_ViewModels.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class AdmonitionViewModel
1717

1818
public class CodeViewModel
1919
{
20+
public required string? ApiCallHeader { get; init; }
2021
public required string? Caption { get; init; }
2122
public required string Language { get; init; }
2223
public required string? CrossReferenceName { get; init; }

src/Elastic.Markdown/Slices/Layout/_Scripts.cshtml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@
1616

1717
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
1818
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/go.min.js"></script>
19+
1920
<script src="@Model.Static("hljs.js")"></script>
21+
<script src="@Model.Static("custom.js")"></script>
2022
<script src="https://unpkg.com/[email protected]/dist/mermaid.min.js"></script>

src/Elastic.Markdown/_static/custom.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,19 @@ See https://github.com/elastic/docs-builder/issues/219 for further details
205205
.globaltoc a.reference.internal {
206206
display: inline-block;
207207
width: 100%
208+
}
209+
210+
211+
.code-block-caption .caption-text {
212+
color: var(--yue-c-code-text);
213+
font-family: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
214+
line-height: 1.48;
215+
font-size: .96rem;
216+
font-weight: 400;
217+
}
218+
219+
code.language-apiheader:has(+ code) {
220+
padding-bottom: 0.4em;
221+
margin-bottom: 0.4em;
222+
border-bottom: 1px solid #dfdfdf;
208223
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
hljs.registerLanguage('apiheader', function() {
2+
return {
3+
case_insensitive: true, // language is case-insensitive
4+
keywords: 'GET POST PUT DELETE HEAD OPTIONS PATCH',
5+
contains: [
6+
hljs.HASH_COMMENT_MODE,
7+
{
8+
className: "subst", // (pathname: path1/path2/dothis) color #ab5656
9+
begin: /(?<=(?:\/|GET |POST |PUT |DELETE |HEAD |OPTIONS |PATH))[^?\n\r\/]+/,
10+
}
11+
], }
12+
})

0 commit comments

Comments
 (0)