Skip to content

Add Ribbon View, Demo Fold Provider, Ribbon Toggles #315

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
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

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct ContentView: View {
@State private var settingsIsPresented: Bool = false
@State private var treeSitterClient = TreeSitterClient()
@AppStorage("showMinimap") private var showMinimap: Bool = true
@AppStorage("showFoldingRibbon") private var showFoldingRibbon: Bool = true
@State private var indentOption: IndentOption = .spaces(count: 4)
@AppStorage("reformatAtColumn") private var reformatAtColumn: Int = 80
@AppStorage("showReformattingGuide") private var showReformattingGuide: Bool = false
Expand Down Expand Up @@ -56,7 +57,8 @@ struct ContentView: View {
useSystemCursor: useSystemCursor,
showMinimap: showMinimap,
reformatAtColumn: reformatAtColumn,
showReformattingGuide: showReformattingGuide
showReformattingGuide: showReformattingGuide,
showFoldingRibbon: showFoldingRibbon
)
.overlay(alignment: .bottom) {
StatusBar(
Expand All @@ -71,7 +73,8 @@ struct ContentView: View {
showMinimap: $showMinimap,
indentOption: $indentOption,
reformatAtColumn: $reformatAtColumn,
showReformattingGuide: $showReformattingGuide
showReformattingGuide: $showReformattingGuide,
showFoldingRibbon: $showFoldingRibbon
)
}
.ignoresSafeArea()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct StatusBar: View {
@Binding var indentOption: IndentOption
@Binding var reformatAtColumn: Int
@Binding var showReformattingGuide: Bool
@Binding var showFoldingRibbon: Bool

var body: some View {
HStack {
Expand All @@ -43,6 +44,7 @@ struct StatusBar: View {
.onChange(of: reformatAtColumn) { _, newValue in
reformatAtColumn = max(1, min(200, newValue))
}
Toggle("Show Folding Ribbon", isOn: $showFoldingRibbon)
if #available(macOS 14, *) {
Toggle("Use System Cursor", isOn: $useSystemCursor)
} else {
Expand Down
9 changes: 9 additions & 0 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ let package = Package(
// A fast, efficient, text view for code.
.package(
url: "https://github.com/CodeEditApp/CodeEditTextView.git",
from: "0.10.1"
from: "0.11.0"
),
// tree-sitter languages
.package(
url: "https://github.com/CodeEditApp/CodeEditLanguages.git",
exact: "0.1.20"
),
// CodeEditSymbols
.package(
url: "https://github.com/CodeEditApp/CodeEditSymbols.git",
exact: "0.2.3"
),
// SwiftLint
.package(
url: "https://github.com/lukepistrol/SwiftLintPlugin",
Expand All @@ -43,7 +48,8 @@ let package = Package(
dependencies: [
"CodeEditTextView",
"CodeEditLanguages",
"TextFormation"
"TextFormation",
"CodeEditSymbols"
],
plugins: [
.plugin(name: "SwiftLint", package: "SwiftLintPlugin")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,22 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
/// the default `TreeSitterClient` highlighter.
/// - contentInsets: Insets to use to offset the content in the enclosing scroll view. Leave as `nil` to let the
/// scroll view automatically adjust content insets.
/// - additionalTextInsets: An additional amount to inset the text of the editor by.
/// - additionalTextInsets: A set of extra text insets to indent only *text* content. Does not effect
/// decorations like the find panel.
/// - isEditable: A Boolean value that controls whether the text view allows the user to edit text.
/// - isSelectable: A Boolean value that controls whether the text view allows the user to select text. If this
/// value is true, and `isEditable` is false, the editor is selectable but not editable.
/// - letterSpacing: The amount of space to use between letters, as a percent. Eg: `1.0` = no space, `1.5` = 1/2 a
/// character's width between characters, etc. Defaults to `1.0`
/// - bracketPairEmphasis: The type of highlight to use to highlight bracket pairs.
/// See `BracketPairHighlight` for more information. Defaults to `nil`
/// - useSystemCursor: If true, uses the system cursor on `>=macOS 14`.
/// - useSystemCursor: Use the system cursor instead of the default line cursor. Only available after macOS 14.
/// - undoManager: The undo manager for the text view. Defaults to `nil`, which will create a new CEUndoManager
/// - coordinators: Any text coordinators for the view to use. See ``TextViewCoordinator`` for more information.
/// - showMinimap: Whether to show the minimap
/// - showMinimap: Toggle the visibility of the minimap.
/// - reformatAtColumn: The column to reformat at
/// - showReformattingGuide: Whether to show the reformatting guide
/// - showFoldingRibbon: Toggle the visibility of the line folding ribbon.
public init(
_ text: Binding<String>,
language: CodeLanguage,
Expand All @@ -77,7 +79,8 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
coordinators: [any TextViewCoordinator] = [],
showMinimap: Bool,
reformatAtColumn: Int,
showReformattingGuide: Bool
showReformattingGuide: Bool,
showFoldingRibbon: Bool
) {
self.text = .binding(text)
self.language = language
Expand Down Expand Up @@ -107,6 +110,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
self.showMinimap = showMinimap
self.reformatAtColumn = reformatAtColumn
self.showReformattingGuide = showReformattingGuide
self.showFoldingRibbon = showFoldingRibbon
}

/// Initializes a Text Editor
Expand All @@ -127,18 +131,22 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
/// the default `TreeSitterClient` highlighter.
/// - contentInsets: Insets to use to offset the content in the enclosing scroll view. Leave as `nil` to let the
/// scroll view automatically adjust content insets.
/// - additionalTextInsets: A set of extra text insets to indent only *text* content. Does not effect
/// decorations like the find panel.
/// - isEditable: A Boolean value that controls whether the text view allows the user to edit text.
/// - isSelectable: A Boolean value that controls whether the text view allows the user to select text. If this
/// value is true, and `isEditable` is false, the editor is selectable but not editable.
/// - letterSpacing: The amount of space to use between letters, as a percent. Eg: `1.0` = no space, `1.5` = 1/2 a
/// character's width between characters, etc. Defaults to `1.0`
/// - bracketPairEmphasis: The type of highlight to use to highlight bracket pairs.
/// See `BracketPairEmphasis` for more information. Defaults to `nil`
/// - useSystemCursor: Use the system cursor instead of the default line cursor. Only available after macOS 14.
/// - undoManager: The undo manager for the text view. Defaults to `nil`, which will create a new CEUndoManager
/// - coordinators: Any text coordinators for the view to use. See ``TextViewCoordinator`` for more information.
/// - showMinimap: Whether to show the minimap
/// - showMinimap: Toggle the visibility of the minimap.
/// - reformatAtColumn: The column to reformat at
/// - showReformattingGuide: Whether to show the reformatting guide
/// - showFoldingRibbon: Toggle the visibility of the line folding ribbon.
public init(
_ text: NSTextStorage,
language: CodeLanguage,
Expand All @@ -163,7 +171,8 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
coordinators: [any TextViewCoordinator] = [],
showMinimap: Bool,
reformatAtColumn: Int,
showReformattingGuide: Bool
showReformattingGuide: Bool,
showFoldingRibbon: Bool
) {
self.text = .storage(text)
self.language = language
Expand Down Expand Up @@ -193,6 +202,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
self.showMinimap = showMinimap
self.reformatAtColumn = reformatAtColumn
self.showReformattingGuide = showReformattingGuide
self.showFoldingRibbon = showFoldingRibbon
}

package var text: TextAPI
Expand All @@ -219,6 +229,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
package var showMinimap: Bool
private var reformatAtColumn: Int
private var showReformattingGuide: Bool
package var showFoldingRibbon: Bool

public typealias NSViewControllerType = TextViewController

Expand Down Expand Up @@ -247,7 +258,8 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
coordinators: coordinators,
showMinimap: showMinimap,
reformatAtColumn: reformatAtColumn,
showReformattingGuide: showReformattingGuide
showReformattingGuide: showReformattingGuide,
showFoldingRibbon: showFoldingRibbon
)
switch text {
case .binding(let binding):
Expand Down Expand Up @@ -336,6 +348,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
controller.contentInsets = contentInsets
controller.additionalTextInsets = additionalTextInsets
controller.showMinimap = showMinimap
controller.showFoldingRibbon = showFoldingRibbon

if controller.indentOption != indentOption {
controller.indentOption = indentOption
Expand Down Expand Up @@ -397,6 +410,7 @@ public struct CodeEditSourceEditor: NSViewControllerRepresentable {
controller.showMinimap == showMinimap &&
controller.reformatAtColumn == reformatAtColumn &&
controller.showReformattingGuide == showReformattingGuide &&
controller.showFoldingRibbon == showFoldingRibbon &&
areHighlightProvidersEqual(controller: controller, coordinator: coordinator)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import AppKit
extension TextViewController {
/// Sets new cursor positions.
/// - Parameter positions: The positions to set. Lines and columns are 1-indexed.
public func setCursorPositions(_ positions: [CursorPosition]) {
public func setCursorPositions(_ positions: [CursorPosition], scrollToVisible: Bool = false) {
if isPostingCursorNotification { return }
var newSelectedRanges: [NSRange] = []
for position in positions {
Expand All @@ -33,6 +33,10 @@ extension TextViewController {
}
}
textView.selectionManager.setSelectedRanges(newSelectedRanges)

if scrollToVisible {
textView.scrollSelectionToVisible()
}
}

/// Update the ``TextViewController/cursorPositions`` variable with new text selections from the text view.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
// Created by Khan Winter on 3/16/25.
//

import Foundation
import AppKit
import CodeEditTextView

extension TextViewController: FindPanelTarget {
var findPanelTargetView: NSView {
textView
}

func findPanelWillShow(panelHeight: CGFloat) {
updateContentInsets()
}
Expand All @@ -17,6 +21,10 @@ extension TextViewController: FindPanelTarget {
updateContentInsets()
}

func findPanelModeDidChange(to mode: FindPanelMode) {
updateContentInsets()
}

var emphasisManager: EmphasisManager? {
textView?.emphasisManager
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import Foundation

extension TextViewController: GutterViewDelegate {
public func gutterViewWidthDidUpdate(newWidth: CGFloat) {
gutterView?.frame.size.width = newWidth
textView?.textInsets = textViewInsets
public func gutterViewWidthDidUpdate() {
updateTextInsets()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ import CodeEditTextView
import AppKit

extension TextViewController {
override public func viewWillAppear() {
super.viewWillAppear()
// The calculation this causes cannot be done until the view knows it's final position
updateTextInsets()
minimapView.layout()
}

override public func loadView() {
super.loadView()

Expand Down Expand Up @@ -106,9 +113,7 @@ extension TextViewController {
object: scrollView.contentView,
queue: .main
) { [weak self] notification in
guard let clipView = notification.object as? NSClipView,
let textView = self?.textView else { return }
textView.updatedViewport(self?.scrollView.documentVisibleRect ?? .zero)
guard let clipView = notification.object as? NSClipView else { return }
self?.gutterView.needsDisplay = true
self?.minimapXConstraint?.constant = clipView.bounds.origin.x
}
Expand All @@ -120,7 +125,6 @@ extension TextViewController {
object: scrollView.contentView,
queue: .main
) { [weak self] _ in
self?.textView.updatedViewport(self?.scrollView.documentVisibleRect ?? .zero)
self?.gutterView.needsDisplay = true
self?.emphasisManager?.removeEmphases(for: EmphasisGroup.brackets)
self?.updateTextInsets()
Expand Down Expand Up @@ -220,7 +224,7 @@ extension TextViewController {
self.findViewController?.showFindPanel()
return nil
case (0, "\u{1b}"): // Escape key
self.findViewController?.findPanel.dismiss()
self.findViewController?.hideFindPanel()
return nil
case (_, _):
return event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ extension TextViewController {
gutterView.selectedLineTextColor = nil
gutterView.selectedLineColor = .clear
}
gutterView.showFoldingRibbon = showFoldingRibbon
}

/// Style the scroll view.
Expand Down Expand Up @@ -96,7 +97,11 @@ extension TextViewController {
minimapView.scrollView.contentInsets.bottom += additionalTextInsets?.bottom ?? 0

// Inset the top by the find panel height
let findInset = (findViewController?.isShowingFindPanel ?? false) ? FindPanel.height : 0
let findInset: CGFloat = if findViewController?.viewModel.isShowingFindPanel ?? false {
findViewController?.viewModel.panelHeight ?? 0
} else {
0
}
scrollView.contentInsets.top += findInset
minimapView.scrollView.contentInsets.top += findInset

Expand Down
Loading