Skip to content

Made Editor Separators Thicker #2055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions CodeEdit/Features/Editor/Views/EditorLayoutView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ struct EditorLayoutView: View {
}

struct SubEditorLayoutView: View {
@ObservedObject var data: SplitViewData
@Environment(\.colorScheme)
private var colorScheme

@ObservedObject var data: SplitViewData
@FocusState.Binding var focus: Editor?

var body: some View {
SplitView(axis: data.axis) {
SplitView(axis: data.axis, dividerStyle: .editorDivider) {
splitView
}
.edgesIgnoringSafeArea([.top, .bottom])
Expand All @@ -61,12 +63,12 @@ struct EditorLayoutView: View {
var splitView: some View {
ForEach(Array(data.editorLayouts.enumerated()), id: \.offset) { index, item in
EditorLayoutView(layout: item, focus: $focus)
.transformEnvironment(\.isAtEdge) { belowToolbar in
calcIsAtEdge(current: &belowToolbar, index: index)
}
.environment(\.splitEditor) { [weak data] edge, newEditor in
data?.split(edge, at: index, new: newEditor)
}
.transformEnvironment(\.isAtEdge) { belowToolbar in
calcIsAtEdge(current: &belowToolbar, index: index)
}
.environment(\.splitEditor) { [weak data] edge, newEditor in
data?.split(edge, at: index, new: newEditor)
}
}
}

Expand Down
42 changes: 42 additions & 0 deletions CodeEdit/Features/SplitView/Model/CodeEditDividerStyle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// CodeEditDividerStyle.swift
// CodeEdit
//
// Created by Khan Winter on 5/30/25.
//

import AppKit

/// The style of divider used by ``SplitView``.
///
/// To add a new style, add another case to this enum and fill in the ``customColor`` and ``customThickness``
/// variables. When passed to ``SplitView``, the custom styles will be used instead of the default styles. Leave
/// values as `nil` to use default styles.
enum CodeEditDividerStyle: Equatable {
case system(NSSplitView.DividerStyle)
case editorDivider

var customColor: NSColor? {
switch self {
case .system:
return nil
case .editorDivider:
return NSColor(name: nil) { appearance in
if appearance.name == .darkAqua {
NSColor.black
} else {
NSColor(white: 203.0 / 255.0, alpha: 1.0)
}
}
}
}

var customThickness: CGFloat? {
switch self {
case .system:
return nil
case .editorDivider:
return 3.0
}
}
}
13 changes: 10 additions & 3 deletions CodeEdit/Features/SplitView/Views/SplitView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,26 @@ import SwiftUI

struct SplitView<Content: View>: View {
var axis: Axis
var dividerStyle: CodeEditDividerStyle
var content: Content

init(axis: Axis, @ViewBuilder content: () -> Content) {
init(axis: Axis, dividerStyle: CodeEditDividerStyle = .system(.thin), @ViewBuilder content: () -> Content) {
self.axis = axis
self.dividerStyle = dividerStyle
self.content = content()
}

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

var body: some View {
VStack {
content.variadic { children in
SplitViewControllerView(axis: axis, children: children, viewController: $viewController)
SplitViewControllerView(
axis: axis,
dividerStyle: dividerStyle,
children: children,
viewController: $viewController
)
}
}
._trait(SplitViewControllerLayoutValueKey.self, viewController)
Expand Down
73 changes: 65 additions & 8 deletions CodeEdit/Features/SplitView/Views/SplitViewControllerView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ import SwiftUI
struct SplitViewControllerView: NSViewControllerRepresentable {

var axis: Axis
var dividerStyle: CodeEditDividerStyle
var children: _VariadicView.Children
@Binding var viewController: () -> SplitViewController?

func makeNSViewController(context: Context) -> SplitViewController {
context.coordinator
let controller = SplitViewController(axis: axis) { controller in
updateItems(controller: controller)
}
return controller
}

func updateNSViewController(_ controller: SplitViewController, context: Context) {
updateItems(controller: controller)
controller.setDividerStyle(dividerStyle)
}

private func updateItems(controller: SplitViewController) {
Expand Down Expand Up @@ -61,40 +66,92 @@ struct SplitViewControllerView: NSViewControllerRepresentable {
}

func makeCoordinator() -> SplitViewController {
SplitViewController(parent: self, axis: axis)
SplitViewController(axis: axis, setUpItems: nil)
}
}

final class SplitViewController: NSSplitViewController {
final class CustomSplitView: NSSplitView {
@Invalidating(.display)
var customDividerStyle: CodeEditDividerStyle = .system(.thin) {
didSet {
switch customDividerStyle {
case .system(let dividerStyle):
self.dividerStyle = dividerStyle
case .editorDivider:
return
}
}
}

init() {
super.init(frame: .zero)
dividerStyle = .thin
}

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

override var dividerColor: NSColor {
customDividerStyle.customColor ?? super.dividerColor
}

override var dividerThickness: CGFloat {
customDividerStyle.customThickness ?? super.dividerThickness
}
}

var items: [SplitViewItem] = []
var axis: Axis
var parentView: SplitViewControllerView
var parentView: SplitViewControllerView?

var setUpItems: ((SplitViewController) -> Void)?

init(parent: SplitViewControllerView, axis: Axis = .horizontal) {
init(axis: Axis, setUpItems: ((SplitViewController) -> Void)?) {
self.axis = axis
self.parentView = parent
self.setUpItems = setUpItems
super.init(nibName: nil, bundle: nil)
}

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

override func loadView() {
splitView = CustomSplitView()
super.loadView()
}

override func viewDidLoad() {
super.viewDidLoad()
splitView.isVertical = axis != .vertical
splitView.dividerStyle = .thin
setUpItems?(self)
DispatchQueue.main.async { [weak self] in
self?.parentView.viewController = { [weak self] in
self?.parentView?.viewController = { [weak self] in
self
}
}
}

override func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool {
override func splitView(_ splitView: NSSplitView, canCollapseSubview subview: NSView) -> Bool {
false
}

override func splitView(_ splitView: NSSplitView, shouldHideDividerAt dividerIndex: Int) -> Bool {
// For some reason, AppKit _really_ wants to hide dividers when there's only one item (and no dividers)
// so we do this check for them.
guard items.count > 1 else { return false }
return super.splitView(splitView, shouldHideDividerAt: dividerIndex)
}

func setDividerStyle(_ dividerStyle: CodeEditDividerStyle) {
guard let splitView = splitView as? CustomSplitView else {
return
}
splitView.customDividerStyle = dividerStyle
}

func collapse(for id: AnyHashable, enabled: Bool) {
items.first { $0.id == id }?.item.animator().isCollapsed = enabled
}
Expand Down