Macos 修改NSTextStorage会导致插入点移动到行的末尾
我有一个Macos 修改NSTextStorage会导致插入点移动到行的末尾,macos,cocoa,nstextview,nstextstorage,Macos,Cocoa,Nstextview,Nstextstorage,我有一个NSTextView子类充当它的NSTextStorage委托。我试着做两件事: 以某种方式突出显示文本 评估文本,然后将答案附加到textview 我用两种不同的方法来实现这一点,这两种方法都由-(void)textStorageWillProcessEditing:(NSNotification*)notification委托回调调用 我可以很好地突出显示语法,但是在添加答案时,插入点会跳到行的末尾,我真的不知道为什么。我的求值方法如下所示: NSString *result = .
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];
- (void)insertText:(id)insertString {
[super insertText:insertString];
NSRange selectedRange = [self selectedRange];
[self doEvaluationAndAppendResult];
[self setSelectedRange:selectedRange];
}
- (void)processEditing {
//Process self.editedRange and apply styles first
[super processEditing];
}
这样做将很好地附加我的结果,但问题是,正如前面提到的,插入点跳到了末尾
我试过:
[textStorage beginEditing]
和-endEditing
中我这样做对吗?我正试图以最不粗俗的方式来做这件事,我也不确定这是否是进行解析/突出显示的理想场所。医生让我相信了这一点,但也许这是错的。很简单!我最后把这个问题分成两部分。由于
textStorage
delegate回调,我仍然会突出显示语法,但现在我会在其他地方进行计算和追加
我最终覆盖了-insertText:
和-deleteBackwards:
(我可能也希望对-deleteForwards:
执行同样的操作)。这两个覆盖看起来如下所示:
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];
- (void)insertText:(id)insertString {
[super insertText:insertString];
NSRange selectedRange = [self selectedRange];
[self doEvaluationAndAppendResult];
[self setSelectedRange:selectedRange];
}
- (void)processEditing {
//Process self.editedRange and apply styles first
[super processEditing];
}
最后我不得不在这里手动重置插入点。我仍然很想弄清楚为什么这是必要的,但至少这感觉不像是一个黑客。我知道这个问题早就得到了回答,但我也有同样的问题。在我的
NSTextStorage
子类中,我执行了以下操作:
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];
- (void)insertText:(id)insertString {
[super insertText:insertString];
NSRange selectedRange = [self selectedRange];
[self doEvaluationAndAppendResult];
[self setSelectedRange:selectedRange];
}
- (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
}
插入点移动的原因
令人惊讶的是,我从来没有找到一个实际的解释来解释为什么这些建议有效(或无效)
深入研究,插入点移动的原因是:.editedCharacters
(NSTextStorageEditedCharacters
,在ObjC中)影响插入点在NSLayoutManager.processEditing(from:editedMask:…)
中的位置
如果仅发送.editedAttribute
/NSTextStorageeditedAttribute
,则插入点将不会被触摸。这就是您在突出显示“仅更改属性”时要实现的目标
为什么高亮显示会影响插入点
此处突出显示的问题是NSTextStorage
在单个处理运行期间收集所有编辑的调用,并组合范围,从用户编辑的更改开始(例如键入时的插入),然后将此范围与addAttributes报告的所有范围合并(u:range:)
。这将导致一个NSLayoutManager.processEditing(from:editedMask:…)
调用,调用的editedMask
同时包含[.editedCharacters、.editedAttribute]
因此,您希望为突出显示的范围发送.editedAttribute
,但最终与.editedCharacters
形成联合。该并集将插入点WAAAAY移动到超出其应移动的位置
更改processEditing
中的顺序以调用super first works,因为版面管理器将收到已完成编辑的通知。但这种方法在某些边缘情况下仍然会中断,导致在键入非常大的段落时布局无效或滚动视图抖动
顺便说一句,我也是
在布局真正完成后挂接回调,以触发高亮显示,而不是processEditing
基于Cocoa框架固有的原因,唯一有效的解决方案是以独占方式从textDidChange(:)
执行高亮显示,即在布局处理真正完成之后。订阅NSTextDidChangeNotification
也同样有效
缺点:对于底层字符串的编程更改,您必须触发高亮显示过程,因为这些过程不会调用textDidChange(u:)
回调
如果你想更多地了解问题的根源,我会在一篇更长的博文中提供更多我的研究、不同的方法和解决方案的细节,以供参考。这篇文章本身仍然是一个独立的解决方案:
什么是lineForRange,我在文档中找不到该方法?如果您是指lineRangeForRange,那么这可能是您的问题。你是想附加到行的末尾,还是选择的结尾?我问题的第二部分怎么样?不清楚您试图将文本附加到何处。当你说插入点移到行尾时,你的意思是在插入之后还是之前?对不起,是的,我正在尝试附加到行尾。再一次,你只回答了我一半的问题。到底是什么问题?文本替换是否正确,但插入点是否移到了末尾(您是指文本的结尾还是仅指行)?或者,替换文本是否位于错误的位置?问题是:这样做将附加我的结果,但问题是,如上所述,插入点跳到了末尾。
谢谢,这解决了我的问题。如果使用NSTextStorageDelegate时遇到此问题,请使用textStorageDidProcessEditing:而不是textStorageWillProcessEditing:。不过,请务必阅读文档中关于将文本存储保留在不一致状态的警告。提醒:虽然这确实有效,但您必须小心不要使用