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

EditorView.attributedText problem #286

Open
easiwriter opened this issue Feb 27, 2024 · 6 comments
Open

EditorView.attributedText problem #286

easiwriter opened this issue Feb 27, 2024 · 6 comments

Comments

@easiwriter
Copy link

easiwriter commented Feb 27, 2024

EditorView.attributedText before assignment is:

A
{
    NSColor = "<UIDynamicCatalogSystemColor: 0x60000179cd80; name = labelColor>";
    NSFont = "<UICTFont: 0x10a173dc0> font-family: \"Helvetica Neue\"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"largeTitle\"), id: Optional(\"DD7AE374-223F-4B4C-B0B1-2BE741DC1C00\"))";
}

The new value being assigned has an additional paragraph and is:

A{
    NSColor = "<UIDynamicCatalogSystemColor: 0x60000179cd80; name = labelColor>";
    NSFont = "<UICTFont: 0x10a173dc0> font-family: \"Helvetica Neue\"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"largeTitle\"), id: Optional(\"DD7AE374-223F-4B4C-B0B1-2BE741DC1C00\"))";
}
{
    NSColor = "<UIDynamicCatalogSystemColor: 0x60000179cd80; name = labelColor>";
    NSFont = "<UICTFont: 0x108a27ca0> font-family: \"Helvetica Neue\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment Left, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"body\"), id: Optional(\"205B7720-ECA2-4820-9B00-CA98B30AB221\"))";
}

After assignment the value is:

A{
    NSColor = "<UIDynamicCatalogSystemColor: 0x60000179cd80; name = labelColor>";
    NSFont = "<UICTFont: 0x10a173dc0> font-family: \"Helvetica Neue\"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"largeTitle\"), id: Optional(\"DD7AE374-223F-4B4C-B0B1-2BE741DC1C00\"))";
}
{
    NSColor = "<UIDynamicCatalogSystemColor: 0x60000179cd80; name = labelColor>";
    NSFont = "<UICTFont: 0x108a27ca0> font-family: \"Helvetica Neue\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"body\"), id: Optional(\"205B7720-ECA2-4820-9B00-CA98B30AB221\"))";
}

For some reason that I cannot work out the alignment in the second paragraph has been changed from left to centre. I'm sure it is obvious, but I can't see it.

@easiwriter
Copy link
Author

I have hit a similar problem and I think this is all down to the setter in public var attributedText: NSAttributedString

I have the following code:

 extension EditorView {
    func setAttributedText(_ text: NSAttributedString) {
        let selection = selectedRange
        attributedText = text
        selectedRange = selection
    }
 }

When this is called with text (for example) set to the value:

O{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600001794d80; name = labelColor>";
    NSFont = "<UICTFont: 0x10bf38840> font-family: \"Helvetica Neue\"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"largeTitle\"), id: Optional(\"DD7AE374-223F-4B4C-B0B1-2BE741DC1C00\"))";
}ne{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600001794d80; name = labelColor>";
    NSFont = "<UICTFont: 0x10c04fd30> font-family: \"Helvetica Neue\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment Left, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection LeftToRight, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    NSUnderline = 0;
}

It calls the setter which contains the lines:

 // Clear text before setting new value to avoid issues with formatting/layout when
 // editor is hosted in a scrollable container and content is set multiple times.
 richTextView.attributedText = NSAttributedString()

And that I think is the source of my problem - this, as it says, clears the text. The moment it does this it invokes textViewDidChangeSelection, which in turn ends up back in my code responding to the selection change. This all happens before the setter assigns the new value in:

richTextView.attributedText = newValue

Unfortunately my code has operated on the incorrect attributed string. This, I'm afraid, is a bit of a show stopper.

@rajdeep
Copy link
Owner

rajdeep commented Feb 29, 2024

@easiwriter, I am not sure if I am getting it fully. Just to share some context: this code, as comment states, is added to circumvent the issue of layout in UITextView. Please note that in case of simple text, this issue is not aggravated. However, when you have a large complex document with custom attributes and a lot of attachments, it has some inconsistent behaviour. In absence of this code, if there is some text with some formatting in the textview and then you reset some other text, in some cases, depending on the attributes it yields unexpected results - possibly trying to merge attributes at the same range. Furthermore, I observed that it also resulted in crashes in some specific cases as the layout calculations in that scenario get corrupted with old and new overlap.

Getting back to textViewDidChangeSelection invocation, if you notice when the text is cleared, the range is .zero and attributedText is also empty. Do you think you can have a check on your code to ignore or process based on this condition? Alternatively, if you help me understand what you are trying to do and the issue that this change causes, I may be able to provide additional info/callbacks that you can use so that you can ignore executing the code that you wish to prevent in such a case.

@rajdeep
Copy link
Owner

rajdeep commented Feb 29, 2024

also, not sure if this is relevant for you in this case, but you should know that the text is set only when Editor is already in a Window or when it moves to a Window. Please see the details here.

