From 61899c33d276578a691b86dafe8589bdc8a69e38 Mon Sep 17 00:00:00 2001 From: Khan Winter <35942988+thecoolwinter@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:23:06 -0500 Subject: [PATCH 1/2] Update CodeEditTextView to `0.12.0` --- .../xcshareddata/swiftpm/Package.resolved | 9 +++++ .../Views/ContentView.swift | 2 +- .../Views/StatusBar.swift | 8 +++-- Package.swift | 2 +- .../TextView+/TextView+TextFormation.swift | 5 +-- .../Highlighting/Highlighter.swift | 2 +- .../Minimap/MinimapLineFragmentView.swift | 35 +++++++++++++------ 7 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c511a9f74..062be1347 100644 --- a/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,6 +18,15 @@ "version" : "0.2.3" } }, + { + "identity" : "codeedittextview", + "kind" : "remoteSourceControl", + "location" : "https://github.com/CodeEditApp/CodeEditTextView.git", + "state" : { + "revision" : "e7f1580a8075af84c349fb8c66fbd2776ff5cb1d", + "version" : "0.12.0" + } + }, { "identity" : "rearrange", "kind" : "remoteSourceControl", diff --git a/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift b/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift index 5984ab0ea..97306b73a 100644 --- a/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift +++ b/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/ContentView.swift @@ -88,7 +88,7 @@ struct ContentView: View { indentOption: $indentOption, reformatAtColumn: $reformatAtColumn, showReformattingGuide: $showReformattingGuide, - showFoldingRibbon: $showFoldingRibbon + showFoldingRibbon: $showFoldingRibbon, invisibles: $invisibleCharactersConfig, warningCharacters: $warningCharacters ) diff --git a/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift b/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift index 597dff508..40e19215b 100644 --- a/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift +++ b/Example/CodeEditSourceEditorExample/CodeEditSourceEditorExample/Views/StatusBar.swift @@ -118,9 +118,9 @@ struct StatusBar: View { .foregroundStyle(.secondary) Button { - state.findPanelVisible.toggle() + state.findPanelVisible?.toggle() } label: { - Text(state.findPanelVisible ? "Hide" : "Show") + Text(" Find") + Text(state.findPanelVisible ?? false ? "Hide" : "Show") + Text(" Find") } .buttonStyle(.borderless) .foregroundStyle(.secondary) @@ -198,7 +198,9 @@ struct StatusBar: View { /// Create a label string for cursor positions. /// - Parameter cursorPositions: The cursor positions to create the label for. /// - Returns: A string describing the user's location in a document. - func getLabel(_ cursorPositions: [CursorPosition]) -> String { + func getLabel(_ cursorPositions: [CursorPosition]?) -> String { + guard let cursorPositions else { return "No cursor" } + if cursorPositions.isEmpty { return "No cursor" } diff --git a/Package.swift b/Package.swift index 6b75d660c..1fc3520aa 100644 --- a/Package.swift +++ b/Package.swift @@ -17,7 +17,7 @@ let package = Package( // A fast, efficient, text view for code. .package( url: "https://github.com/CodeEditApp/CodeEditTextView.git", - from: "0.11.4" + from: "0.12.0" ), // tree-sitter languages .package( diff --git a/Sources/CodeEditSourceEditor/Extensions/TextView+/TextView+TextFormation.swift b/Sources/CodeEditSourceEditor/Extensions/TextView+/TextView+TextFormation.swift index 853773412..a3cccd19e 100644 --- a/Sources/CodeEditSourceEditor/Extensions/TextView+/TextView+TextFormation.swift +++ b/Sources/CodeEditSourceEditor/Extensions/TextView+/TextView+TextFormation.swift @@ -10,7 +10,8 @@ import CodeEditTextView import TextStory import TextFormation -extension TextView: TextInterface { +extension TextView: @retroactive TextStoring {} +extension TextView: @retroactive TextInterface { public var selectedRange: NSRange { get { return selectionManager @@ -45,6 +46,6 @@ extension TextView: TextInterface { in: mutation.range, replacementLength: (mutation.string as NSString).length ) - layoutManager.setNeedsLayout() + layoutManager.invalidateLayoutForRange(mutation.range) } } diff --git a/Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift b/Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift index 21c33e343..9f1e70ea4 100644 --- a/Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift +++ b/Sources/CodeEditSourceEditor/Highlighting/Highlighter.swift @@ -214,7 +214,7 @@ class Highlighter: NSObject { // MARK: NSTextStorageDelegate -extension Highlighter: NSTextStorageDelegate { +extension Highlighter: @preconcurrency NSTextStorageDelegate { /// Processes an edited range in the text. func textStorage( _ textStorage: NSTextStorage, diff --git a/Sources/CodeEditSourceEditor/Minimap/MinimapLineFragmentView.swift b/Sources/CodeEditSourceEditor/Minimap/MinimapLineFragmentView.swift index e148a0e76..c77e12164 100644 --- a/Sources/CodeEditSourceEditor/Minimap/MinimapLineFragmentView.swift +++ b/Sources/CodeEditSourceEditor/Minimap/MinimapLineFragmentView.swift @@ -43,25 +43,40 @@ final class MinimapLineFragmentView: LineFragmentView { /// Set the new line fragment, and calculate drawing runs for drawing the fragment in the view. /// - Parameter newFragment: The new fragment to use. - override func setLineFragment(_ newFragment: LineFragment, renderer: LineFragmentRenderer) { - super.setLineFragment(newFragment, renderer: renderer) + override func setLineFragment(_ newFragment: LineFragment, fragmentRange: NSRange, renderer: LineFragmentRenderer) { + super.setLineFragment(newFragment, fragmentRange: fragmentRange, renderer: renderer) guard let textStorage else { return } + let fragmentRange = newFragment.documentRange // Create the drawing runs using attribute information - var position = newFragment.documentRange.location + var position = fragmentRange.location for contentRun in newFragment.contents { switch contentRun.data { case .text: - addDrawingRunsUntil(max: position + contentRun.length, position: &position, textStorage: textStorage) + addDrawingRunsUntil( + max: position + contentRun.length, + position: &position, + textStorage: textStorage, + fragmentRange: fragmentRange + ) case .attachment(let attachment): position += attachment.range.length - appendDrawingRun(color: .clear, range: NSRange(location: position, length: contentRun.length)) + appendDrawingRun( + color: .clear, + range: NSRange(location: position, length: contentRun.length), + fragmentRange: fragmentRange + ) } } } - private func addDrawingRunsUntil(max: Int, position: inout Int, textStorage: NSTextStorage) { + private func addDrawingRunsUntil( + max: Int, + position: inout Int, + textStorage: NSTextStorage, + fragmentRange: NSRange + ) { while position < max { var longestRange: NSRange = .notFound defer { position = longestRange.max } @@ -83,7 +98,7 @@ final class MinimapLineFragmentView: LineFragmentView { if let scalar = UnicodeScalar(char), CharacterSet.whitespacesAndNewlines.contains(scalar) { // Whitespace if range != .notFound { - appendDrawingRun(color: foregroundColor, range: range) + appendDrawingRun(color: foregroundColor, range: range, fragmentRange: fragmentRange) range = .notFound } } else { @@ -97,7 +112,7 @@ final class MinimapLineFragmentView: LineFragmentView { } if range != .notFound { - appendDrawingRun(color: foregroundColor, range: range) + appendDrawingRun(color: foregroundColor, range: range, fragmentRange: fragmentRange) } } } @@ -106,12 +121,12 @@ final class MinimapLineFragmentView: LineFragmentView { /// - Parameters: /// - color: The color of the run, will have opacity applied by this method. /// - range: The range, relative to the document. Will be normalized to the fragment by this method. - private func appendDrawingRun(color: NSColor, range: NSRange) { + private func appendDrawingRun(color: NSColor, range: NSRange, fragmentRange: NSRange) { drawingRuns.append( Run( color: color.withAlphaComponent(0.4), range: NSRange( - location: range.location - (lineFragment?.documentRange.location ?? 0), + location: range.location - fragmentRange.location, length: range.length ) ) From 2fe2d25eff9ccaafe857da9243c80a09bfee2ea1 Mon Sep 17 00:00:00 2001 From: Khan Winter <35942988+thecoolwinter@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:26:22 -0500 Subject: [PATCH 2/2] Remove Warnings --- .../Extensions/NSEdgeInsets/NSEdgeInsets+Equatable.swift | 2 +- Tests/CodeEditSourceEditorTests/RangeStoreTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/CodeEditSourceEditor/Extensions/NSEdgeInsets/NSEdgeInsets+Equatable.swift b/Sources/CodeEditSourceEditor/Extensions/NSEdgeInsets/NSEdgeInsets+Equatable.swift index dbdcdca23..38911245f 100644 --- a/Sources/CodeEditSourceEditor/Extensions/NSEdgeInsets/NSEdgeInsets+Equatable.swift +++ b/Sources/CodeEditSourceEditor/Extensions/NSEdgeInsets/NSEdgeInsets+Equatable.swift @@ -7,7 +7,7 @@ import Foundation -extension NSEdgeInsets: Equatable { +extension NSEdgeInsets: @retroactive Equatable { public static func == (lhs: NSEdgeInsets, rhs: NSEdgeInsets) -> Bool { lhs.bottom == rhs.bottom && lhs.top == rhs.top && diff --git a/Tests/CodeEditSourceEditorTests/RangeStoreTests.swift b/Tests/CodeEditSourceEditorTests/RangeStoreTests.swift index a065d3f7c..1603a6487 100644 --- a/Tests/CodeEditSourceEditorTests/RangeStoreTests.swift +++ b/Tests/CodeEditSourceEditorTests/RangeStoreTests.swift @@ -14,7 +14,7 @@ struct RangeStoreTests { func initWithLength() { for _ in 0..<100 { let length = Int.random(in: 0..<1000) - var store = Store(documentLength: length) + let store = Store(documentLength: length) #expect(store.length == length) } }