Skip to content

Commit b2b4909

Browse files
authored
Run Tasks (#1798)
### Description This PR introduces the ability to run tasks within CodeEdit, utilizing a `.codeedit` folder to store task configurations. The goal is to enable users to create and manage tasks quickly and easily. #### Simple Tasks Example: ```json { "tasks" : [ { "command" : "go build", "name" : "build", } ] } ``` #### Tasks with Environment Variables: ```json "tasks" : [ { "environmentVariables" : { "database" : "maps" }, "target" : "Docker", "name" : "build", "command" : "go build", "workingDirectory" : "\/Users\/tommyludwig\/ScratchFolder\/task-tests" } ], ``` #### Key Structures Introduced: - `CETask`: Configuration for executing a task, including command and environment settings. - `CEActiveTask`: Represents a running task with output and status (running, stopped, failed, succeeded). CETask is injected into CEActiveTask with essential information such as full command and environment variables. - `CETaskManager`: Handles active tasks (run, renew, suspend, resume, terminate, interrupt). - `CEWorkspaceSettings`: Holds workspace-specific settings data. Distinct from CEWorkspaceSettingsManager, which handles workspace settings management (e.g., saving, loading). #### Active Task States: An active task can be: - `notRunning`: The task hasn't been interacted with yet. - `stopped`: The task is currently suspended(paused). - `running`: The task is actively running. - `failed`: The task finished with an error code. - `finished`: The task successfully completed. #### Task Shell Options: TaskShell provides various shells (e.g., bash, zsh, csh) for executing commands. Currently defaults to bash; future updates may include user settings for shell preference. Tasks are executed using `executeCommandWithShell`, utilizing a Swift `Process` to run commands within the user's environment plus additional variables from `CETask`. Output (`stdout` and stderr`) is captured using a `Pipe`. > [!IMPORTANT] > Reviewers, please pay close attention to the usage of classes vs. structs, as well as the naming conventions for classes, functions, and variables. Clear naming decisions now will save significant effort later. ### Related Issues * closes #262 * closes #699 ### Checklist - [x] I read and understood the [contributing guide](https://github.com/CodeEditApp/CodeEdit/blob/main/CONTRIBUTING.md) as well as the [code of conduct](https://github.com/CodeEditApp/CodeEdit/blob/main/CODE_OF_CONDUCT.md) - [x] The issues this PR addresses are related to each other - [x] My changes generate no new warnings - [x] My code builds and runs on my machine - [x] My changes are all related to the related issue above - [x] I documented my code ### Screenshots <img width="1581" alt="Screenshot 2024-07-05 at 4 00 06 PM" src="https://github.com/CodeEditApp/CodeEdit/assets/83090745/8d303d9a-8d59-427e-979c-49a77471dc87"> <img width="1183" alt="Screenshot 2024-07-05 at 3 59 49 PM" src="https://github.com/CodeEditApp/CodeEdit/assets/83090745/a28e9ebd-3e07-4d15-a1fa-076808dcfd03"> <img width="1181" alt="Screenshot 2024-07-05 at 3 59 19 PM" src="https://github.com/CodeEditApp/CodeEdit/assets/83090745/52e49fc0-8907-4ed8-a875-cbf6b5239b07"> <img width="277" alt="Screenshot 2024-07-05 at 3 59 04 PM" src="https://github.com/CodeEditApp/CodeEdit/assets/83090745/2da86c33-180c-4f8a-8a64-ed80abd6deec">
1 parent 00653f3 commit b2b4909

File tree

54 files changed

+2297
-858
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2297
-858
lines changed

CodeEdit.xcodeproj/project.pbxproj

Lines changed: 165 additions & 75 deletions
Large diffs are not rendered by default.

CodeEdit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CodeEdit/Features/ActivityViewer/ActivityViewer.swift

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,33 @@ struct ActivityViewer: View {
1212
@Environment(\.colorScheme)
1313
var colorScheme
1414

15+
var workspaceFileManager: CEWorkspaceFileManager?
16+
1517
@ObservedObject var taskNotificationHandler: TaskNotificationHandler
18+
@ObservedObject var workspaceSettingsManager: CEWorkspaceSettings
19+
20+
// TODO: try to get this from the envrionment
21+
@ObservedObject var taskManager: TaskManager
1622

23+
init(
24+
workspaceFileManager: CEWorkspaceFileManager?,
25+
workspaceSettingsManager: CEWorkspaceSettings,
26+
taskNotificationHandler: TaskNotificationHandler,
27+
taskManager: TaskManager
28+
) {
29+
self.workspaceFileManager = workspaceFileManager
30+
self.workspaceSettingsManager = workspaceSettingsManager
31+
self.taskNotificationHandler = taskNotificationHandler
32+
self.taskManager = taskManager
33+
}
1734
var body: some View {
1835
HStack(spacing: 0) {
19-
// This is only a placeholder for the task popover(coming in the next pr)
20-
Rectangle()
21-
.frame(height: 22)
22-
.hidden()
23-
.fixedSize()
36+
SchemeDropDownView(
37+
workspaceSettingsManager: workspaceSettingsManager,
38+
workspaceFileManager: workspaceFileManager
39+
)
40+
41+
TaskDropDownView(taskManager: taskManager)
2442

2543
Spacer(minLength: 0)
2644

@@ -30,8 +48,13 @@ struct ActivityViewer: View {
3048
.fixedSize(horizontal: false, vertical: false)
3149
.padding(.horizontal, 10)
3250
.background {
33-
RoundedRectangle(cornerRadius: 5)
34-
.opacity(0.1)
51+
if colorScheme == .dark {
52+
RoundedRectangle(cornerRadius: 5)
53+
.opacity(0.10)
54+
} else {
55+
RoundedRectangle(cornerRadius: 5)
56+
.opacity(0.1)
57+
}
3558
}
3659
}
3760
}

CodeEdit/Features/ActivityViewer/TaskNotificationView.swift renamed to CodeEdit/Features/ActivityViewer/Notificaitons/TaskNotificationView.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ struct TaskNotificationView: View {
2828
} else {
2929
if taskNotificationHandler.notifications.count > 1 {
3030
Text("\(taskNotificationHandler.notifications.count)")
31+
.font(.caption)
32+
.padding(5)
3133
.background(
3234
Circle()
3335
.foregroundStyle(.gray)
36+
.opacity(0.3)
3437
)
38+
.padding(-5)
3539
}
3640
}
3741
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// DropdownMenuItemStyleModifier.swift
3+
// CodeEdit
4+
//
5+
// Created by Tommy Ludwig on 24.06.24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct DropdownMenuItemStyleModifier: ViewModifier {
11+
@State private var isHovering = false
12+
13+
func body(content: Content) -> some View {
14+
content
15+
.background(isHovering ? Color(NSColor.systemBlue) : .clear)
16+
.foregroundColor(isHovering ? Color(NSColor.white) : .primary)
17+
.onHover(perform: { hovering in
18+
self.isHovering = hovering
19+
})
20+
}
21+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//
2+
// OptionMenuItemView.swift
3+
// CodeEdit
4+
//
5+
// Created by Tommy Ludwig on 24.06.24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct OptionMenuItemView: View {
11+
var label: String
12+
var action: () -> Void
13+
var body: some View {
14+
HStack {
15+
Text(label)
16+
Spacer()
17+
}
18+
.padding(.vertical, 5)
19+
.padding(.horizontal, 28)
20+
.modifier(DropdownMenuItemStyleModifier())
21+
.clipShape(RoundedRectangle(cornerRadius: 5))
22+
.onTapGesture {
23+
action()
24+
}
25+
}
26+
}
27+
28+
#Preview {
29+
OptionMenuItemView(label: "Tst") {
30+
print("test")
31+
}
32+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//
2+
// SchemeDropDownView.swift
3+
// CodeEdit
4+
//
5+
// Created by Tommy Ludwig on 24.06.24.
6+
//
7+
8+
import SwiftUI
9+
10+
struct SchemeDropDownView: View {
11+
@Environment(\.colorScheme)
12+
private var colorScheme
13+
14+
@State var isSchemePopOverPresented: Bool = false
15+
@State private var isHoveringScheme: Bool = false
16+
17+
@ObservedObject var workspaceSettingsManager: CEWorkspaceSettings
18+
var workspaceFileManager: CEWorkspaceFileManager?
19+
20+
var body: some View {
21+
HStack(spacing: 5) {
22+
Image(systemName: "folder.badge.gearshape")
23+
.imageScale(.medium)
24+
25+
Group {
26+
if workspaceSettingsManager.settings.project.projectName.isEmpty {
27+
Text(workspaceFileManager?.workspaceItem.fileName() ?? "No Project found")
28+
} else {
29+
Text(workspaceSettingsManager.settings.project.projectName)
30+
}
31+
}.font(.subheadline)
32+
}
33+
.font(.caption)
34+
.padding(.trailing, 9)
35+
.padding(5)
36+
.background {
37+
Color(nsColor: colorScheme == .dark ? .white : .black)
38+
.opacity(isHoveringScheme || isSchemePopOverPresented ? 0.05 : 0)
39+
.clipShape(RoundedRectangle(cornerSize: CGSize(width: 4, height: 4)))
40+
HStack {
41+
Spacer()
42+
if isHoveringScheme || isSchemePopOverPresented {
43+
chevronDown
44+
.padding(.trailing, 3)
45+
} else {
46+
chevron
47+
.padding(.trailing, 3)
48+
}
49+
}
50+
}
51+
.onHover(perform: { hovering in
52+
self.isHoveringScheme = hovering
53+
})
54+
.popover(isPresented: $isSchemePopOverPresented, arrowEdge: .bottom) {
55+
VStack(alignment: .leading, spacing: 0) {
56+
WorkspaceMenuItemView(
57+
workspaceFileManager: workspaceFileManager,
58+
item: workspaceFileManager?.workspaceItem
59+
)
60+
61+
Divider()
62+
.padding(.vertical, 5)
63+
Group {
64+
OptionMenuItemView(label: "Add Folder..") {
65+
// TODO: Implment Add Folder
66+
print("NOT IMPLMENTED")
67+
}
68+
OptionMenuItemView(label: "Workspace Settings...") {
69+
NSApp.sendAction(
70+
#selector(CodeEditWindowController.openWorkspaceSettings(_:)), to: nil, from: nil
71+
)
72+
}
73+
}
74+
}
75+
.padding(5)
76+
}.onTapGesture {
77+
self.isSchemePopOverPresented.toggle()
78+
}
79+
}
80+
81+
private var chevron: some View {
82+
Image(systemName: "chevron.compact.right")
83+
.font(.system(size: 9, weight: .medium, design: .default))
84+
.foregroundStyle(.secondary)
85+
.scaleEffect(x: 1.30, y: 1.0, anchor: .center)
86+
.imageScale(.large)
87+
}
88+
89+
private var chevronDown: some View {
90+
VStack(spacing: 1) {
91+
Image(systemName: "chevron.down")
92+
}
93+
.font(.system(size: 8, weight: .bold, design: .default))
94+
.padding(.top, 0.5)
95+
}
96+
}
97+
98+
// #Preview {
99+
// SchemeDropDownMenuView()
100+
// }

0 commit comments

Comments
 (0)