diff --git a/CodeEdit/Assets.xcassets/custom.breakpoint.fill.symbolset/Contents.json b/CodeEdit/Assets.xcassets/custom.breakpoint.fill.symbolset/Contents.json
new file mode 100644
index 0000000000..970b1de6de
--- /dev/null
+++ b/CodeEdit/Assets.xcassets/custom.breakpoint.fill.symbolset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "symbols" : [
+ {
+ "filename" : "custom.breakpoint.fill.svg",
+ "idiom" : "universal"
+ }
+ ]
+}
diff --git a/CodeEdit/Assets.xcassets/custom.breakpoint.fill.symbolset/custom.breakpoint.fill.svg b/CodeEdit/Assets.xcassets/custom.breakpoint.fill.symbolset/custom.breakpoint.fill.svg
new file mode 100644
index 0000000000..59e8ba76fc
--- /dev/null
+++ b/CodeEdit/Assets.xcassets/custom.breakpoint.fill.symbolset/custom.breakpoint.fill.svg
@@ -0,0 +1,167 @@
+
+
+
+
diff --git a/CodeEdit/Assets.xcassets/custom.breakpoint.symbolset/Contents.json b/CodeEdit/Assets.xcassets/custom.breakpoint.symbolset/Contents.json
new file mode 100644
index 0000000000..b55d72d295
--- /dev/null
+++ b/CodeEdit/Assets.xcassets/custom.breakpoint.symbolset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "symbols" : [
+ {
+ "filename" : "custom.breakpoint.svg",
+ "idiom" : "universal"
+ }
+ ]
+}
diff --git a/CodeEdit/Assets.xcassets/custom.breakpoint.symbolset/custom.breakpoint.svg b/CodeEdit/Assets.xcassets/custom.breakpoint.symbolset/custom.breakpoint.svg
new file mode 100644
index 0000000000..51d6528a95
--- /dev/null
+++ b/CodeEdit/Assets.xcassets/custom.breakpoint.symbolset/custom.breakpoint.svg
@@ -0,0 +1,167 @@
+
+
+
+
diff --git a/CodeEdit/Documents/WorkspaceDocument.swift b/CodeEdit/Documents/WorkspaceDocument.swift
index fa4813d302..f0e8b160ea 100644
--- a/CodeEdit/Documents/WorkspaceDocument.swift
+++ b/CodeEdit/Documents/WorkspaceDocument.swift
@@ -15,6 +15,7 @@ import Search
import QuickOpen
import CodeEditKit
import ExtensionsStore
+import StatusBar
@objc(WorkspaceDocument)
final class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate {
@@ -25,6 +26,7 @@ final class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate {
@Published var sortFoldersOnTop: Bool = true
@Published var selectionState: WorkspaceSelectionState = .init()
+ var statusBarModel: StatusBarModel?
var searchState: SearchState?
var quickOpenState: QuickOpenState?
private var cancellables = Set()
@@ -124,7 +126,7 @@ final class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate {
self.addWindowController(windowController)
}
- override func read(from url: URL, ofType typeName: String) throws {
+ private func initWorkspaceState(_ url: URL) throws {
self.workspaceClient = try .default(
fileManager: .default,
folderURL: url,
@@ -132,6 +134,11 @@ final class WorkspaceDocument: NSDocument, ObservableObject, NSToolbarDelegate {
)
self.searchState = .init(self)
self.quickOpenState = .init(fileURL: url)
+ self.statusBarModel = .init(workspaceURL: url)
+ }
+
+ override func read(from url: URL, ofType typeName: String) throws {
+ try initWorkspaceState(url)
// Initialize Workspace
do {
diff --git a/CodeEdit/WorkspaceView.swift b/CodeEdit/WorkspaceView.swift
index 567297d240..2af3dde5f2 100644
--- a/CodeEdit/WorkspaceView.swift
+++ b/CodeEdit/WorkspaceView.swift
@@ -36,12 +36,10 @@ struct WorkspaceView: View {
var body: some View {
ZStack {
- if workspace.workspaceClient != nil {
+ if workspace.workspaceClient != nil, let model = workspace.statusBarModel {
WorkspaceCodeFileView(windowController: windowController, workspace: workspace)
.safeAreaInset(edge: .bottom) {
- if let url = workspace.fileURL {
- StatusBarView(workspaceURL: url)
- }
+ StatusBarView(model: model)
}
} else {
EmptyView()
diff --git a/CodeEditModules/Modules/StatusBar/src/Model/StatusBarModel.swift b/CodeEditModules/Modules/StatusBar/src/Model/StatusBarModel.swift
index 311686a1c9..6636b98da9 100644
--- a/CodeEditModules/Modules/StatusBar/src/Model/StatusBarModel.swift
+++ b/CodeEditModules/Modules/StatusBar/src/Model/StatusBarModel.swift
@@ -8,11 +8,29 @@
import GitClient
import SwiftUI
+public enum StatusBarTab: String, CaseIterable, Identifiable {
+ case terminal
+ case debugger
+ case output
+
+ public var id: String { return self.rawValue }
+ public static var allOptions: [String] {
+ return StatusBarTab.allCases.map { $0.rawValue.capitalized }
+ }
+}
+
/// # StatusBarModel
///
/// A model class to host and manage data for the ``StatusBarView``
///
public class StatusBarModel: ObservableObject {
+ /// The selected tab in the main section.
+ /// - **0**: Terminal
+ /// - **1**: Debugger
+ /// - **2**: Output
+ @Published
+ public var selectedTab: Int = 1
+
// TODO: Implement logic for updating values
/// Returns number of errors during comilation
@Published
@@ -42,6 +60,10 @@ public class StatusBarModel: ObservableObject {
@Published
public var isExpanded: Bool = false
+ /// Returns true when the drawer is visible
+ @Published
+ public var isMaximized: Bool = false
+
/// The current height of the drawer. Zero if hidden
@Published
public var currentHeight: Double = 0
@@ -50,6 +72,14 @@ public class StatusBarModel: ObservableObject {
@Published
public var isDragging: Bool = false
+ /// Indicates whether the breakpoint is enabled or not
+ @Published
+ public var isBreakpointEnabled: Bool = true
+
+ /// Search value to filter in drawer
+ @Published
+ public var searchText: String = ""
+
/// Returns the font for status bar items to use
private(set) var toolbarFont: Font = .system(size: 11)
@@ -60,7 +90,8 @@ public class StatusBarModel: ObservableObject {
private(set) var workspaceURL: URL
/// The maximum height of the drawer
- private(set) var maxHeight: Double = 500
+ /// when isMaximized is true the height gets set to maxHeight
+ private(set) var maxHeight: Double = 5000
/// The default height of the drawer
private(set) var standardHeight: Double = 300
diff --git a/CodeEditModules/Modules/StatusBar/src/StatusBar.swift b/CodeEditModules/Modules/StatusBar/src/StatusBar.swift
index b0482de3a2..0353acc220 100644
--- a/CodeEditModules/Modules/StatusBar/src/StatusBar.swift
+++ b/CodeEditModules/Modules/StatusBar/src/StatusBar.swift
@@ -7,6 +7,7 @@
import SwiftUI
import GitClient
+import CodeEditUI
/// # StatusBarView
///
@@ -21,10 +22,10 @@ public struct StatusBarView: View {
@ObservedObject
private var model: StatusBarModel
- /// Initialize with GitClient
- /// - Parameter gitClient: a GitClient
- public init(workspaceURL: URL) {
- self.model = .init(workspaceURL: workspaceURL)
+ /// Initialize with model
+ /// - Parameter model: The statusbar model
+ public init(model: StatusBarModel) {
+ self.model = model
}
public var body: some View {
@@ -46,16 +47,11 @@ public struct StatusBarView: View {
.foregroundStyle(.bar)
HStack(spacing: 15) {
HStack(spacing: 5) {
- StatusBarLabelButton(
- model: model,
- title: model.errorCount.formatted(),
- image: "xmark.octagon"
- )
- StatusBarLabelButton(
- model: model,
- title: model.warningCount.formatted(),
- image: "exclamationmark.triangle"
- )
+ StatusBarBreakpointButton(model: model)
+ Divider()
+ .frame(maxHeight: 12)
+ .padding(.horizontal, 7)
+ SegmentedControl($model.selectedTab, options: StatusBarTab.allOptions)
}
if model.selectedBranch != nil {
StatusBarBranchPicker(model: model)
@@ -111,7 +107,7 @@ struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
ZStack(alignment: .bottom) {
Color.white
- StatusBarView(workspaceURL: URL(fileURLWithPath: ""))
+ StatusBarView(model: StatusBarModel(workspaceURL: URL(fileURLWithPath: "")))
.previewLayout(.fixed(width: 1.336, height: 500.0))
.preferredColorScheme(.light)
}
diff --git a/CodeEditModules/Modules/StatusBar/src/StatusBarItems/FilterTextField.swift b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/FilterTextField.swift
new file mode 100644
index 0000000000..d82685d945
--- /dev/null
+++ b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/FilterTextField.swift
@@ -0,0 +1,53 @@
+//
+// FilterTextField.swift
+//
+//
+// Created by Stef Kors on 12/04/2022.
+//
+
+import SwiftUI
+
+struct FilterTextField: View {
+ let title: String
+
+ @Binding
+ var text: String
+
+ var body: some View {
+ HStack {
+ Image(systemName: "line.3.horizontal.decrease.circle")
+ .foregroundColor(Color(nsColor: .secondaryLabelColor))
+ textField
+ if !text.isEmpty { clearButton }
+ }
+ .padding(.horizontal, 5)
+ .padding(.vertical, 3)
+ .overlay(
+ RoundedRectangle(cornerRadius: 4)
+ .stroke(Color.gray, lineWidth: 0.5).cornerRadius(4)
+ )
+ }
+
+ private var textField: some View {
+ TextField(title, text: $text)
+ .disableAutocorrection(true)
+ .textFieldStyle(PlainTextFieldStyle())
+ }
+
+ private var clearButton: some View {
+ Button {
+ self.text = ""
+ } label: {
+ Image(systemName: "xmark.circle.fill")
+ }
+ .foregroundColor(.secondary)
+ .buttonStyle(PlainButtonStyle())
+ }
+}
+
+struct FilterTextField_Previews: PreviewProvider {
+ static var previews: some View {
+ FilterTextField(title: "Filter", text: .constant(""))
+ FilterTextField(title: "Filter", text: .constant("codeedi"))
+ }
+}
diff --git a/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarBreakpointButton.swift b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarBreakpointButton.swift
new file mode 100644
index 0000000000..c00fff77af
--- /dev/null
+++ b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarBreakpointButton.swift
@@ -0,0 +1,39 @@
+//
+// StatusBarBreakpointButton.swift
+//
+//
+// Created by Stef Kors on 14/04/2022.
+//
+
+import SwiftUI
+
+internal struct StatusBarBreakpointButton: View {
+ @ObservedObject
+ private var model: StatusBarModel
+
+ internal init(model: StatusBarModel) {
+ self.model = model
+ }
+
+ internal var body: some View {
+ Button {
+ model.isBreakpointEnabled.toggle()
+ } label: {
+ if model.isBreakpointEnabled {
+ Image("custom.breakpoint.fill")
+ .foregroundColor(.accentColor)
+ } else {
+ Image("custom.breakpoint")
+ .foregroundColor(.secondary)
+ }
+ }
+ .buttonStyle(.plain)
+ }
+}
+
+struct StatusBarBreakpointButton_Previews: PreviewProvider {
+ static var previews: some View {
+ let url = URL(string: "~/Developer")!
+ StatusBarBreakpointButton(model: StatusBarModel(workspaceURL: url))
+ }
+}
diff --git a/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarClearButton.swift b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarClearButton.swift
new file mode 100644
index 0000000000..5d5a091c93
--- /dev/null
+++ b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarClearButton.swift
@@ -0,0 +1,34 @@
+//
+// StatusBarClearButton.swift
+//
+//
+// Created by Stef Kors on 12/04/2022.
+//
+
+import SwiftUI
+
+internal struct StatusBarClearButton: View {
+ @ObservedObject
+ private var model: StatusBarModel
+
+ internal init(model: StatusBarModel) {
+ self.model = model
+ }
+
+ internal var body: some View {
+ Button {
+ // Clear terminal
+ } label: {
+ Image(systemName: "trash")
+ .foregroundColor(.secondary)
+ }
+ .buttonStyle(.plain)
+ }
+}
+
+struct StatusBarClearButton_Previews: PreviewProvider {
+ static var previews: some View {
+ let url = URL(string: "~/Developer")!
+ StatusBarClearButton(model: StatusBarModel(workspaceURL: url))
+ }
+}
diff --git a/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarDrawer.swift b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarDrawer.swift
index 1b40727184..ff53e5c145 100644
--- a/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarDrawer.swift
+++ b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarDrawer.swift
@@ -12,14 +12,40 @@ internal struct StatusBarDrawer: View {
@ObservedObject
private var model: StatusBarModel
+ @State
+ private var searchText = ""
+
internal init(model: StatusBarModel) {
self.model = model
}
+ var height: CGFloat {
+ if model.isMaximized {
+ return model.maxHeight
+ }
+ if model.isExpanded {
+ return model.currentHeight
+ }
+ return 0
+ }
+
internal var body: some View {
- TerminalEmulatorView(url: model.workspaceURL)
- .frame(minHeight: 0,
- idealHeight: model.isExpanded ? model.currentHeight : 0,
- maxHeight: model.isExpanded ? model.currentHeight : 0)
+ ZStack(alignment: .bottom) {
+ TerminalEmulatorView(url: model.workspaceURL)
+ .frame(minHeight: 0,
+ idealHeight: height,
+ maxHeight: height)
+ HStack(alignment: .center, spacing: 10) {
+ FilterTextField(title: "Filter", text: $searchText)
+ .frame(maxWidth: 300)
+ Spacer()
+ StatusBarClearButton(model: model)
+ Divider()
+ StatusBarSplitTerminalButton(model: model)
+ StatusBarMaximizeButton(model: model)
+ }
+ .padding(.all, 10)
+ .frame(maxHeight: 34)
+ }
}
}
diff --git a/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarMaximizeButton.swift b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarMaximizeButton.swift
new file mode 100644
index 0000000000..821d4d7dfa
--- /dev/null
+++ b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarMaximizeButton.swift
@@ -0,0 +1,34 @@
+//
+// StatusBarMaximizeButton.swift
+//
+//
+// Created by Stef Kors on 12/04/2022.
+//
+
+import SwiftUI
+
+internal struct StatusBarMaximizeButton: View {
+ @ObservedObject
+ private var model: StatusBarModel
+
+ internal init(model: StatusBarModel) {
+ self.model = model
+ }
+
+ internal var body: some View {
+ Button {
+ model.isMaximized.toggle()
+ } label: {
+ Image(systemName: "arrowtriangle.up.square")
+ .foregroundColor(model.isMaximized ? .accentColor : .primary)
+ }
+ .buttonStyle(.plain)
+ }
+}
+
+struct StatusBarMaximizeButton_Previews: PreviewProvider {
+ static var previews: some View {
+ let url = URL(string: "~/Developer")!
+ StatusBarMaximizeButton(model: StatusBarModel(workspaceURL: url))
+ }
+}
diff --git a/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarSplitTerminalButton.swift b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarSplitTerminalButton.swift
new file mode 100644
index 0000000000..122eb9e3eb
--- /dev/null
+++ b/CodeEditModules/Modules/StatusBar/src/StatusBarItems/StatusBarSplitTerminalButton.swift
@@ -0,0 +1,34 @@
+//
+// StatusBarSplitTerminalButton.swift
+//
+//
+// Created by Stef Kors on 14/04/2022.
+//
+
+import SwiftUI
+
+internal struct StatusBarSplitTerminalButton: View {
+ @ObservedObject
+ private var model: StatusBarModel
+
+ internal init(model: StatusBarModel) {
+ self.model = model
+ }
+
+ internal var body: some View {
+ Button {
+ // todo
+ } label: {
+ Image(systemName: "square.split.2x1")
+ .foregroundColor(.secondary)
+ }
+ .buttonStyle(.plain)
+ }
+}
+
+struct StatusBarSplitTerminalButton_Previews: PreviewProvider {
+ static var previews: some View {
+ let url = URL(string: "~/Developer")!
+ StatusBarSplitTerminalButton(model: StatusBarModel(workspaceURL: url))
+ }
+}
diff --git a/CodeEditModules/Package.swift b/CodeEditModules/Package.swift
index 619472ea9d..2d38de2b68 100644
--- a/CodeEditModules/Package.swift
+++ b/CodeEditModules/Package.swift
@@ -176,6 +176,7 @@ let package = Package(
"GitClient",
"TerminalEmulator",
"CodeFile",
+ "CodeEditUI",
],
path: "Modules/StatusBar/src"
),