我有一个NSTextView
子类作为其NSTextStorage
委托。我正在尝试做两件事:
我在两个不同的方法中执行此操作,均由- (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];
这样做会很好地附加我的结果,但问题是,如上所述,插入点会跳到最后。
我试过了:
[textStorage beginEditing]
和-endEditing
中调用。我这样做了吗?我试图以最少的hackish方式做到这一点,我也不确定这是否是进行解析/突出显示的理想场所。文档让我相信这一点,但也许这是错误的。
答案 0 :(得分:4)
我知道这个问题早已回答,但我确实完全同样的问题。在我的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
}
答案 1 :(得分:3)
令人惊讶的是,我从来没有找到为什么这些建议能够(或不能)发挥作用的实际解释。
深入研究,插入点移动的原因是:.editedCharacters
(ObjC中的NSTextStorageEditedCharacters
)会影响{{1}的插入点位置}。
如果仅发送NSLayoutManager.processEditing(from:editedMask:...)
/ .editedAttributes
,则不会触及插入点。这是您在突出显示时想要实现的目标:仅更改属性。
此处突出显示的问题是NSTextStorageEditedAttributes
在单个处理运行期间收集所有NSTextStorage
个调用并组合范围,从用户编辑的更改开始(例如输入时插入),然后形成edited
报告的此范围和所有范围的并集。这会导致一次addAttributes(_:range:)
次调用 - NSLayoutManager.processEditing(from:editedMask:...)
editedMask
。{/ p>
因此,希望为突出显示的范围发送[.editedCharacters, .editedAttributes]
,但最终会与.editedAttributes
形成联盟。那个联盟将插入点waaaaaaaay移动到应该去的地方。
更改.editedCharacters
中的顺序以调用超级优先,因为布局管理器将收到已完成编辑的通知。但是这种方法仍会因某些边缘情况而中断,导致无效的布局或在您输入非常大的段落时摇晃滚动视图。
This is true for hooking into NSTextStorageDelegate
。
processEditing
基于Cocoa框架固有的原因,唯一可以稳健工作的解决方案是从processEditing
专门执行突出显示,即在布局处理确实完成之后。也可以订阅textDidChange(_:)
。
下行:您必须触发突出显示传递以对基础字符串进行编程更改,因为这些不会调用NSTextDidChangeNotification
回调。
如果您想了解更多有关问题根源的信息,我会在更长的博客文章中提供更多我的研究,不同方法和解决方案的详细信息,以供参考。这篇文章本身仍然是一个独立的解决方案: http://christiantietze.de/posts/2017/11/syntax-highlight-nstextstorage-insertion-point-change/
答案 2 :(得分:0)
很简单!我最终把这个问题分成两部分。由于textStorage
委托回调,我仍然会进行语法突出显示,但现在我进行评估并附加到其他地方。
我最终覆盖了-insertText:
和-deleteBackwards:
(我可能也希望对-deleteForwards:
执行相同操作)。两个覆盖都如下所示:
- (void)insertText:(id)insertString {
[super insertText:insertString];
NSRange selectedRange = [self selectedRange];
[self doEvaluationAndAppendResult];
[self setSelectedRange:selectedRange];
}
我最终必须在这里手动重置插入点。我仍然想知道为什么这是必要的,但至少这感觉不像是黑客。