@@ -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 {
@@ -377,15 +394,33 @@ public final actor SemanticIndexManager {
377394 let id = UUID ( )
378395 let task = Task ( priority: priority) {
379396 await withLoggingScope ( " preparation " ) {
380- await self . prepareFileForEditorFunctionality ( uri)
397+ // Should be kept in sync with `prepareFileForEditorFunctionality`
398+ guard let target = await buildSystemManager. canonicalConfiguredTarget ( for: uri) else {
399+ return
400+ }
401+ if Task . isCancelled {
402+ return
403+ }
404+ if inProgressPrepareForEditorTask? . id == id {
405+ if inProgressPrepareForEditorTask? . state != . determiningCanonicalConfiguredTarget {
406+ logger. fault ( " inProgressPrepareForEditorTask is in unexpected state " )
407+ }
408+ inProgressPrepareForEditorTask? . state = . preparingTarget
409+ }
410+ await self . prepare ( targets: [ target] , priority: nil )
381411 if inProgressPrepareForEditorTask? . id == id {
382412 inProgressPrepareForEditorTask = nil
383413 self . indexProgressStatusDidChange ( )
384414 }
385415 }
386416 }
387417 inProgressPrepareForEditorTask? . task. cancel ( )
388- inProgressPrepareForEditorTask = ( id, uri, task)
418+ inProgressPrepareForEditorTask = InProgressPrepareForEditorTask (
419+ id: id,
420+ document: uri,
421+ task: task,
422+ state: . determiningCanonicalConfiguredTarget
423+ )
389424 self . indexProgressStatusDidChange ( )
390425 }
391426
@@ -394,6 +429,7 @@ public final actor SemanticIndexManager {
394429 ///
395430 /// If file's target is known to be up-to-date, this returns almost immediately.
396431 public func prepareFileForEditorFunctionality( _ uri: DocumentURI ) async {
432+ // Should be kept in sync with `schedulePreparationForEditorFunctionality`.
397433 guard let target = await buildSystemManager. canonicalConfiguredTarget ( for: uri) else {
398434 return
399435 }
0 commit comments