Skip to content

🐞 CodeEditTextView Does Not Update When Binding Changes Programmatically #213

Closed

Description

@nkleemann

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

Activity

  1. thecoolwinter commented on Dec 9, 2023

    @thecoolwinter
    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.

  2. moved this from 🆕 New to 🏁 Complete in CodeEdit Projecton Dec 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions