Skip to content

Commit 4a73315

Browse files
committed
Initial Commit - Ribbon View & Toggles
1 parent 3dccebd commit 4a73315

18 files changed

Lines changed: 572 additions & 90 deletions

File tree

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct ContentView: View {
2727
@State private var settingsIsPresented: Bool = false
2828
@State private var treeSitterClient = TreeSitterClient()
2929
@AppStorage("showMinimap") private var showMinimap: Bool = true
30+
@AppStorage("showFoldingRibbon") private var showFoldingRibbon: Bool = true
3031
@State private var indentOption: IndentOption = .spaces(count: 4)
3132
@AppStorage("reformatAtColumn") private var reformatAtColumn: Int = 80
3233
@AppStorage("showReformattingGuide") private var showReformattingGuide: Bool = false
@@ -56,7 +57,8 @@ struct ContentView: View {
5657
useSystemCursor: useSystemCursor,
5758
showMinimap: showMinimap,
5859
reformatAtColumn: reformatAtColumn,
59-
showReformattingGuide: showReformattingGuide
60+
showReformattingGuide: showReformattingGuide,
61+
showFoldingRibbon: showFoldingRibbon
6062
)
6163
.overlay(alignment: .bottom) {
6264
StatusBar(
@@ -71,7 +73,8 @@ struct ContentView: View {
7173
showMinimap: $showMinimap,
7274
indentOption: $indentOption,
7375
reformatAtColumn: $reformatAtColumn,
74-
showReformattingGuide: $showReformattingGuide
76+
showReformattingGuide: $showReformattingGuide,
77+
showFoldingRibbon: $showFoldingRibbon
7578
)
7679
}
7780
.ignoresSafeArea()

Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct StatusBar: View {
2626
@Binding var indentOption: IndentOption
2727
@Binding var reformatAtColumn: Int
2828
@Binding var showReformattingGuide: Bool
29+
@Binding var showFoldingRibbon: Bool
2930

3031
var body: some View {
3132
HStack {
@@ -43,6 +44,7 @@ struct StatusBar: View {
4344
.onChange(of: reformatAtColumn) { _, newValue in
4445
reformatAtColumn = max(1, min(200, newValue))
4546
}
47+
Toggle("Show Folding Ribbon", isOn: $showFoldingRibbon)
4648
if #available(macOS 14, *) {
4749
Toggle("Use System Cursor", isOn: $useSystemCursor)
4850
} else {

Package.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ let package = Package(
1616
dependencies: [
1717
// A fast, efficient, text view for code.
1818
.package(
19-
url: "https://github.com/CodeEditApp/CodeEditTextView.git",
20-
from: "0.10.1"
19+
path: "../CodeEditTextView"
20+
// url: "https://github.com/CodeEditApp/CodeEditTextView.git",
21+
// from: "0.10.1"
2122
),
2223
// tree-sitter languages
2324
.package(

Sources/CodeEditSourceEditor/CodeEditSourceEditor/CodeEditSourceEditor.swift

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,22 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
3939
/// the default `TreeSitterClient` highlighter.
4040
/// - contentInsets: Insets to use to offset the content in the enclosing scroll view. Leave as `nil` to let the
4141
/// scroll view automatically adjust content insets.
42-
/// - additionalTextInsets: An additional amount to inset the text of the editor by.
42+
/// - additionalTextInsets: A set of extra text insets to indent only *text* content. Does not effect
43+
/// decorations like the find panel.
4344
/// - isEditable: A Boolean value that controls whether the text view allows the user to edit text.
4445
/// - isSelectable: A Boolean value that controls whether the text view allows the user to select text. If this
4546
/// value is true, and `isEditable` is false, the editor is selectable but not editable.
4647
/// - letterSpacing: The amount of space to use between letters, as a percent. Eg: `1.0` = no space, `1.5` = 1/2 a
4748
/// character's width between characters, etc. Defaults to `1.0`
4849
/// - bracketPairEmphasis: The type of highlight to use to highlight bracket pairs.
4950
/// See `BracketPairHighlight` for more information. Defaults to `nil`
50-
/// - useSystemCursor: If true, uses the system cursor on `>=macOS 14`.
51+
/// - useSystemCursor: Use the system cursor instead of the default line cursor. Only available after macOS 14.
5152
/// - undoManager: The undo manager for the text view. Defaults to `nil`, which will create a new CEUndoManager
5253
/// - coordinators: Any text coordinators for the view to use. See ``TextViewCoordinator`` for more information.
53-
/// - showMinimap: Whether to show the minimap
54+
/// - showMinimap: Toggle the visibility of the minimap.
5455
/// - reformatAtColumn: The column to reformat at
5556
/// - showReformattingGuide: Whether to show the reformatting guide
57+
/// - showFoldingRibbon: Toggle the visibility of the line folding ribbon.
5658
public init(
5759
_ text: Binding<String>,
5860
language: CodeLanguage,
@@ -77,7 +79,8 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
7779
coordinators: [any TextViewCoordinator] = [],
7880
showMinimap: Bool,
7981
reformatAtColumn: Int,
80-
showReformattingGuide: Bool
82+
showReformattingGuide: Bool,
83+
showFoldingRibbon: Bool
8184
) {
8285
self.text = .binding(text)
8386
self.language = language
@@ -107,6 +110,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
107110
self.showMinimap = showMinimap
108111
self.reformatAtColumn = reformatAtColumn
109112
self.showReformattingGuide = showReformattingGuide
113+
self.showFoldingRibbon = showFoldingRibbon
110114
}
111115

112116
/// Initializes a Text Editor
@@ -127,18 +131,22 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
127131
/// the default `TreeSitterClient` highlighter.
128132
/// - contentInsets: Insets to use to offset the content in the enclosing scroll view. Leave as `nil` to let the
129133
/// scroll view automatically adjust content insets.
134+
/// - additionalTextInsets: A set of extra text insets to indent only *text* content. Does not effect
135+
/// decorations like the find panel.
130136
/// - isEditable: A Boolean value that controls whether the text view allows the user to edit text.
131137
/// - isSelectable: A Boolean value that controls whether the text view allows the user to select text. If this
132138
/// value is true, and `isEditable` is false, the editor is selectable but not editable.
133139
/// - letterSpacing: The amount of space to use between letters, as a percent. Eg: `1.0` = no space, `1.5` = 1/2 a
134140
/// character's width between characters, etc. Defaults to `1.0`
135141
/// - bracketPairEmphasis: The type of highlight to use to highlight bracket pairs.
136142
/// See `BracketPairEmphasis` for more information. Defaults to `nil`
143+
/// - useSystemCursor: Use the system cursor instead of the default line cursor. Only available after macOS 14.
137144
/// - undoManager: The undo manager for the text view. Defaults to `nil`, which will create a new CEUndoManager
138145
/// - coordinators: Any text coordinators for the view to use. See ``TextViewCoordinator`` for more information.
139-
/// - showMinimap: Whether to show the minimap
146+
/// - showMinimap: Toggle the visibility of the minimap.
140147
/// - reformatAtColumn: The column to reformat at
141148
/// - showReformattingGuide: Whether to show the reformatting guide
149+
/// - showFoldingRibbon: Toggle the visibility of the line folding ribbon.
142150
public init(
143151
_ text: NSTextStorage,
144152
language: CodeLanguage,
@@ -163,7 +171,8 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
163171
coordinators: [any TextViewCoordinator] = [],
164172
showMinimap: Bool,
165173
reformatAtColumn: Int,
166-
showReformattingGuide: Bool
174+
showReformattingGuide: Bool,
175+
showFoldingRibbon: Bool
167176
) {
168177
self.text = .storage(text)
169178
self.language = language
@@ -193,6 +202,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
193202
self.showMinimap = showMinimap
194203
self.reformatAtColumn = reformatAtColumn
195204
self.showReformattingGuide = showReformattingGuide
205+
self.showFoldingRibbon = showFoldingRibbon
196206
}
197207

198208
package var text: TextAPI
@@ -219,6 +229,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
219229
package var showMinimap: Bool
220230
private var reformatAtColumn: Int
221231
private var showReformattingGuide: Bool
232+
package var showFoldingRibbon: Bool
222233

223234
public typealias NSViewControllerType = TextViewController
224235

@@ -247,7 +258,8 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
247258
coordinators: coordinators,
248259
showMinimap: showMinimap,
249260
reformatAtColumn: reformatAtColumn,
250-
showReformattingGuide: showReformattingGuide
261+
showReformattingGuide: showReformattingGuide,
262+
showFoldingRibbon: showFoldingRibbon
251263
)
252264
switch text {
253265
case .binding(let binding):
@@ -336,6 +348,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
336348
controller.contentInsets = contentInsets
337349
controller.additionalTextInsets = additionalTextInsets
338350
controller.showMinimap = showMinimap
351+
controller.showFoldingRibbon = showFoldingRibbon
339352

340353
if controller.indentOption != indentOption {
341354
controller.indentOption = indentOption
@@ -397,6 +410,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
397410
controller.showMinimap == showMinimap &&
398411
controller.reformatAtColumn == reformatAtColumn &&
399412
controller.showReformattingGuide == showReformattingGuide &&
413+
controller.showFoldingRibbon == showFoldingRibbon &&
400414
areHighlightProvidersEqual(controller: controller, coordinator: coordinator)
401415
}
402416

Sources/CodeEditSourceEditor/Controller/TextViewController+GutterViewDelegate.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
import Foundation
99

1010
extension TextViewController: GutterViewDelegate {
11-
public func gutterViewWidthDidUpdate(newWidth: CGFloat) {
12-
gutterView?.frame.size.width = newWidth
13-
textView?.textInsets = textViewInsets
11+
public func gutterViewWidthDidUpdate() {
12+
updateTextInsets()
1413
}
1514
}

Sources/CodeEditSourceEditor/Controller/TextViewController+LoadView.swift renamed to Sources/CodeEditSourceEditor/Controller/TextViewController+Lifecycle.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import CodeEditTextView
99
import AppKit
1010

1111
extension TextViewController {
12+
override public func viewWillAppear() {
13+
super.viewWillAppear()
14+
// The calculation this causes cannot be done until the view knows it's final position
15+
updateTextInsets()
16+
minimapView.layout()
17+
}
18+
1219
override public func loadView() {
1320
super.loadView()
1421

@@ -106,9 +113,7 @@ extension TextViewController {
106113
object: scrollView.contentView,
107114
queue: .main
108115
) { [weak self] notification in
109-
guard let clipView = notification.object as? NSClipView,
110-
let textView = self?.textView else { return }
111-
textView.updatedViewport(self?.scrollView.documentVisibleRect ?? .zero)
116+
guard let clipView = notification.object as? NSClipView else { return }
112117
self?.gutterView.needsDisplay = true
113118
self?.minimapXConstraint?.constant = clipView.bounds.origin.x
114119
}
@@ -120,7 +125,6 @@ extension TextViewController {
120125
object: scrollView.contentView,
121126
queue: .main
122127
) { [weak self] _ in
123-
self?.textView.updatedViewport(self?.scrollView.documentVisibleRect ?? .zero)
124128
self?.gutterView.needsDisplay = true
125129
self?.emphasisManager?.removeEmphases(for: EmphasisGroup.brackets)
126130
self?.updateTextInsets()

Sources/CodeEditSourceEditor/Controller/TextViewController+StyleViews.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ extension TextViewController {
5656
gutterView.selectedLineTextColor = nil
5757
gutterView.selectedLineColor = .clear
5858
}
59+
gutterView.showFoldingRibbon = showFoldingRibbon
5960
}
6061

6162
/// Style the scroll view.

Sources/CodeEditSourceEditor/Controller/TextViewController.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ public class TextViewController: NSViewController { // swiftlint:disable:this ty
204204
}
205205
}
206206

207+
/// Toggles the line folding ribbon in the gutter view.
208+
public var showFoldingRibbon: Bool {
209+
didSet {
210+
gutterView?.showFoldingRibbon = showFoldingRibbon
211+
}
212+
}
213+
207214
var textCoordinators: [WeakCoordinator] = []
208215

209216
var highlighter: Highlighter?
@@ -229,7 +236,7 @@ public class TextViewController: NSViewController { // swiftlint:disable:this ty
229236

230237
package var textViewInsets: HorizontalEdgeInsets {
231238
HorizontalEdgeInsets(
232-
left: gutterView.gutterWidth,
239+
left: gutterView?.frame.width ?? 0.0,
233240
right: textViewTrailingInset
234241
)
235242
}
@@ -265,6 +272,9 @@ public class TextViewController: NSViewController { // swiftlint:disable:this ty
265272
}
266273
}
267274

275+
/// A default `NSParagraphStyle` with a set `lineHeight`
276+
package lazy var paragraphStyle: NSMutableParagraphStyle = generateParagraphStyle()
277+
268278
// MARK: Init
269279

270280
init(
@@ -291,7 +301,8 @@ public class TextViewController: NSViewController { // swiftlint:disable:this ty
291301
coordinators: [TextViewCoordinator] = [],
292302
showMinimap: Bool,
293303
reformatAtColumn: Int = 80,
294-
showReformattingGuide: Bool = false
304+
showReformattingGuide: Bool = false,
305+
showFoldingRibbon: Bool
295306
) {
296307
self.language = language
297308
self.font = font
@@ -314,6 +325,7 @@ public class TextViewController: NSViewController { // swiftlint:disable:this ty
314325
self.showMinimap = showMinimap
315326
self.reformatAtColumn = reformatAtColumn
316327
self.showReformattingGuide = showReformattingGuide
328+
self.showFoldingRibbon = showFoldingRibbon
317329

318330
super.init(nibName: nil, bundle: nil)
319331

@@ -362,18 +374,6 @@ public class TextViewController: NSViewController { // swiftlint:disable:this ty
362374
self.gutterView.setNeedsDisplay(self.gutterView.frame)
363375
}
364376

365-
// MARK: Paragraph Style
366-
367-
/// A default `NSParagraphStyle` with a set `lineHeight`
368-
package lazy var paragraphStyle: NSMutableParagraphStyle = generateParagraphStyle()
369-
370-
override public func viewWillAppear() {
371-
super.viewWillAppear()
372-
// The calculation this causes cannot be done until the view knows it's final position
373-
updateTextInsets()
374-
minimapView.layout()
375-
}
376-
377377
deinit {
378378
if let highlighter {
379379
textView.removeStorageDelegate(highlighter)

Sources/CodeEditSourceEditor/Extensions/TextView+/TextView+TextFormation.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ extension TextView: TextInterface {
4545
in: mutation.range,
4646
replacementLength: (mutation.string as NSString).length
4747
)
48+
layoutManager.setNeedsLayout()
4849
}
4950
}

0 commit comments

Comments
 (0)