Skip to content

Commit 0671361

Browse files
committed
fix(macOS): isolate project tree actions for Swift 6
Button and context-menu closures are not MainActor-isolated under the CI Swift 6 check. Hop back to AppModel from nonisolated action methods instead of marking the helper class itself MainActor.
1 parent dd41066 commit 0671361

1 file changed

Lines changed: 53 additions & 26 deletions

File tree

Sources/Lithe/Views/Workspace/ProjectSidebarView.swift

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -180,29 +180,56 @@ private struct ProjectGitStatusSnapshot: Equatable {
180180
}
181181
}
182182

183-
@MainActor
184-
private final class ProjectTreeActions {
183+
private final class ProjectTreeActions: @unchecked Sendable {
185184
private let model: AppModel
186185

187186
init(model: AppModel) {
188187
self.model = model
189188
}
190189

191-
func openFile(_ url: URL) { model.openFile(url) }
192-
func requestCreateFile(in url: URL) { model.requestCreateFile(in: url) }
193-
func requestCreateDirectory(in url: URL) { model.requestCreateDirectory(in: url) }
194-
func revealInFinder(_ url: URL) { model.revealProjectItemInFinder(url) }
195-
func copyPath(_ url: URL, relative: Bool) { model.copyProjectItemPath(url, relative: relative) }
196-
func duplicate(_ url: URL) async { await model.duplicateProjectItem(at: url) }
197-
func requestRename(_ url: URL) { model.requestRenameProjectItem(at: url) }
198-
func requestDelete(_ url: URL, isDirectory: Bool) {
199-
model.requestDeleteProjectItem(at: url, isDirectory: isDirectory)
200-
}
201-
func refreshWorkspace() async { await model.refreshWorkspace() }
202-
func showGitDirectoryDiff(_ url: URL) async { await model.showGitDirectoryDiff(for: url) }
203-
func selectChange(_ change: GitChange) { model.selectChange(change) }
204-
func showLocalHistory(_ url: URL) { model.showLocalHistory(for: url) }
205-
func javaIconKind(for url: URL) async -> LitheIconKind? { await model.javaIconKind(for: url) }
190+
// Button and context-menu closures are not MainActor-isolated under the
191+
// Swift 6 test/release check. Keep these methods synchronous and hop.
192+
nonisolated func openFile(_ url: URL) {
193+
Task { @MainActor in self.model.openFile(url) }
194+
}
195+
nonisolated func requestCreateFile(_ url: URL) {
196+
Task { @MainActor in self.model.requestCreateFile(in: url) }
197+
}
198+
nonisolated func requestCreateDirectory(_ url: URL) {
199+
Task { @MainActor in self.model.requestCreateDirectory(in: url) }
200+
}
201+
nonisolated func revealInFinder(_ url: URL) {
202+
Task { @MainActor in self.model.revealProjectItemInFinder(url) }
203+
}
204+
nonisolated func copyPath(_ url: URL, relative: Bool) {
205+
Task { @MainActor in self.model.copyProjectItemPath(url, relative: relative) }
206+
}
207+
nonisolated func duplicate(_ url: URL) {
208+
Task { await self.model.duplicateProjectItem(at: url) }
209+
}
210+
nonisolated func requestRename(_ url: URL) {
211+
Task { @MainActor in self.model.requestRenameProjectItem(at: url) }
212+
}
213+
nonisolated func requestDelete(_ url: URL, _ isDirectory: Bool) {
214+
Task { @MainActor in
215+
self.model.requestDeleteProjectItem(at: url, isDirectory: isDirectory)
216+
}
217+
}
218+
nonisolated func refreshWorkspace() {
219+
Task { await self.model.refreshWorkspace() }
220+
}
221+
nonisolated func showGitDirectoryDiff(_ url: URL) {
222+
Task { await self.model.showGitDirectoryDiff(for: url) }
223+
}
224+
nonisolated func selectChange(_ change: GitChange) {
225+
Task { @MainActor in self.model.selectChange(change) }
226+
}
227+
nonisolated func showLocalHistory(_ url: URL) {
228+
Task { @MainActor in self.model.showLocalHistory(for: url) }
229+
}
230+
func javaIconKind(_ url: URL) async -> LitheIconKind? {
231+
await model.javaIconKind(for: url)
232+
}
206233
}
207234

208235
private struct ProjectFileTreeContent: View, Equatable {
@@ -361,24 +388,24 @@ private struct FileNodeRow: View {
361388
.contextMenu { fileContextMenu }
362389
.task(id: node.url.standardizedFileURL.path) {
363390
guard node.url.pathExtension.lowercased() == "java" else { return }
364-
resolvedJavaIconKind = await actions.javaIconKind(for: node.url)
391+
resolvedJavaIconKind = await actions.javaIconKind(node.url)
365392
}
366393
}
367394

368395
@ViewBuilder
369396
private var directoryContextMenu: some View {
370397
if gitStatus.kind(for: node.url, isDirectory: true) != nil {
371398
Button("Show Git Diff") {
372-
Task { await actions.showGitDirectoryDiff(node.url) }
399+
actions.showGitDirectoryDiff(node.url)
373400
}
374401
Divider()
375402
}
376403

377404
Button("New File…") {
378-
actions.requestCreateFile(in: node.url)
405+
actions.requestCreateFile(node.url)
379406
}
380407
Button("New Directory…") {
381-
actions.requestCreateDirectory(in: node.url)
408+
actions.requestCreateDirectory(node.url)
382409
}
383410

384411
Divider()
@@ -397,20 +424,20 @@ private struct FileNodeRow: View {
397424
Divider()
398425

399426
Button("Duplicate") {
400-
Task { await actions.duplicate(node.url) }
427+
actions.duplicate(node.url)
401428
}
402429
Button("Rename…") {
403430
actions.requestRename(node.url)
404431
}
405432
Button("Move to Trash", role: .destructive) {
406-
actions.requestDelete(node.url, isDirectory: true)
433+
actions.requestDelete(node.url, true)
407434
}
408435
}
409436

410437
Divider()
411438

412439
Button("Refresh") {
413-
Task { await actions.refreshWorkspace() }
440+
actions.refreshWorkspace()
414441
}
415442
}
416443

@@ -432,7 +459,7 @@ private struct FileNodeRow: View {
432459

433460
Group {
434461
Button("Duplicate") {
435-
Task { await actions.duplicate(node.url) }
462+
actions.duplicate(node.url)
436463
}
437464
Button("Rename…") {
438465
actions.requestRename(node.url)
@@ -441,7 +468,7 @@ private struct FileNodeRow: View {
441468
actions.showLocalHistory(node.url)
442469
}
443470
Button("Move to Trash", role: .destructive) {
444-
actions.requestDelete(node.url, isDirectory: false)
471+
actions.requestDelete(node.url, false)
445472
}
446473
}
447474

0 commit comments

Comments
 (0)