55using Elastic . Markdown . Diagnostics ;
66using Elastic . Markdown . Myst . Directives ;
77using Elastic . Markdown . Slices . Directives ;
8+ using Markdig . Helpers ;
89using Markdig . Renderers ;
910using Markdig . Renderers . Html ;
1011using Markdig . Syntax ;
@@ -14,15 +15,85 @@ namespace Elastic.Markdown.Myst.CodeBlocks;
1415
1516public 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 ;
0 commit comments