@@ -98,39 +98,48 @@ public override bool Close(BlockProcessor processor, Block block)
9898 if ( codeBlock . OpeningFencedCharCount > 3 )
9999 continue ;
100100
101- if ( span . IndexOf ( "<" ) < 0 && span . IndexOf ( "//" ) < 0 )
102- continue ;
103-
104- CallOut ? callOut = null ;
101+ List < CallOut > callOuts = [ ] ;
105102
106- if ( span . IndexOf ( "<" ) > 0 )
103+ var hasClassicCallout = span . IndexOf ( "<" ) > 0 ;
104+ if ( hasClassicCallout )
107105 {
108106 var matchClassicCallout = CallOutParser . CallOutNumber ( ) . EnumerateMatches ( span ) ;
109- callOut = EnumerateAnnotations ( matchClassicCallout , ref span , ref callOutIndex , originatingLine , false ) ;
107+ callOuts . AddRange (
108+ EnumerateAnnotations ( matchClassicCallout , ref span , ref callOutIndex , originatingLine , false )
109+ ) ;
110110 }
111111
112112 // only support magic callouts for smaller line lengths
113- if ( callOut is null && span . Length < 200 )
113+ if ( callOuts . Count == 0 && span . Length < 200 )
114114 {
115115 var matchInline = CallOutParser . MathInlineAnnotation ( ) . EnumerateMatches ( span ) ;
116- callOut = EnumerateAnnotations ( matchInline , ref span , ref callOutIndex , originatingLine ,
117- true ) ;
116+ callOuts . AddRange (
117+ EnumerateAnnotations ( matchInline , ref span , ref callOutIndex , originatingLine , true )
118+ ) ;
118119 }
119120
120- if ( callOut is null )
121+ if ( callOuts . Count == 0 )
121122 continue ;
122123
123124 codeBlock . CallOuts ??= [ ] ;
124- codeBlock . CallOuts . Add ( callOut ) ;
125+ codeBlock . CallOuts . AddRange ( callOuts ) ;
125126 }
126127
127128 //update string slices to ignore call outs
128- if ( codeBlock . CallOuts is not null )
129+ if ( codeBlock . CallOuts ? . Count > 0 )
129130 {
130- foreach ( var callout in codeBlock . CallOuts )
131+
132+ var callouts = codeBlock . CallOuts . Aggregate ( new Dictionary < int , CallOut > ( ) , ( acc , curr ) =>
131133 {
132- var line = lines . Lines [ callout . Line - 1 ] ;
134+ if ( acc . TryAdd ( curr . Line , curr ) ) return acc ;
135+ if ( acc [ curr . Line ] . SliceStart > curr . SliceStart )
136+ acc [ curr . Line ] = curr ;
137+ return acc ;
138+ } ) ;
133139
140+ foreach ( var callout in callouts . Values )
141+ {
142+ var line = lines . Lines [ callout . Line - 1 ] ;
134143 var newSpan = line . Slice . AsSpan ( ) [ ..callout . SliceStart ] ;
135144 var s = new StringSlice ( newSpan . ToString ( ) ) ;
136145 lines . Lines [ callout . Line - 1 ] = new StringLine ( ref s ) ;
@@ -149,44 +158,79 @@ public override bool Close(BlockProcessor processor, Block block)
149158 return base . Close ( processor , block ) ;
150159 }
151160
152- private static CallOut ? EnumerateAnnotations ( Regex . ValueMatchEnumerator matches ,
161+ private static List < CallOut > EnumerateAnnotations ( Regex . ValueMatchEnumerator matches ,
153162 ref ReadOnlySpan < char > span ,
154163 ref int callOutIndex ,
155164 int originatingLine ,
156165 bool inlineCodeAnnotation )
157166 {
167+ var callOuts = new List < CallOut > ( ) ;
158168 foreach ( var match in matches )
159169 {
160170 if ( match . Length == 0 )
161171 continue ;
162172
163- var startIndex = span . LastIndexOf ( "<" ) ;
164- if ( ! inlineCodeAnnotation && startIndex <= 0 )
165- continue ;
166173 if ( inlineCodeAnnotation )
167174 {
168- startIndex = Math . Max ( span . LastIndexOf ( "//" ) , span . LastIndexOf ( '#' ) ) ;
169- if ( startIndex <= 0 )
170- continue ;
175+ var callOut = ParseMagicCallout ( match , ref span , ref callOutIndex , originatingLine ) ;
176+ if ( callOut != null )
177+ return [ callOut ] ;
178+ continue ;
171179 }
172180
173- callOutIndex ++ ;
174- var callout = span . Slice ( match . Index + startIndex , match . Length - startIndex ) ;
175- var index = callOutIndex ;
176- if ( ! inlineCodeAnnotation && int . TryParse ( callout . Trim ( [ '<' , '>' ] ) , out index ) )
177- {
181+ var classicCallOuts = ParseClassicCallOuts ( match , ref span , ref callOutIndex , originatingLine ) ;
182+ callOuts . AddRange ( classicCallOuts ) ;
183+ }
178184
179- }
180- return new CallOut
185+ return callOuts ;
186+ }
187+
188+ private static CallOut ? ParseMagicCallout ( ValueMatch match , ref ReadOnlySpan < char > span , ref int callOutIndex , int originatingLine )
189+ {
190+ var startIndex = Math . Max ( span . LastIndexOf ( "//" ) , span . LastIndexOf ( '#' ) ) ;
191+ if ( startIndex <= 0 )
192+ return null ;
193+
194+ callOutIndex ++ ;
195+ var callout = span . Slice ( match . Index + startIndex , match . Length - startIndex ) ;
196+
197+ return new CallOut
198+ {
199+ Index = callOutIndex ,
200+ Text = callout . TrimStart ( '/' ) . TrimStart ( '#' ) . TrimStart ( ) . ToString ( ) ,
201+ InlineCodeAnnotation = true ,
202+ SliceStart = startIndex ,
203+ Line = originatingLine ,
204+ } ;
205+ }
206+
207+ private static List < CallOut > ParseClassicCallOuts ( ValueMatch match , ref ReadOnlySpan < char > span , ref int callOutIndex , int originatingLine )
208+ {
209+ var startIndex = span . LastIndexOf ( "<" ) ;
210+ if ( startIndex <= 0 )
211+ return [ ] ;
212+ var allStartIndices = new List < int > ( ) ;
213+ for ( var i = 0 ; i < span . Length ; i ++ )
214+ {
215+ if ( span [ i ] == '<' )
216+ allStartIndices . Add ( i ) ;
217+ }
218+ var callOuts = new List < CallOut > ( ) ;
219+ foreach ( var individualStartIndex in allStartIndices )
220+ {
221+ callOutIndex ++ ;
222+ var endIndex = span . Slice ( match . Index + individualStartIndex ) . IndexOf ( '>' ) + 1 ;
223+ var callout = span . Slice ( match . Index + individualStartIndex , endIndex ) ;
224+ _ = int . TryParse ( callout . Trim ( [ '<' , '>' ] ) , out var index ) ;
225+ callOuts . Add ( new CallOut
181226 {
182227 Index = index ,
183228 Text = callout . TrimStart ( '/' ) . TrimStart ( '#' ) . TrimStart ( ) . ToString ( ) ,
184- InlineCodeAnnotation = inlineCodeAnnotation ,
185- SliceStart = startIndex ,
229+ InlineCodeAnnotation = false ,
230+ SliceStart = individualStartIndex ,
186231 Line = originatingLine ,
187- } ;
232+ } ) ;
188233 }
189-
190- return null ;
234+ return callOuts ;
191235 }
192236}
0 commit comments