Skip to content

Commit e011829

Browse files
authored
Merge pull request #1379 from ahoppen/no-prepare-for-editor-task-while-determining-target
Don’t show a “Preparing current file” progress while determining target of file
2 parents 6206d2a + 01e8858 commit e011829

File tree

2 files changed

+62
-7
lines changed

2 files changed

+62
-7
lines changed

Sources/SemanticIndex/SemanticIndexManager.swift

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
100120
public 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
}

Tests/SourceKitLSPTests/BackgroundIndexingTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,4 +868,23 @@ final class BackgroundIndexingTests: XCTestCase {
868868
let message = try await project.testClient.nextNotification(ofType: ShowMessageNotification.self)
869869
XCTAssert(message.message.contains("Background indexing"), "Received unexpected message: \(message.message)")
870870
}
871+
872+
func testNoPreparationStatusIfTargetIsUpToDate() async throws {
873+
let project = try await SwiftPMTestProject(
874+
files: [
875+
"Lib.swift": ""
876+
],
877+
capabilities: ClientCapabilities(window: WindowClientCapabilities(workDoneProgress: true)),
878+
enableBackgroundIndexing: true
879+
)
880+
881+
// Opening the document prepares it for editor functionality. Its target is already prepared, so we shouldn't show
882+
// a work done progress for it.
883+
project.testClient.handleSingleRequest { (request: CreateWorkDoneProgressRequest) in
884+
XCTFail("Received unexpected create work done progress: \(request)")
885+
return VoidResponse()
886+
}
887+
_ = try project.openDocument("Lib.swift")
888+
_ = try await project.testClient.send(BarrierRequest())
889+
}
871890
}

0 commit comments

Comments
 (0)