Modifying NSTextStorage attributes causes scroll view to jump around
Asked Answered
C

4

7

I have implemented basic syntax highlighting by properly setting the NSTextStorage delegate of my NSTextView and changing the text attributes in -textStorageDidProcessEditing.

The basic process is as follows

- (void)textStorageDidProcessEditing:(NSNotification *)notification {
  NSTextStorage *storage = [notification object];
  [storage beginEditing];

  NSString *text = [storage string];
  NSRange textRange = NSMakeRange(0, [text length]);

  [storage removeAttribute:NSForegroundColorAttributeName range:textRange];

  // Some regex matching here ...

  [storage addAttribute:NSForegroundColorAttributeName
                  value:[COSyntax colorForPatternGroup:pattern.groupName]
                  range:capturedRanges[group]];

  [storage endEditing];
}

Whenever -removeAttribute:range: or -addAttribute:value:range is invoked when a SPACE character is entered, the NSTextViews surrounding NSScrollView location begins to jump around (scroll knob goes to some random position near the )

What's causing this?

Consensual answered 16/3, 2011 at 10:17 Comment(0)
H
14

I have finally found out from my observations that the jumping happens not only when pressing spacebar but for other keys such as backspace as well and this happens exactly when both of these happen.
- Non-contiguous layout is turned on
- Any modification, even to attributes, of text preceding the visible region is made inside -textStorageDidProcessEditing:
Looks like it is a bug in Non-contiguous layout feature! Would be good if an expert could confirm.
It appears to have nothing to do with calling -beginEditing and -endEditing.

Hardie answered 2/1, 2012 at 4:52 Comment(2)
I was doing my processing in processEditing in a custom text storage. Moving that to the delegate method solved my problem. Thanks!Garnierite
This appears to be the correct answer, and should be the accepted answer. Turning off non-contiguous layout in IB fixes the problem. Other proposed fixes, such as using didChangeText instead, or not using beginEditing/endEditing inside textStorageDidProcessEditing:, are not a good idea, whether or not they avoid this specific bug. I have just filed this bug on Apple's bug reporter, #24539235. Please file bugs!Skimp
L
7

Eric. I don't know if you solved this. However, I ran into a similar problem and I found out that turning off "Non-contiguous layout" option in the XCode 4.x attributes inspector for the NSTextView in case will solve the problem. The documentation for NSLayoutManager provides more clues (under "Overview" section): "Noncontiguous layout is an optional layout manager behavior new in Mac OS X v10.5...".

Here's the post

In my case, I experienced this behavior irrespective of using delegate methods or intermediate methods called via notifications and happened only when the text storage content became larger than the enclosing text view, causing scrolling to be active and "pushing" the text view to the top. After turning the option off, the "jump" was no longer observed. Hope it helps. Tom

Lacedaemon answered 25/7, 2011 at 12:21 Comment(0)
C
1

Turns out calling -beginEditing and -endEditing inside a -textStorageDidProcessEditing: function is not very healthy! I switched to the NSTextViews -didChangeText instead.

Consensual answered 16/3, 2011 at 11:44 Comment(1)
This is incorrect and should not be the accepted answer. The correct answer, by trss, correctly diagnoses the problem as being related to non-contiguous layout.Skimp
G
1

textView.layoutManager?.allowsNonContiguousLayout = false

solved my problem

Guria answered 26/6, 2019 at 13:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.