Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐞 CodeEditTextView Does Not Update When Binding Changes Programmatically #213

Closed
nkleemann opened this issue Nov 14, 2023 · 1 comment
Labels
bug Something isn't working

Comments

@nkleemann
Copy link

nkleemann commented Nov 14, 2023

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

@nkleemann nkleemann added the bug Something isn't working label Nov 14, 2023
@thecoolwinter
Copy link
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
Status: 🏁 Complete
Development

No branches or pull requests

2 participants