๐ CodeEditTextView Does Not Update When Binding Changes Programmatically
Closed this issue ยท 1 comments
Description
When trying to programmatically insert text at the cursor position (or anywhere) in a CodeEditTextView, there is an observed issue where the data model (the text binding) updates as expected, but these changes are not reflected in the CodeEditTextView. This occurs when the binding changes are made programmatically, without any key presses.
To help debugging this I created a minimal example. As you can see, when appending content to the code
Binding, neither the cursor position nor the code displayed in the View updates as expected.
struct ContentView: View {
// text we want to programmatically append
@State var codeToAppend = ""
// managed by editor
@State var code = ""
@State var cursorPosition = (1, 1)
var body: some View {
VStack {
HStack {
TextField("code to append..", text: $codeToAppend)
Button {
self.code.append(codeToAppend)
} label: {
Text("append")
}
}
CodeEditTextView(
$code,
language: .swift,
theme: Foo.theme,
font: Foo.font,
tabWidth: Foo.tabWidth,
lineHeight: Foo.lineHeight,
wrapLines: Foo.wrapLines,
editorOverscroll: Foo.editorOverscroll,
cursorPosition: $cursorPosition
)
HStack {
Text("line: \(cursorPosition.0) col: \(cursorPosition.1)")
Text("# of chars in editor: \(code.count)")
}
}
.padding()
}
}
// ignore
struct Foo {
static let theme = EditorTheme(
text: .init(hex: "#F6F7EE"),
insertionPoint: .init(hex: "#9E9F9D"),
invisibles: .init(hex: "#343b59", alpha: 0.6),
background: .init(hex: "#000000"),
lineHighlight: .init(hex: "#151515", alpha: 0.3),
selection: .init(hex: "#A5CDFF"),
keywords: .init(hex: "#F074D5"),
commands: .init(hex: "#34548a"),
types: .init(hex: "#8f5e15"),
attributes: .init(hex: "#9399FF"),
variables: .init(hex: "#9399FF"),
values: .init(hex: "#9399FF"),
numbers: .init(hex: "#67B7A4"),
strings: .init(hex: "#67B7A4"),
characters: .init(hex: "#0f4b6e"),
comments: .init(hex: "#414141")
)
static let font = NSFont.monospacedSystemFont(ofSize: 11, weight: .regular)
static let tabWidth = 4
static let lineHeight = 1.2
static let editorOverscroll = 0.3
static let wrapLines = true
}
To Reproduce
Use my provided, minimal example.
Expected Behavior
Changes to the underlying Bindings (code and cursor position) should be reflected in the View. This will become especially important when developing autocompletion features.
Version Information
CodeEditTextView: [e.g. 0.x.y]
macOS: [e.g. 13.2.1]
Xcode: [e.g. 14.2]
Additional Context
No response
Screenshots
No response
The cursor position binding has been fixed in #211.
Due to SwiftUI limitations, allowing the text binding to be reversible (eg: updated from outside the view) would mean having to reload the view's contents every time SwiftUI decides to update the view. This could be negated if we had means to determine if a view update was due to an update from the text binding, but there is no API for that.
Instead, we're introducing a new API for updating the view's text programmatically using TextCoordinator
's. These are a protocol that developers can provide one or more instances of to CodeEditTextView to receive notifications for events in the view, or capture a reference to the view controller and update text without a binding. We've merged the first version of this API on the main branch, and we'll be making a tagged release soon. We'll also have some more detailed docs with examples, but there is already documentation available here.