问题描述
我在使用NSTextView的macOS 10.12 Mojave上观察到一个奇怪的问题.
I'm observing a strange issue on macOS 10.12 Mojave with NSTextView.
.
我正在像这样更改 didChangeText()
中的textStorage属性:
I'm changing the textStorage attributes in didChangeText()
like this :
self.textStorage?.beginEditing()
ARTokenManager.getToken(text: text, language: language) { (tokens) in
// This line reset the attributes
// If I remove it, the cursor appear properly
// But the attributes are conserved
self.textStorage?.setAttributes([NSAttributedString.Key.font: self.font!,
NSAttributedString.Key.foregroundColor: self.defaultTextColor], range: range)
for token in tokens {
let attributeRange = NSRange(location: token.range.location + range.location, length: token.range.length)
self.textStorage?.addAttributes(token.attributes, range: attributeRange)
}
}
self.textStorage?.endEditing()
当我删除 setAttributes
方法时,一切都按预期工作,但我无法解释原因.我可能将属性重置错误.此问题仅适用于Mojave.
When I remove the setAttributes
method, everything works as expected, but I can't explain why. I'm possibly resetting the attributes wrong. This issue only works with Mojave.
有人有同样的问题或可以向我解释我在做什么错吗?
Does someone have the same issue or can explain me what I'm doing wrong ?
谢谢.
推荐答案
经过研究,我发现我的问题更多是关于使用NSTextView突出显示语法.我知道这是很多macOS开发人员都在问的一个问题,并且有很多解决方案.这可能不是最好的方法,但这就是我解决此问题的方法.
After some research, I discovered that my question was more about syntax highlighting with NSTextView. I know this is a question that a lot of macOS developers are asking about and there are a lot of solutions for that. This is not probably the best one, but this is how I’ve solved this problem.
为此,我使用了NSTextStorage的子类.这是完成所有语法工作的地方.NSTextStorage不是面向协议的,因此您必须按照Apple文档的建议自己重写方法:
To achieve that, I’ve used a subclass of NSTextStorage. This is where all the syntax work will be done. NSTextStorage is not protocol oriented so you have to override method by yourself as the Apple documentation suggest :
class SyntaxTextStorage: NSTextStorage {
private var storage: NSTextStorage
override var string: String {
return storage.string
}
override init() {
self.storage = NSTextStorage(string: "")
super.init()
}
override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedString.Key : Any] {
return storage.attributes(at: location, effectiveRange: range)
}
override func replaceCharacters(in range: NSRange, with str: String) {
beginEditing()
storage.replaceCharacters(in: range, with: str)
edited(.editedCharacters, range: range, changeInLength: str.count - range.length)
endEditing()
}
override func setAttributes(_ attrs: [NSAttributedString.Key : Any]?, range: NSRange) {
beginEditing()
storage.setAttributes(attrs, range: range)
edited(.editedAttributes, range: range, changeInLength: 0)
endEditing()
}
}
这是创建文本存储的基础.
This is the basic to create your text storage.
下一步是将文本存储设置为textView.为此,可以使用textView layoutManager
中可访问的 replaceTextStorage()
方法.
The next step is to set your text storage into your textView. To do so, you can use the replaceTextStorage()
method accessible in the textView layoutManager
.
class SyntaxTextView: NSTextView {
var storage: SyntaxTextStorage!
override func awakeFromNib() {
super.awakeFromNib()
configureTextStorage()
}
private func configureTextStorage() {
storage = SyntaxTextStorage()
layoutManager?.replaceTextStorage(storage)
}
}
语法
最后一步是完成语法工作.此过程的CPU成本非常高.有很多方法可以做到最好.我建议您实现一个类,该类将为您返回 NSAttributedString
和 NSRange
的列表.文本存储的工作仅应将样式应用于文本.我个人使用 processEditing
方法执行文本分析:
Syntaxing
The final step is to do your syntax job. The CPU cost of this process is very hight. There is a lot of way to do it to have the best performances. I suggest you to implement a class that will returns you a list of NSAttributedString
and NSRange
. The job of the text storage should only be applying the style to your text.Personally, I've used the processEditing
method to perform my text analyze :
override func processEditing() {
super.processEditing()
syntaxCurrentParagraph()
}
我建议您在后台进行语法分析,然后,如果自上次分析以来没有文本更改,请将更改应用于文本.始终在文本存储区中,我实现了一个 syntax
方法,该方法将样式应用于文本:
I recommend you to do you syntax analyze in background, then, if there is no text change since your last analyze, apply the change to your text. Always in my text storage, I've implemented a syntax
method that apply the style to the text :
private func syntax(range: NSRange, completion: ((_ succeed: Bool) -> Void)? = nil) {
guard range.length > 0 else {
completion?(true)
return
}
// Save your data to do the job in background
let currentString = self.string
let substring = currentString.substring(range: range)
let mutableAttributedString = NSMutableAttributedString(string: substring, attributes: NSAttributedString.defaultAttributes as [NSAttributedString.Key : Any])
DispatchQueue.global(qos: .background).async {
ARSyntaxManager.tokens(text: substring, language: self.language) { (tokens) in
// Fill you attributed string
for token in tokens {
mutableAttributedString.addAttributes(token.attributes, range: token.range)
}
DispatchQueue.main.async {
// Check if there is no change
guard self.string.count == currentString.count else {
completion?(false)
return
}
completion?(true)
// Apply your change
self.storage.replaceCharacters(in: range, with: mutableAttributedString)
self.displayVisibleRect()
}
}
}
}
就是这样.希望对您有所帮助.
That's it. Hope it will help some of you.
这篇关于在macOS 10.14上键入文本时,NSTextView光标没有出现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!