@@ -38,17 +38,30 @@ export function extractRef(repoFullName: string, path: string, matchIndex: numbe
3838 * that `highlightFragment` can map them to the correct terminal lines.
3939 */
4040function recomputeSegments ( fragment : string , regex : RegExp ) : TextMatchSegment [ ] {
41- // Force global flag so exec() advances; strip it first to avoid double-g
42- const re = new RegExp ( regex . source , regex . flags . replace ( "g" , "" ) + "g" ) ;
41+ // Force global flag so exec() advances; strip g and y first to avoid double-g
42+ // and to prevent sticky mode from anchoring every match at lastIndex.
43+ const re = new RegExp ( regex . source , regex . flags . replace ( / [ g y ] / g, "" ) + "g" ) ;
44+ // Precompute newline positions once — O(n) — so per-match line/col lookup
45+ // is O(log n) via binary search instead of O(n) per match (O(n²) overall).
46+ const newlines : number [ ] = [ ] ;
47+ for ( let i = 0 ; i < fragment . length ; i ++ ) {
48+ if ( fragment [ i ] === "\n" ) newlines . push ( i ) ;
49+ }
4350 const segments : TextMatchSegment [ ] = [ ] ;
4451 let m : RegExpExecArray | null ;
4552 while ( ( m = re . exec ( fragment ) ) !== null ) {
4653 const start = m . index ;
4754 const end = start + m [ 0 ] . length ;
48- const before = fragment . slice ( 0 , start ) ;
49- const nlIdx = before . lastIndexOf ( "\n" ) ;
50- const line = ( before . match ( / \n / g) ?. length ?? 0 ) + 1 ;
51- const col = ( nlIdx === - 1 ? start : start - nlIdx - 1 ) + 1 ;
55+ // Binary-search for the number of newlines before `start`.
56+ let lo = 0 ;
57+ let hi = newlines . length ;
58+ while ( lo < hi ) {
59+ const mid = ( lo + hi ) >> 1 ;
60+ if ( newlines [ mid ] < start ) lo = mid + 1 ;
61+ else hi = mid ;
62+ }
63+ const line = lo + 1 ; // 1-based
64+ const col = ( lo === 0 ? start : start - newlines [ lo - 1 ] - 1 ) + 1 ; // 1-based
5265 segments . push ( { text : m [ 0 ] , indices : [ start , end ] , line, col } ) ;
5366 if ( m [ 0 ] . length === 0 ) re . lastIndex ++ ; // guard against zero-width matches
5467 }
0 commit comments