Skip to content

Commit 12f3199

Browse files
Made Editor Separators Thicker (#2055)
### Description Added a new split view separator style that results in a thicker separator. ### Related Issues * #2054 ### 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 Before <img width="1728" alt="image" src="https://github.com/user-attachments/assets/178f1457-9255-4948-b6c9-2ae1fecf5bc9" /> After <img width="1728" alt="image" src="https://github.com/user-attachments/assets/ab9defef-2f8e-45c8-bce2-c2e8bcb41b2b" />
1 parent 3d1ac2b commit 12f3199

File tree

4 files changed

+127
-19
lines changed

4 files changed

+127
-19
lines changed

CodeEdit/Features/Editor/Views/EditorLayoutView.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,14 @@ struct EditorLayoutView: View {
4747
}
4848

4949
struct SubEditorLayoutView: View {
50-
@ObservedObject var data: SplitViewData
50+
@Environment(\.colorScheme)
51+
private var colorScheme
5152

53+
@ObservedObject var data: SplitViewData
5254
@FocusState.Binding var focus: Editor?
5355

5456
var body: some View {
55-
SplitView(axis: data.axis) {
57+
SplitView(axis: data.axis, dividerStyle: .editorDivider) {
5658
splitView
5759
}
5860
.edgesIgnoringSafeArea([.top, .bottom])
@@ -61,12 +63,12 @@ struct EditorLayoutView: View {
6163
var splitView: some View {
6264
ForEach(Array(data.editorLayouts.enumerated()), id: \.offset) { index, item in
6365
EditorLayoutView(layout: item, focus: $focus)
64-
.transformEnvironment(\.isAtEdge) { belowToolbar in
65-
calcIsAtEdge(current: &belowToolbar, index: index)
66-
}
67-
.environment(\.splitEditor) { [weak data] edge, newEditor in
68-
data?.split(edge, at: index, new: newEditor)
69-
}
66+
.transformEnvironment(\.isAtEdge) { belowToolbar in
67+
calcIsAtEdge(current: &belowToolbar, index: index)
68+
}
69+
.environment(\.splitEditor) { [weak data] edge, newEditor in
70+
data?.split(edge, at: index, new: newEditor)
71+
}
7072
}
7173
}
7274

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// CodeEditDividerStyle.swift
3+
// CodeEdit
4+
//
5+
// Created by Khan Winter on 5/30/25.
6+
//
7+
8+
import AppKit
9+
10+
/// The style of divider used by ``SplitView``.
11+
///
12+
/// To add a new style, add another case to this enum and fill in the ``customColor`` and ``customThickness``
13+
/// variables. When passed to ``SplitView``, the custom styles will be used instead of the default styles. Leave
14+
/// values as `nil` to use default styles.
15+
enum CodeEditDividerStyle: Equatable {
16+
case system(NSSplitView.DividerStyle)
17+
case editorDivider
18+
19+
var customColor: NSColor? {
20+
switch self {
21+
case .system:
22+
return nil
23+
case .editorDivider:
24+
return NSColor(name: nil) { appearance in
25+
if appearance.name == .darkAqua {
26+
NSColor.black
27+
} else {
28+
NSColor(white: 203.0 / 255.0, alpha: 1.0)
29+
}
30+
}
31+
}
32+
}
33+
34+
var customThickness: CGFloat? {
35+
switch self {
36+
case .system:
37+
return nil
38+
case .editorDivider:
39+
return 3.0
40+
}
41+
}
42+
}

CodeEdit/Features/SplitView/Views/SplitView.swift

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,26 @@ import SwiftUI
99

1010
struct SplitView<Content: View>: View {
1111
var axis: Axis
12+
var dividerStyle: CodeEditDividerStyle
1213
var content: Content
1314

14-
init(axis: Axis, @ViewBuilder content: () -> Content) {
15+
init(axis: Axis, dividerStyle: CodeEditDividerStyle = .system(.thin), @ViewBuilder content: () -> Content) {
1516
self.axis = axis
17+
self.dividerStyle = dividerStyle
1618
self.content = content()
1719
}
1820

19-
@State var viewController: () -> SplitViewController? = { nil }
21+
@State private var viewController: () -> SplitViewController? = { nil }
2022

2123
var body: some View {
2224
VStack {
2325
content.variadic { children in
24-
SplitViewControllerView(axis: axis, children: children, viewController: $viewController)
26+
SplitViewControllerView(
27+
axis: axis,
28+
dividerStyle: dividerStyle,
29+
children: children,
30+
viewController: $viewController
31+
)
2532
}
2633
}
2734
._trait(SplitViewControllerLayoutValueKey.self, viewController)

CodeEdit/Features/SplitView/Views/SplitViewControllerView.swift

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,20 @@ import SwiftUI
1010
struct SplitViewControllerView: NSViewControllerRepresentable {
1111

1212
var axis: Axis
13+
var dividerStyle: CodeEditDividerStyle
1314
var children: _VariadicView.Children
1415
@Binding var viewController: () -> SplitViewController?
1516

1617
func makeNSViewController(context: Context) -> SplitViewController {
17-
context.coordinator
18+
let controller = SplitViewController(axis: axis) { controller in
19+
updateItems(controller: controller)
20+
}
21+
return controller
1822
}
1923

2024
func updateNSViewController(_ controller: SplitViewController, context: Context) {
2125
updateItems(controller: controller)
26+
controller.setDividerStyle(dividerStyle)
2227
}
2328

2429
private func updateItems(controller: SplitViewController) {
@@ -61,40 +66,92 @@ struct SplitViewControllerView: NSViewControllerRepresentable {
6166
}
6267

6368
func makeCoordinator() -> SplitViewController {
64-
SplitViewController(parent: self, axis: axis)
69+
SplitViewController(axis: axis, setUpItems: nil)
6570
}
6671
}
6772

6873
final class SplitViewController: NSSplitViewController {
74+
final class CustomSplitView: NSSplitView {
75+
@Invalidating(.display)
76+
var customDividerStyle: CodeEditDividerStyle = .system(.thin) {
77+
didSet {
78+
switch customDividerStyle {
79+
case .system(let dividerStyle):
80+
self.dividerStyle = dividerStyle
81+
case .editorDivider:
82+
return
83+
}
84+
}
85+
}
86+
87+
init() {
88+
super.init(frame: .zero)
89+
dividerStyle = .thin
90+
}
91+
92+
required init?(coder: NSCoder) {
93+
fatalError("init(coder:) has not been implemented")
94+
}
95+
96+
override var dividerColor: NSColor {
97+
customDividerStyle.customColor ?? super.dividerColor
98+
}
99+
100+
override var dividerThickness: CGFloat {
101+
customDividerStyle.customThickness ?? super.dividerThickness
102+
}
103+
}
69104

70105
var items: [SplitViewItem] = []
71106
var axis: Axis
72-
var parentView: SplitViewControllerView
107+
var parentView: SplitViewControllerView?
108+
109+
var setUpItems: ((SplitViewController) -> Void)?
73110

74-
init(parent: SplitViewControllerView, axis: Axis = .horizontal) {
111+
init(axis: Axis, setUpItems: ((SplitViewController) -> Void)?) {
75112
self.axis = axis
76-
self.parentView = parent
113+
self.setUpItems = setUpItems
77114
super.init(nibName: nil, bundle: nil)
78115
}
79116

80117
required init?(coder: NSCoder) {
81118
fatalError("init(coder:) has not been implemented")
82119
}
83120

121+
override func loadView() {
122+
splitView = CustomSplitView()
123+
super.loadView()
124+
}
125+
84126
override func viewDidLoad() {
127+
super.viewDidLoad()
85128
splitView.isVertical = axis != .vertical
86-
splitView.dividerStyle = .thin
129+
setUpItems?(self)
87130
DispatchQueue.main.async { [weak self] in
88-
self?.parentView.viewController = { [weak self] in
131+
self?.parentView?.viewController = { [weak self] in
89132
self
90133
}
91134
}
92135
}
93136

94-
override func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool {
137+
override func splitView(_ splitView: NSSplitView, canCollapseSubview subview: NSView) -> Bool {
95138
false
96139
}
97140

141+
override func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool {
142+
// For some reason, AppKit _really_ wants to hide dividers when there's only one item (and no dividers)
143+
// so we do this check for them.
144+
guard items.count > 1 else { return false }
145+
return super.splitView(splitView, shouldHideDividerAt: dividerIndex)
146+
}
147+
148+
func setDividerStyle(_ dividerStyle: CodeEditDividerStyle) {
149+
guard let splitView = splitView as? CustomSplitView else {
150+
return
151+
}
152+
splitView.customDividerStyle = dividerStyle
153+
}
154+
98155
func collapse(for id: AnyHashable, enabled: Bool) {
99156
items.first { $0.id == id }?.item.animator().isCollapsed = enabled
100157
}

0 commit comments

Comments
 (0)