Skip to content

Commit

Permalink
Add contentInsets Parameter (CodeEditApp#141)
Browse files Browse the repository at this point in the history
# Description

This PR adds a `contentInsets` parameter that lets users set an inset
object for the editor. It also updates `STTextView` to be able to set
the left inset correctly. When left `nil` the scroll view will use
automatic insets.

This also doesn't override the overscroll option, but rather adds the
overscroll after the insets are applied.

# Related Issues

- [Discord
discussion](https://canary.discord.com/channels/951544472238444645/954084547694325861/1075085722211581952)
- [STTextView
commit](krzyzanowskim/STTextView@06d8f33)

# Screenshots

Adding top and left insets:
<img width="741" alt="Screenshot 2023-02-14 at 3 09 57 PM"
src="https://user-images.githubusercontent.com/35942988/218863914-8869e185-cd21-45a7-a7aa-58387ea778ea.png">

Adding left and bottom insets (scroller is also inset):
<img width="835" alt="Screenshot 2023-02-14 at 3 10 15 PM"
src="https://user-images.githubusercontent.com/35942988/218863899-99d2b124-fc96-418a-9869-d6897a7baea4.png">
  • Loading branch information
thecoolwinter authored Feb 15, 2023
1 parent 14f82ff commit d83b449
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 7 deletions.
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

0 comments on commit d83b449

Please sign in to comment.