HighlightedTextEditor icon indicating copy to clipboard operation
HighlightedTextEditor copied to clipboard

Initial caret size is wrong when using the `.all` rule to set the default editor font (macOS)

Open jbmorley opened this issue 9 months ago • 0 comments

DO NOT DELETE THIS TEMPLATE

If you do not fill out this template, your issue will be automatically closed.

Describe the bug

I'm using the .all convenience to set the default editor font size (as per https://github.com/kyle-n/HighlightedTextEditor/issues/63). When the editor view is first displayed, the caret size still matches the built-in default font size and doesn't adjust to the correct size until the first character is typed, causing it immediately change size as you type. I've only tested this on macOS.

To Reproduce

Please provide a small snippet of sample code and steps to reproduce the behavior. Write them like:

  1. Set up the editor with rules which specify a custom editor font:
        static var customRules: [HighlightRule] {
             let editorFont = NSFont.monospacedSystemFont(ofSize: 20.0, weight: .regular)
             return [
                 HighlightRule(pattern: .all, formattingRule: TextFormattingRule(key: .font, value: editorFont)),
                 /* ... */
             ]
         }
    
  2. Run the app.
  3. Focus the editor and observe the caret size.
  4. Start typing and notice that the caret size jumps to the larger font size.
  5. Interestingly, deleting the newly typed characters leaves the caret at the correct size, but Cmd+Z / Undo makes it small again.

Expected behavior

I expect the initial caret size to match the font provided with the .all regex.

Screenshots

Initial state with a small caret:

Screenshot 2024-05-09 at 07 43 47

State after typing with the expected caret size:

Screenshot 2024-05-09 at 07 45 34

Environment

  • macOS Sonoma 14.4.1
  • Xcode 15.3 (15E204a)
  • AppKit (native macOS app)

Additional context

I took a quick look at how this could be implemented by setting the initial editor font size to match that in a .all regex if one existed in the rules. Not sure I like the approach, but I thought I'd include it here for completeness:

public struct HighlightedTextEditor: NSViewRepresentable, HighlightingTextEditor {

    /* .... */

    public func makeNSView(context: Context) -> ScrollableTextView {
        let textView = ScrollableTextView()
        textView.delegate = context.coordinator
        let emptyString = ""
        let defaultRuleEditorFont = highlightRules
            .first { $0.pattern == NSRegularExpression.all }?
            .formattingRules
            .first { $0.key == .font }?
            .calculateValue?(emptyString, Range(uncheckedBounds: (lower: emptyString.startIndex, upper: emptyString.endIndex))) as? NSFont
        textView.textView.font = defaultRuleEditorFont ?? defaultEditorFont
        runIntrospect(textView)
        return textView
    }

    /* ... */

}

jbmorley avatar May 09 '24 17:05 jbmorley