Allow multiple concurrent reference searches (#33739)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: 403d4f5900a8c4ccdc64032d365adb285a191b71
This commit is contained in:
Alf Eaton
2026-05-19 12:25:40 +01:00
committed by Copybot
parent c0acddbfaf
commit d8c33cc34c
3 changed files with 21 additions and 13 deletions
@@ -194,7 +194,7 @@ export const ReferencesProvider: FC<React.PropsWithChildren> = ({
return { hits: [] }
}
const indexer = await indexerRef.current
return await indexer.search(query)
return await indexer.search(query, 'searchLocalReferences')
},
[]
)
@@ -3,6 +3,7 @@ import { generateSHA1Hash } from '@/shared/utils/sha1'
import { AdvancedReferenceSearchResult, Changes } from './types'
import { debugConsole } from '@/utils/debugging'
import type { ReferenceWorkerResponse } from './references.worker'
import { v4 as uuid } from 'uuid'
const ONE_MB = 1024 * 1024
const MAX_BIB_DATA_SIZE = 6 * ONE_MB
@@ -11,9 +12,10 @@ export class ReferenceIndexer {
private fileIndexHash: Map<string, string> = new Map()
private worker: Worker
private updateResolve: ((result: Set<string>) => void) | null = null
private searchResolve:
| ((result: AdvancedReferenceSearchResult) => void)
| null = null
private searchResolvers = new Map<
string,
(result: AdvancedReferenceSearchResult) => void
>()
constructor() {
this.worker = new Worker(
@@ -26,9 +28,12 @@ export class ReferenceIndexer {
private handleMessage(event: MessageEvent) {
const data = event.data as ReferenceWorkerResponse
if (data.type === 'searchResult' && this.searchResolve) {
this.searchResolve(data.result)
this.searchResolve = null
if (data.type === 'searchResult') {
const searchResolver = this.searchResolvers.get(data.id)
if (searchResolver) {
searchResolver(data.result)
this.searchResolvers.delete(data.id)
}
} else if (data.type === 'updateKeys' && this.updateResolve) {
this.updateResolve(data.keys)
this.updateResolve = null
@@ -127,11 +132,14 @@ export class ReferenceIndexer {
})
}
async search(query: string): Promise<AdvancedReferenceSearchResult> {
this.worker.postMessage({ type: 'search', query })
async search(
query: string,
id: string = uuid()
): Promise<AdvancedReferenceSearchResult> {
this.worker.postMessage({ id, type: 'search', query })
const { promise, resolve } =
Promise.withResolvers<AdvancedReferenceSearchResult>()
this.searchResolve = resolve
this.searchResolvers.set(id, resolve)
return promise
}
}
@@ -14,11 +14,11 @@ const indices = importOverleafModules('referenceIndices') as {
export type ReferenceWorkerRequest =
| { type: 'update'; changes: Changes }
| { type: 'search'; query: string }
| { id: string; type: 'search'; query: string }
export type ReferenceWorkerResponse =
| { type: 'updateKeys'; keys: Set<string> }
| { type: 'searchResult'; result: AdvancedReferenceSearchResult }
| { id: string; type: 'searchResult'; result: AdvancedReferenceSearchResult }
function createIndex(): ReferenceIndex {
const Klass = indices[0]?.import.default ?? BasicReferenceIndex
@@ -37,7 +37,7 @@ self.addEventListener('message', async (event: MessageEvent) => {
case 'search': {
const result = await indexer.search(message.query)
self.postMessage({ type: 'searchResult', result })
self.postMessage({ id: message.id, type: 'searchResult', result })
break
}