Skip to content
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
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ let package = Package(
dependencies: [
.package(
url: "https://github.com/krzyzanowskim/STTextView.git",
exact: "0.4.0"
from: "0.4.1"
),
.package(
url: "https://github.com/CodeEditApp/CodeEditLanguages.git",
Expand Down
11 changes: 9 additions & 2 deletions Sources/CodeEditTextView/CodeEditTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
/// - editorOverscroll: The percentage for overscroll, between 0-1 (default: `0.0`)
/// - highlightProvider: A class you provide to perform syntax highlighting. Leave this as `nil` to use the
/// built-in `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.
public init(
_ text: Binding<String>,
language: CodeLanguage,
Expand All @@ -36,7 +38,8 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
editorOverscroll: Binding<Double> = .constant(0.0),
cursorPosition: Published<(Int, Int)>.Publisher? = nil,
useThemeBackground: Bool = true,
highlightProvider: HighlightProviding? = nil
highlightProvider: HighlightProviding? = nil,
contentInsets: NSEdgeInsets? = nil
) {
self._text = text
self.language = language
Expand All @@ -49,6 +52,7 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
self._editorOverscroll = editorOverscroll
self.cursorPosition = cursorPosition
self.highlightProvider = highlightProvider
self.contentInsets = contentInsets
}

@Binding private var text: String
Expand All @@ -62,6 +66,7 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
private var cursorPosition: Published<(Int, Int)>.Publisher?
private var useThemeBackground: Bool
private var highlightProvider: HighlightProviding?
private var contentInsets: NSEdgeInsets?

public typealias NSViewControllerType = STTextViewController

Expand All @@ -76,7 +81,8 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
cursorPosition: cursorPosition,
editorOverscroll: editorOverscroll,
useThemeBackground: useThemeBackground,
highlightProvider: highlightProvider
highlightProvider: highlightProvider,
contentInsets: contentInsets
)
controller.lineHeightMultiple = lineHeight
return controller
Expand All @@ -89,6 +95,7 @@ public struct CodeEditTextView: NSViewControllerRepresentable {
controller.useThemeBackground = useThemeBackground
controller.lineHeightMultiple = lineHeight
controller.editorOverscroll = editorOverscroll
controller.contentInsets = contentInsets

// Updating the language and theme needlessly can cause highlights to be re-calculated.
if controller.language.id != language.id {
Expand Down
23 changes: 19 additions & 4 deletions Sources/CodeEditTextView/STTextViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
/// Filters used when applying edits..
internal var textFilters: [TextFormation.Filter] = []

/// Optional insets to offset the text view in the scroll view by.
public var contentInsets: NSEdgeInsets?

// MARK: - Highlighting

internal var highlighter: Highlighter?
Expand All @@ -77,7 +80,8 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
cursorPosition: Published<(Int, Int)>.Publisher? = nil,
editorOverscroll: Double,
useThemeBackground: Bool,
highlightProvider: HighlightProviding? = nil
highlightProvider: HighlightProviding? = nil,
contentInsets: NSEdgeInsets? = nil
) {
self.text = text
self.language = language
Expand All @@ -89,6 +93,7 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
self.editorOverscroll = editorOverscroll
self.useThemeBackground = useThemeBackground
self.highlightProvider = highlightProvider
self.contentInsets = contentInsets
super.init(nibName: nil, bundle: nil)
}

Expand All @@ -98,6 +103,7 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt

// MARK: VC Lifecycle

// swiftlint:disable function_body_length
public override func loadView() {
textView = STTextView()

Expand All @@ -106,6 +112,10 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
scrollView.hasVerticalScroller = true
scrollView.documentView = textView
scrollView.drawsBackground = useThemeBackground
scrollView.automaticallyAdjustsContentInsets = contentInsets == nil
if let contentInsets = contentInsets {
scrollView.contentInsets = contentInsets
}

rulerView = STLineNumberRulerView(textView: textView, scrollView: scrollView)
rulerView.backgroundColor = useThemeBackground ? theme.background : .clear
Expand Down Expand Up @@ -218,9 +228,14 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
rulerView?.separatorColor = theme.invisibles
rulerView?.baselineOffset = baselineOffset

(view as? NSScrollView)?.drawsBackground = useThemeBackground
(view as? NSScrollView)?.backgroundColor = useThemeBackground ? theme.background : .clear
(view as? NSScrollView)?.contentView.contentInsets.bottom = bottomContentInsets
if let scrollView = view as? NSScrollView {
scrollView.drawsBackground = useThemeBackground
scrollView.backgroundColor = useThemeBackground ? theme.background : .clear
if let contentInsets = contentInsets {
scrollView.contentInsets = contentInsets
}
scrollView.contentInsets.bottom = bottomContentInsets + (contentInsets?.bottom ?? 0)
}

setStandardAttributes()
}
Expand Down
46 changes: 46 additions & 0 deletions Tests/CodeEditTextViewTests/STTextViewControllerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ final class STTextViewControllerTests: XCTestCase {
width: 100,
height: 100)

controller.editorOverscroll = 0
controller.contentInsets = nil
controller.reloadUI()

// editorOverscroll: 0
XCTAssertEqual(scrollView.contentView.contentInsets.bottom, 0)

Expand All @@ -86,6 +90,48 @@ final class STTextViewControllerTests: XCTestCase {
XCTAssertEqual(scrollView.contentView.contentInsets.bottom, 87.0)
}

func test_editorInsets() throws {
let scrollView = try XCTUnwrap(controller.view as? NSScrollView)
scrollView.frame = .init(x: .zero,
y: .zero,
width: 100,
height: 100)

func assertInsetsEqual(_ lhs: NSEdgeInsets, _ rhs: NSEdgeInsets) throws {
XCTAssertEqual(lhs.top, rhs.top)
XCTAssertEqual(lhs.right, rhs.right)
XCTAssertEqual(lhs.bottom, rhs.bottom)
XCTAssertEqual(lhs.left, rhs.left)
}

controller.editorOverscroll = 0
controller.contentInsets = nil
controller.reloadUI()

// contentInsets: 0
try assertInsetsEqual(scrollView.contentInsets, NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))

// contentInsets: 16
controller.contentInsets = NSEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
controller.reloadUI()

try assertInsetsEqual(scrollView.contentInsets, NSEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))

// contentInsets: different
controller.contentInsets = NSEdgeInsets(top: 32.5, left: 12.3, bottom: 20, right: 1)
controller.reloadUI()

try assertInsetsEqual(scrollView.contentInsets, NSEdgeInsets(top: 32.5, left: 12.3, bottom: 20, right: 1))

// contentInsets: 16
// editorOverscroll: 0.5
controller.contentInsets = NSEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
controller.editorOverscroll = 0.5
controller.reloadUI()

try assertInsetsEqual(scrollView.contentInsets, NSEdgeInsets(top: 16, left: 16, bottom: 16 + 50, right: 16))
}

func test_editorOverScroll_ZeroCondition() throws {
let scrollView = try XCTUnwrap(controller.view as? NSScrollView)
scrollView.frame = .zero
Expand Down