@@ -3239,9 +3239,36 @@ function handleMinimapClick(event: MouseEvent): void {
32393239
32403240 // Map click position to line number
32413241 const totalLines = getTotalLines ( ) ;
3242- const targetLine = Math . floor ( ( clickY / minimapHeight ) * totalLines ) ;
3243- const targetScrollTop = lineToScrollTop ( targetLine ) ;
3242+ const proportionalLine = Math . floor ( ( clickY / minimapHeight ) * totalLines ) ;
3243+
3244+ // Snap to nearest search result if clicking near one (within ~3 buckets / ~6px)
3245+ let targetLine = proportionalLine ;
3246+ if ( state . searchResults . length > 0 ) {
3247+ const SNAP_RADIUS_LINES = Math . max ( 50 , Math . floor ( ( 6 / minimapHeight ) * totalLines ) ) ;
3248+ let nearestResult : typeof state . searchResults [ 0 ] | null = null ;
3249+ let nearestDist = Infinity ;
3250+ for ( const r of state . searchResults ) {
3251+ const pos = state . isFiltered && r . displayIndex != null ? r . displayIndex : r . lineNumber ;
3252+ const dist = Math . abs ( pos - proportionalLine ) ;
3253+ if ( dist < nearestDist ) {
3254+ nearestDist = dist ;
3255+ nearestResult = r ;
3256+ }
3257+ }
3258+ if ( nearestResult && nearestDist <= SNAP_RADIUS_LINES ) {
3259+ targetLine = state . isFiltered && nearestResult . displayIndex != null
3260+ ? nearestResult . displayIndex : nearestResult . lineNumber ;
3261+ // Update current search index too
3262+ const idx = state . searchResults . indexOf ( nearestResult ) ;
3263+ if ( idx >= 0 ) {
3264+ state . currentSearchIndex = idx ;
3265+ updateSearchUI ( ) ;
3266+ updateSearchResultsCurrent ( ) ;
3267+ }
3268+ }
3269+ }
32443270
3271+ const targetScrollTop = lineToScrollTop ( targetLine ) ;
32453272 logViewerElement . scrollTop = Math . max ( 0 , targetScrollTop ) ;
32463273}
32473274
@@ -3458,17 +3485,28 @@ function renderMinimapMarkers(): void {
34583485 fragment . appendChild ( marker ) ;
34593486 }
34603487
3461- // Add search result markers (limit to prevent performance issues)
3462- const maxSearchMarkers = 100 ;
3463- const searchStep = Math . max ( 1 , Math . floor ( state . searchResults . length / maxSearchMarkers ) ) ;
3464- for ( let i = 0 ; i < state . searchResults . length ; i += searchStep ) {
3465- const result = state . searchResults [ i ] ;
3466- const marker = document . createElement ( 'div' ) ;
3467- marker . className = 'minimap-search-marker' ;
3468- const markerPos = state . isFiltered && result . displayIndex != null
3469- ? result . displayIndex : result . lineNumber ;
3470- marker . style . top = `${ ( markerPos / totalLines ) * minimapHeight } px` ;
3471- fragment . appendChild ( marker ) ;
3488+ // Add search result markers — bucket aggregation to show ALL matches accurately
3489+ if ( state . searchResults . length > 0 ) {
3490+ const SEARCH_BUCKETS = Math . max ( 50 , Math . floor ( minimapHeight / 2 ) ) ;
3491+ const buckets = new Uint32Array ( SEARCH_BUCKETS ) ;
3492+ let maxBucket = 0 ;
3493+ for ( const result of state . searchResults ) {
3494+ const markerPos = state . isFiltered && result . displayIndex != null
3495+ ? result . displayIndex : result . lineNumber ;
3496+ const idx = Math . min ( SEARCH_BUCKETS - 1 , Math . floor ( ( markerPos / totalLines ) * SEARCH_BUCKETS ) ) ;
3497+ buckets [ idx ] ++ ;
3498+ if ( buckets [ idx ] > maxBucket ) maxBucket = buckets [ idx ] ;
3499+ }
3500+ const bucketHeight = minimapHeight / SEARCH_BUCKETS ;
3501+ for ( let i = 0 ; i < SEARCH_BUCKETS ; i ++ ) {
3502+ if ( buckets [ i ] === 0 ) continue ;
3503+ const intensity = Math . min ( 1 , 0.4 + ( buckets [ i ] / maxBucket ) * 0.6 ) ;
3504+ const marker = document . createElement ( 'div' ) ;
3505+ marker . className = 'minimap-search-marker' ;
3506+ marker . style . cssText = `position:absolute;left:0;right:0;top:${ i * bucketHeight } px;height:${ Math . max ( 2 , Math . ceil ( bucketHeight ) ) } px;background-color:rgba(255,255,0,${ intensity } );` ;
3507+ marker . title = `${ buckets [ i ] } match${ buckets [ i ] !== 1 ? 'es' : '' } ` ;
3508+ fragment . appendChild ( marker ) ;
3509+ }
34723510 }
34733511
34743512 // Add search config markers (colored by config)
0 commit comments