@@ -23,12 +23,15 @@ export function findSections(text: string, languageId?: string): SectionMatch[]
2323
2424 // For Markdown/Quarto files, find code block ranges to exclude from parsing
2525 const codeBlocks : { start : number ; end : number } [ ] = [ ] ;
26+ let lineStartIndices : number [ ] = [ ] ;
2627 if ( isMarkdownOrQuarto ) {
2728 const lines = text . split ( '\n' ) ;
2829 let inCodeBlock = false ;
2930 let codeBlockStart = 0 ;
30-
31+ let charIndex = 0 ;
32+ lineStartIndices = [ ] ;
3133 lines . forEach ( ( line , index ) => {
34+ lineStartIndices . push ( charIndex ) ;
3235 if ( line . trim ( ) . startsWith ( '```' ) ) {
3336 if ( ! inCodeBlock ) {
3437 inCodeBlock = true ;
@@ -41,6 +44,7 @@ export function findSections(text: string, languageId?: string): SectionMatch[]
4144 } ) ;
4245 }
4346 }
47+ charIndex += line . length + 1 ; // +1 for '\n'
4448 } ) ;
4549 // Edge case: unmatched opening code block at end of file
4650 if ( inCodeBlock ) {
@@ -51,10 +55,18 @@ export function findSections(text: string, languageId?: string): SectionMatch[]
5155 // Helper function to check if a match index is inside a code block
5256 const isInCodeBlock = ( matchIndex : number ) : boolean => {
5357 if ( ! isMarkdownOrQuarto ) return false ;
54-
55- const lines = text . substring ( 0 , matchIndex ) . split ( '\n' ) ;
56- const matchLineNumber = lines . length - 1 ;
57-
58+ // Binary search to find line number for matchIndex
59+ let left = 0 , right = lineStartIndices . length - 1 ;
60+ let matchLineNumber = 0 ;
61+ while ( left <= right ) {
62+ const mid = Math . floor ( ( left + right ) / 2 ) ;
63+ if ( lineStartIndices [ mid ] <= matchIndex ) {
64+ matchLineNumber = mid ;
65+ left = mid + 1 ;
66+ } else {
67+ right = mid - 1 ;
68+ }
69+ }
5870 return codeBlocks . some ( block =>
5971 matchLineNumber >= block . start && matchLineNumber <= block . end
6072 ) ;
0 commit comments