Skip to content

Commit 9d4bbf2

Browse files
committed
Add ⌘R and ⌘. to Start and Stop Tasks, Add Tasks Menu
1 parent bcd5f11 commit 9d4bbf2

File tree

6 files changed

+88
-16
lines changed

6 files changed

+88
-16
lines changed

CodeEdit/Features/Tasks/TaskManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class TaskManager: ObservableObject {
9393
}
9494
}
9595

96-
func terminateActiveTask() {
96+
func terminateSelectedTask() {
9797
guard let taskID = selectedTaskID else {
9898
return
9999
}

CodeEdit/Features/Tasks/Views/StopTaskToolbarButton.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ struct StopTaskToolbarButton: View {
2424
HStack {
2525
if let currentSelectedStatus, currentSelectedStatus == .running {
2626
Button {
27-
taskManager.terminateActiveTask()
27+
taskManager.terminateSelectedTask()
2828
} label: {
2929
Label("Stop", systemImage: "stop.fill")
3030
.labelStyle(.iconOnly)

CodeEdit/Features/WindowCommands/CodeEditCommands.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct CodeEditCommands: Commands {
1717
ViewCommands()
1818
FindCommands()
1919
NavigateCommands()
20+
TasksCommands()
2021
if sourceControlIsEnabled { SourceControlCommands() }
2122
ExtensionCommands()
2223
WindowCommands()
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//
2+
// TasksCommands.swift
3+
// CodeEdit
4+
//
5+
// Created by Khan Winter on 7/8/25.
6+
//
7+
8+
import SwiftUI
9+
10+
struct TasksCommands: Commands {
11+
@UpdatingWindowController var windowController: CodeEditWindowController?
12+
13+
var taskManager: TaskManager? {
14+
windowController?.workspace?.taskManager
15+
}
16+
17+
var selectedTask: CETask? {
18+
taskManager?.availableTasks.first(where: { $0.id == taskManager?.selectedTaskID })
19+
}
20+
21+
var body: some Commands {
22+
CommandMenu("Tasks") {
23+
let selectedTaskName: String? = if let selectedTask {
24+
"\"" + selectedTask.name + "\""
25+
} else {
26+
nil
27+
}
28+
29+
Button("Run \(selectedTaskName ?? "(No Selected Task)")") {
30+
taskManager?.executeActiveTask()
31+
}
32+
.keyboardShortcut("r", modifiers: .command)
33+
.disabled(taskManager?.selectedTaskID == nil)
34+
35+
Button("Stop \(selectedTaskName ?? "(No Selected Task)")") {
36+
taskManager?.terminateSelectedTask()
37+
}
38+
.keyboardShortcut(".", modifiers: .command)
39+
.disabled(taskManager?.activeTasks.isEmpty == true)
40+
41+
Divider()
42+
43+
Menu {
44+
if let taskManager {
45+
ForEach(taskManager.availableTasks) { task in
46+
Button(task.name) {
47+
taskManager.selectedTaskID = task.id
48+
}
49+
}
50+
}
51+
} label: {
52+
Text("Choose Task...")
53+
}
54+
.disabled(taskManager?.availableTasks.isEmpty == true)
55+
56+
Button("Manage Tasks...") {
57+
NSApp.sendAction(
58+
#selector(CodeEditWindowController.openWorkspaceSettings(_:)),
59+
to: windowController,
60+
from: nil
61+
)
62+
}
63+
.disabled(windowController == nil)
64+
}
65+
}
66+
}

CodeEdit/Features/WindowCommands/Utils/WindowControllerPropertyWrapper.swift

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ struct UpdatingWindowController: DynamicProperty {
3636
class WindowControllerBox: ObservableObject {
3737
public private(set) weak var controller: CodeEditWindowController?
3838

39-
private var objectWillChangeCancellable: AnyCancellable?
40-
private var utilityAreaCancellable: AnyCancellable? // ``ViewCommands`` needs this.
41-
private var windowCancellable: AnyCancellable?
42-
private var activeEditorCancellable: AnyCancellable?
39+
private var windowCancellable: AnyCancellable? // Needs to stick around between window changes.
40+
private var cancellables: Set<AnyCancellable> = []
4341

4442
init() {
4543
windowCancellable = NSApp.publisher(for: \.keyWindow).receive(on: RunLoop.main).sink { [weak self] window in
@@ -50,25 +48,32 @@ struct UpdatingWindowController: DynamicProperty {
5048
}
5149

5250
func setNewController(_ controller: CodeEditWindowController?) {
53-
objectWillChangeCancellable?.cancel()
54-
objectWillChangeCancellable = nil
55-
utilityAreaCancellable?.cancel()
56-
utilityAreaCancellable = nil
57-
activeEditorCancellable?.cancel()
58-
activeEditorCancellable = nil
51+
cancellables.forEach { $0.cancel() }
52+
cancellables.removeAll()
5953

6054
self.controller = controller
6155

62-
objectWillChangeCancellable = controller?.objectWillChange.sink { [weak self] in
56+
controller?.objectWillChange.sink { [weak self] in
6357
self?.objectWillChange.send()
6458
}
65-
utilityAreaCancellable = controller?.workspace?.utilityAreaModel?.objectWillChange.sink { [weak self] in
59+
.store(in: &cancellables)
60+
61+
controller?.workspace?.utilityAreaModel?.objectWillChange.sink { [weak self] in
6662
self?.objectWillChange.send()
6763
}
64+
.store(in: &cancellables)
65+
6866
let activeEditor = controller?.workspace?.editorManager?.activeEditor
69-
activeEditorCancellable = activeEditor?.objectWillChange.sink { [weak self] in
67+
activeEditor?.objectWillChange.sink { [weak self] in
68+
self?.objectWillChange.send()
69+
}
70+
.store(in: &cancellables)
71+
72+
controller?.workspace?.taskManager?.objectWillChange.sink { [weak self] in
7073
self?.objectWillChange.send()
7174
}
75+
.store(in: &cancellables)
76+
7277
self.objectWillChange.send()
7378
}
7479
}

CodeEditTests/Features/Tasks/TaskManagerTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ final class TaskManagerTests: XCTestCase {
5959
let testExpectation1 = XCTestExpectation()
6060
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
6161
XCTAssertEqual(self.taskManager.taskStatus(taskID: task.id), .running)
62-
self.taskManager.terminateActiveTask()
62+
self.taskManager.terminateSelectedTask()
6363
testExpectation1.fulfill()
6464
}
6565

0 commit comments

Comments
 (0)