@@ -98,10 +98,6 @@ public enum IndexProgressStatus {
98
98
99
99
/// See `SemanticIndexManager.inProgressPrepareForEditorTask`.
100
100
fileprivate struct InProgressPrepareForEditorTask {
101
- fileprivate enum State {
102
- case determiningCanonicalConfiguredTarget
103
- case preparingTarget
104
- }
105
101
/// A unique ID that identifies the preparation task and is used to set
106
102
/// `SemanticIndexManager.inProgressPrepareForEditorTask` to `nil` when the current in progress task finishes.
107
103
let id : UUID
@@ -111,9 +107,21 @@ fileprivate struct InProgressPrepareForEditorTask {
111
107
112
108
/// The task that prepares the document. Should never be awaited and only be used to cancel the task.
113
109
let task : Task < Void , Never >
110
+ }
111
+
112
+ /// The reason why a target is being prepared. This is used to determine the `IndexProgressStatus`.
113
+ fileprivate enum TargetPreparationPurpose : Comparable {
114
+ /// We are preparing the target so we can index files in it.
115
+ case forIndexing
116
+
117
+ /// We are preparing the target to provide semantic functionality in one of its files.
118
+ case forEditorFunctionality
119
+ }
114
120
115
- /// Whether the task is currently determining the file's target or actually preparing the document.
116
- var state : State
121
+ /// An entry in `SemanticIndexManager.inProgressPreparationTasks`.
122
+ fileprivate struct InProgressPreparationTask {
123
+ let task : OpaqueQueuedIndexTask
124
+ let purpose : TargetPreparationPurpose
117
125
}
118
126
119
127
/// Schedules index tasks and keeps track of the index status of files.
@@ -139,7 +147,7 @@ public final actor SemanticIndexManager {
139
147
/// executing.
140
148
///
141
149
/// After a preparation task finishes, it is removed from this dictionary.
142
- private var inProgressPreparationTasks : [ ConfiguredTarget : OpaqueQueuedIndexTask ] = [ : ]
150
+ private var inProgressPreparationTasks : [ ConfiguredTarget : InProgressPreparationTask ] = [ : ]
143
151
144
152
/// The files that are currently being index, either waiting for their target to be prepared, waiting for the index
145
153
/// store update task to be scheduled in the task scheduler or which currently have an index store update running.
@@ -175,14 +183,14 @@ public final actor SemanticIndexManager {
175
183
176
184
/// A summary of the tasks that this `SemanticIndexManager` has currently scheduled or is currently indexing.
177
185
public var progressStatus : IndexProgressStatus {
178
- if let inProgressPrepareForEditorTask , inProgressPrepareForEditorTask . state == . preparingTarget {
186
+ if inProgressPreparationTasks . values . contains ( where : { $0 . purpose == . forEditorFunctionality } ) {
179
187
return . preparingFileForEditorFunctionality
180
188
}
181
189
if generateBuildGraphTask != nil {
182
190
return . generatingBuildGraph
183
191
}
184
- let preparationTasks = inProgressPreparationTasks. mapValues { queuedTask in
185
- return queuedTask . isExecuting ? IndexTaskStatus . executing : IndexTaskStatus . scheduled
192
+ let preparationTasks = inProgressPreparationTasks. mapValues { inProgressTask in
193
+ return inProgressTask . task . isExecuting ? IndexTaskStatus . executing : IndexTaskStatus . scheduled
186
194
}
187
195
let indexTasks = inProgressIndexTasks. mapValues { status in
188
196
switch status {
@@ -385,38 +393,18 @@ public final actor SemanticIndexManager {
385
393
let id = UUID ( )
386
394
let task = Task ( priority: priority) {
387
395
await withLoggingScope ( " preparation " ) {
388
- defer {
389
- if inProgressPrepareForEditorTask? . id == id {
390
- inProgressPrepareForEditorTask = nil
391
- self . indexProgressStatusDidChange ( )
392
- }
393
- }
394
- // Should be kept in sync with `prepareFileForEditorFunctionality`
395
- guard let target = await buildSystemManager. canonicalConfiguredTarget ( for: uri) else {
396
- return
397
- }
398
- if Task . isCancelled {
399
- return
400
- }
401
- if await preparationUpToDateTracker. isUpToDate ( target) {
402
- // If the target is up-to-date, there is nothing to prepare.
403
- return
404
- }
396
+ await prepareFileForEditorFunctionality ( uri)
405
397
if inProgressPrepareForEditorTask? . id == id {
406
- if inProgressPrepareForEditorTask? . state != . determiningCanonicalConfiguredTarget {
407
- logger. fault ( " inProgressPrepareForEditorTask is in unexpected state " )
408
- }
409
- inProgressPrepareForEditorTask? . state = . preparingTarget
398
+ inProgressPrepareForEditorTask = nil
399
+ self . indexProgressStatusDidChange ( )
410
400
}
411
- await self . prepare ( targets: [ target] , priority: nil )
412
401
}
413
402
}
414
403
inProgressPrepareForEditorTask? . task. cancel ( )
415
404
inProgressPrepareForEditorTask = InProgressPrepareForEditorTask (
416
405
id: id,
417
406
document: uri,
418
- task: task,
419
- state: . determiningCanonicalConfiguredTarget
407
+ task: task
420
408
)
421
409
self . indexProgressStatusDidChange ( )
422
410
}
@@ -433,13 +421,16 @@ public final actor SemanticIndexManager {
433
421
if Task . isCancelled {
434
422
return
435
423
}
436
- await self . prepare ( targets: [ target] , priority: nil )
424
+ if await preparationUpToDateTracker. isUpToDate ( target) {
425
+ // If the target is up-to-date, there is nothing to prepare.
426
+ return
427
+ }
428
+ await self . prepare ( targets: [ target] , purpose: . forEditorFunctionality, priority: nil )
437
429
}
438
430
439
431
// MARK: - Helper functions
440
432
441
- /// Prepare the given targets for indexing.
442
- private func prepare( targets: [ ConfiguredTarget ] , priority: TaskPriority ? ) async {
433
+ private func prepare( targets: [ ConfiguredTarget ] , purpose: TargetPreparationPurpose , priority: TaskPriority ? ) async {
443
434
// Perform a quick initial check whether the target is up-to-date, in which case we don't need to schedule a
444
435
// preparation operation at all.
445
436
// We will check the up-to-date status again in `PreparationTaskDescription.execute`. This ensures that if we
@@ -471,14 +462,25 @@ public final actor SemanticIndexManager {
471
462
return
472
463
}
473
464
for target in targetsToPrepare {
474
- if self . inProgressPreparationTasks [ target] == OpaqueQueuedIndexTask ( task) {
465
+ if self . inProgressPreparationTasks [ target] ? . task == OpaqueQueuedIndexTask ( task) {
475
466
self . inProgressPreparationTasks [ target] = nil
476
467
}
477
468
}
478
469
self . indexProgressStatusDidChange ( )
479
470
}
480
471
for target in targetsToPrepare {
481
- inProgressPreparationTasks [ target] = OpaqueQueuedIndexTask ( preparationTask)
472
+ // If we are preparing the same target for indexing and editor functionality, pick editor functionality as the
473
+ // purpose because it is more significant.
474
+ let mergedPurpose =
475
+ if let existingPurpose = inProgressPreparationTasks [ target] ? . purpose {
476
+ max ( existingPurpose, purpose)
477
+ } else {
478
+ purpose
479
+ }
480
+ inProgressPreparationTasks [ target] = InProgressPreparationTask (
481
+ task: OpaqueQueuedIndexTask ( preparationTask) ,
482
+ purpose: mergedPurpose
483
+ )
482
484
}
483
485
await withTaskCancellationHandler {
484
486
return await preparationTask. waitToFinish ( )
@@ -603,7 +605,7 @@ public final actor SemanticIndexManager {
603
605
let preparationTaskID = UUID ( )
604
606
let indexTask = Task ( priority: priority) {
605
607
// First prepare the targets.
606
- await prepare ( targets: targetsBatch, priority: priority)
608
+ await prepare ( targets: targetsBatch, purpose : . forIndexing , priority: priority)
607
609
608
610
// And after preparation is done, index the files in the targets.
609
611
await withTaskGroup ( of: Void . self) { taskGroup in
0 commit comments