修改NSTextStorage引起插入点移动到行的结尾(Modifying NSTextStorag

2019-06-27 10:52发布

我有一个NSTextView作为它的子类NSTextStorage委托。 我试图做两件事情:

  1. 突出显示在某些方面的文本
  2. 评估文本,然后追加答案TextView的。

我在两种不同的方法,无论是通过调用这样做- (void)textStorageWillProcessEditing:(NSNotification *)notification委托回调。

我可以做语法高亮就好了,但是当涉及到追加我的答案, 将插入点跳转到该行的结束 ,我真的不知道为什么。 我的评价方法如下所示:

NSString *result = ..;
NSRange lineRange = [[textStorage string] lineRangeForRange:[self selectedRange]];
NSString *line = [[textStorage string] substringWithRange:lineRange];
line = [self appendResult:result toLine:line]; // appends the answer

[textStorage replaceCharactersInRange:lineRange withString:line];

这样做,将追加我的成绩不错,但问题是,如前所述,将插入点跳转到最后。

我试过了:

  1. 包裹在那些上述调[textStorage beginEditing]-endEditing
  2. 改变文本存储,所以我可以事后重置之前保存的选择范围(即插入点),但没有骰子。

我这样做对吗? 我想这样做至少hackish的方式,而且我也不能确定这是否是理想的地方做我的解析/高亮。 该文档使我相信这一点,但也许这是错误的。

Answer 1:

我知道这个问题已经早就回答了,但我有完全一样的问题。 在我NSTextStorage子我是做了以下内容:

- (void)processEditing {
    //Process self.editedRange and apply styles first
    [super processEditing];
}

但是,做正确的事情是这样的:

- (void)processEditing {
    [super processEditing];
    //Process self.editedRange and apply styles after calling superclass method
}


Answer 2:

原因将插入点移动

令人惊奇的是,我从来没有发现一个实际的解释为什么这些建议做(或没有)的工作。

挖掘到它,因为将插入点移动的理由是: .editedCharactersNSTextStorageEditedCharacters在ObjC)影响将插入点从位置NSLayoutManager.processEditing(from:editedMask:...)

如果只有.editedAttributes / NSTextStorageEditedAttributes发送,插入点不会被感动。 这是你想要的东西来实现,当你强调:只有改变属性。

为什么要突出影响将插入点

与突出这里的问题是, NSTextStorage收集所有edited单个处理运行期间调用和结合范围内,与所述用户编辑的变化开始(例如打字时的插入),则形成的这种联合,并通过报告的所有范围addAttributes(_:range:) 。 这导致在一个单一的NSLayoutManager.processEditing(from:editedMask:...)调用-与editedMask两者[.editedCharacters, .editedAttributes]

所以,你.editedAttributes突出显示的范围,但最终形成了工会.editedCharacters代替。 该联盟将插入点移动waaaaaaaay超越它应该去。

在更改顺序processEditing调用超的首部作品,因为布局管理器会通知最终编辑。 但是这种方法仍然会打破一些边缘情况,导致无效的布局或轻摇滚动景色,而你输入非常大的段落。

这是挂接到真正NSTextStorageDelegate ,也顺便说一下。

勾成回调后的布局已经完成真正触发加亮,而不是processEditing

将工作稳健基础上的Cocoa框架内在原因,唯一的解决办法是执行从突出textDidChange(_:)唯一的,布局处理后,即真正已经完成。 订阅NSTextDidChangeNotification工作一样好。

缺点:你必须触发方案变动凸显通行证基础字符串,因为这些不会调用textDidChange(_:)回调。


如果你想了解更多有关该问题的根源,我把更多的我的研究,不同的方法和解决方案的细节在更长的博客文章以供参考。 这篇文章仍然是本身就是一个独立的解决方案: http://christiantietze.de/posts/2017/11/syntax-highlight-nstextstorage-insertion-point-change/



Answer 3:

这很简单! 我最终打破这个问题分为两个部分。 我还是我的语法高亮显示的结果textStorage委托回调,但现在我做我的评价和其他地方附加。

我结束了覆盖两个-insertText:-deleteBackwards:我可能还需要做同样的-deleteForwards:太)。 两个覆盖如下所示:

- (void)insertText:(id)insertString {
    [super insertText:insertString];
    NSRange selectedRange = [self selectedRange];
    [self doEvaluationAndAppendResult];
    [self setSelectedRange:selectedRange];
}

我最后不得不将插入点手动在这里重置。 我仍然希望找出为什么这是必要的,但至少这种感觉就像少了黑客攻击。



文章来源: Modifying NSTextStorage causes insertion point to move to the end of the line