@easiwriter
Copy link
Author

I've added a flag which is set before assigning to attributedText such that any call backs to change selection are ignored. The code in the setter now gets to line 527 in the attributedText setter. At the line:

richTextView.attributedText = newValue

the newValue is correct.

A{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600001784340; name = labelColor>";
    NSFont = "<UICTFont: 0x10ee37900> font-family: \"Helvetica Neue\"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"largeTitle\"), id: Optional(\"DAF9DAC4-5D4F-437A-B2B9-C8DCC6577DFC\"))";
}
{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600001784340; name = labelColor>";
    NSFont = "<UICTFont: 0x11137a590> font-family: \"Helvetica Neue\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment Left, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"body\"), id: Optional(\"51601A2C-0B6D-41B1-A05A-0219F541D050\"))";
}

The input text consists of the letter A followed by a newline. The app implements a style mechanism to control formatting. Instead of fiddling with formatting commands the user simply chooses a style from a menu. In the example above the letter A is formatted according to the attributes of LargeTitle. The style name is held as the custom attribute

WriteStyle = "Write_.StyleIdentifier(name: Optional(\"largeTitle\")

The second paragraph is set to the body style as shown by its style attribute.

This is where things go wrong. The newValue as I said is correct and the alignment of the second paragraph is Alignment Left. I had just changed this paragraph to use the body style.

However, the code below at RichTextView line 82 changes the alignment to Alignment Centre.

    override var attributedText: NSAttributedString! {
        willSet {
            // Remove all attachment subviews else we may run into PRTextStorage "in middle of editing" crash
            subviews.filter { $0 is AttachmentContentView }.forEach { $0.removeFromSuperview() }
        }
    }

Here is the text after this method is called

A{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600001789840; name = labelColor>";
    NSFont = "<UICTFont: 0x113340ea0> font-family: \"Helvetica Neue\"; font-weight: bold; font-style: normal; font-size: 34.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"largeTitle\"), id: Optional(\"DAF9DAC4-5D4F-437A-B2B9-C8DCC6577DFC\"))";
}
{
    NSColor = "<UIDynamicCatalogSystemColor: 0x600001789840; name = labelColor>";
    NSFont = "<UICTFont: 0x16d00c980> font-family: \"Helvetica Neue\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
    NSParagraphStyle = "Alignment Center, LineSpacing 1, ParagraphSpacing 0, ParagraphSpacingBefore 10, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 1, LineBreakMode WordWrapping, Tabs (\n    28L,\n    56L,\n    84L,\n    112L,\n    140L,\n    168L,\n    196L,\n    224L,\n    252L,\n    280L,\n    308L,\n    336L\n), DefaultTabInterval 0, Blocks (\n), Lists (\n), BaseWritingDirection Natural, HyphenationFactor 0, TighteningForTruncation NO, HeaderLevel 0 LineBreakStrategy 0 PresentationIntents (\n) ListIntentOrdinal 0 CodeBlockIntentLanguageHint ''";
    NSStrikethrough = 0;
    WriteStyle = "Write_.StyleIdentifier(name: Optional(\"body\"), id: Optional(\"51601A2C-0B6D-41B1-A05A-0219F541D050\"))";
}

I don't understand what is going on here because there is only one view, the one containing the text. The app only has a single EditorView. I can only assume that the code has somehow used the alignment of the first paragraph.

What is really don't understand is this is not new code. It was working OK before I took a rest for a few months, so I don't know if the changes to AttributedText (here and in the calling method) have been made during this period. If so this would account for the problems I'm now having.

@rajdeep
Copy link
Owner

rajdeep commented Mar 3, 2024

the code you have referenced here:

    override var attributedText: NSAttributedString! {
        willSet {
            // Remove all attachment subviews else we may run into PRTextStorage "in middle of editing" crash
            subviews.filter { $0 is AttachmentContentView }.forEach { $0.removeFromSuperview() }
        }
    }

has noting to do with attributedText or alignments of paragraph. This is specifically removing subviews added to the Editor via Attachment. If I understand it correctly, you are not using any attachments so this code should be of no consequence to you.

Over the past few months, I have been making a lot of updates to Proton which are primarily geared towards fixing bugs and performance issues. There may have been a change or a fix to a bug that is now causing a bug in your code or I might have accidentally fixed one bug and introduced another. I think we can do the following here:

  1. If it helps, please have a look at the Release Notes here for the time you were not actively developing the app and see if there's something obvious that shows up.
  2. If possible, please create a failing unit test case with your scenario and the expected output. If I have a failing test case, it will be much easier for me to provide a fix or advise if there's something that you may need to do differently.

Also, there is no code at all in Proton anywhere that changes the alignment of Paragraph to center. The only code around alignment that is there is in regards to the default paragraphStyle that you can set on the Editor which is automatically applied if the editor has some content and then entire content is deleted using backspace/select and delete.

@easiwriter
Copy link
Author

easiwriter commented Mar 3, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants