|
7 | 7 |
|
8 | 8 | import AppKit
|
9 | 9 | import SwiftUI
|
| 10 | +import Combine |
10 | 11 | import STTextView
|
11 | 12 | import SwiftTreeSitter
|
12 | 13 |
|
@@ -47,13 +48,20 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
|
47 | 48 |
|
48 | 49 | // MARK: Init
|
49 | 50 |
|
50 |
| - public init(text: Binding<String>, language: CodeLanguage, font: NSFont, theme: EditorTheme, tabWidth: Int) { |
| 51 | + public init( |
| 52 | + text: Binding<String>, |
| 53 | + language: CodeLanguage, |
| 54 | + font: NSFont, |
| 55 | + theme: EditorTheme, |
| 56 | + tabWidth: Int, |
| 57 | + cursorPosition: Published<(Int, Int)>.Publisher? = nil |
| 58 | + ) { |
51 | 59 | self.text = text
|
52 | 60 | self.language = language
|
53 | 61 | self.font = font
|
54 | 62 | self.theme = theme
|
55 | 63 | self.tabWidth = tabWidth
|
56 |
| - |
| 64 | + self.cursorPosition = cursorPosition |
57 | 65 | super.init(nibName: nil, bundle: nil)
|
58 | 66 | }
|
59 | 67 |
|
@@ -124,6 +132,10 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
|
124 | 132 | }
|
125 | 133 |
|
126 | 134 | setUpHighlighting()
|
| 135 | + |
| 136 | + self.cursorPositionCancellable = self.cursorPosition?.sink(receiveValue: { value in |
| 137 | + self.setCursorPosition(value) |
| 138 | + }) |
127 | 139 | }
|
128 | 140 |
|
129 | 141 | internal func setUpHighlighting() {
|
@@ -223,6 +235,35 @@ public class STTextViewController: NSViewController, STTextViewDelegate, ThemeAt
|
223 | 235 | keyIsDown = false
|
224 | 236 | }
|
225 | 237 |
|
| 238 | + // MARK: Cursor Position |
| 239 | + |
| 240 | + private var cursorPosition: Published<(Int, Int)>.Publisher? |
| 241 | + private var cursorPositionCancellable: AnyCancellable? |
| 242 | + |
| 243 | + private func setCursorPosition(_ position: (Int, Int)) { |
| 244 | + guard let provider = textView.textLayoutManager.textContentManager else { |
| 245 | + return |
| 246 | + } |
| 247 | + |
| 248 | + var (line, column) = position |
| 249 | + let string = textView.string |
| 250 | + if line > 0 { |
| 251 | + string.enumerateSubstrings(in: string.startIndex..<string.endIndex) { _, lineRange, _, done in |
| 252 | + line -= 1 |
| 253 | + if line < 1 { |
| 254 | + // If `column` exceeds the line length, set cursor to the end of the line. |
| 255 | + let index = min(lineRange.upperBound, string.index(lineRange.lowerBound, offsetBy: column - 1)) |
| 256 | + if let newRange = NSTextRange(NSRange(index..<index, in: string), provider: provider) { |
| 257 | + self.textView.setSelectedRange(newRange) |
| 258 | + } |
| 259 | + done = true |
| 260 | + } else { |
| 261 | + done = false |
| 262 | + } |
| 263 | + } |
| 264 | + } |
| 265 | + } |
| 266 | + |
226 | 267 | deinit {
|
227 | 268 | textView = nil
|
228 | 269 | highlighter = nil
|
|
0 commit comments