@@ -96,6 +96,26 @@ public enum IndexProgressStatus {
9696 }
9797}
9898
99+ /// See `SemanticIndexManager.inProgressPrepareForEditorTask`.
100+ fileprivate struct InProgressPrepareForEditorTask {
101+ fileprivate enum State {
102+ case determiningCanonicalConfiguredTarget
103+ case preparingTarget
104+ }
105+ /// A unique ID that identifies the preparation task and is used to set
106+ /// `SemanticIndexManager.inProgressPrepareForEditorTask` to `nil` when the current in progress task finishes.
107+ let id : UUID
108+
109+ /// The document that is being prepared.
110+ let document : DocumentURI
111+
112+ /// The task that prepares the document. Should never be awaited and only be used to cancel the task.
113+ let task : Task < Void , Never >
114+
115+ /// Whether the task is currently determining the file's target or actually preparing the document.
116+ var state : State
117+ }
118+
99119/// Schedules index tasks and keeps track of the index status of files.
100120public final actor SemanticIndexManager {
101121 /// The underlying index. This is used to check if the index of a file is already up-to-date, in which case it doesn't
@@ -133,10 +153,7 @@ public final actor SemanticIndexManager {
133153 /// avoid the following scenario: The user browses through documents from targets A, B, and C in quick succession. We
134154 /// don't want stack preparation of A, B, and C. Instead we want to only prepare target C - and also finish
135155 /// preparation of A if it has already started when the user opens C.
136- ///
137- /// `id` is a unique ID that identifies the preparation task and is used to set `inProgressPrepareForEditorTask` to
138- /// `nil` when the current in progress task finishes.
139- private var inProgressPrepareForEditorTask : ( id: UUID , document: DocumentURI , task: Task < Void , Never > ) ? = nil
156+ private var inProgressPrepareForEditorTask : InProgressPrepareForEditorTask ? = nil
140157
141158 /// The `TaskScheduler` that manages the scheduling of index tasks. This is shared among all `SemanticIndexManager`s
142159 /// in the process, to ensure that we don't schedule more index operations than processor cores from multiple
@@ -161,7 +178,7 @@ public final actor SemanticIndexManager {
161178
162179 /// A summary of the tasks that this `SemanticIndexManager` has currently scheduled or is currently indexing.
163180 public var progressStatus : IndexProgressStatus {
164- if inProgressPrepareForEditorTask != nil {
181+ if let inProgressPrepareForEditorTask, inProgressPrepareForEditorTask . state == . preparingTarget {
165182 return . preparingFileForEditorFunctionality
166183 }
167184 if generateBuildGraphTask != nil {
@@ -370,15 +387,33 @@ public final actor SemanticIndexManager {
370387 let id = UUID ( )
371388 let task = Task ( priority: priority) {
372389 await withLoggingScope ( " preparation " ) {
373- await self . prepareFileForEditorFunctionality ( uri)
390+ // Should be kept in sync with `prepareFileForEditorFunctionality`
391+ guard let target = await buildSystemManager. canonicalConfiguredTarget ( for: uri) else {
392+ return
393+ }
394+ if Task . isCancelled {
395+ return
396+ }
397+ if inProgressPrepareForEditorTask? . id == id {
398+ if inProgressPrepareForEditorTask? . state != . determiningCanonicalConfiguredTarget {
399+ logger. fault ( " inProgressPrepareForEditorTask is in unexpected state " )
400+ }
401+ inProgressPrepareForEditorTask? . state = . preparingTarget
402+ }
403+ await self . prepare ( targets: [ target] , priority: nil )
374404 if inProgressPrepareForEditorTask? . id == id {
375405 inProgressPrepareForEditorTask = nil
376406 self . indexProgressStatusDidChange ( )
377407 }
378408 }
379409 }
380410 inProgressPrepareForEditorTask? . task. cancel ( )
381- inProgressPrepareForEditorTask = ( id, uri, task)
411+ inProgressPrepareForEditorTask = InProgressPrepareForEditorTask (
412+ id: id,
413+ document: uri,
414+ task: task,
415+ state: . determiningCanonicalConfiguredTarget
416+ )
382417 self . indexProgressStatusDidChange ( )
383418 }
384419
@@ -387,6 +422,7 @@ public final actor SemanticIndexManager {
387422 ///
388423 /// If file's target is known to be up-to-date, this returns almost immediately.
389424 public func prepareFileForEditorFunctionality( _ uri: DocumentURI ) async {
425+ // Should be kept in sync with `schedulePreparationForEditorFunctionality`.
390426 guard let target = await buildSystemManager. canonicalConfiguredTarget ( for: uri) else {
391427 return
392428 }
0 commit comments