I would like to change the formatting of the first line of text in an NSTextView
(give it a different font size and weight to make it look like a headline). Therefore, I need the range of the first line. One way to go is this:
guard let firstLineString = textView.string.components(separatedBy: .newlines).first else {
return
}
let range = NSRange(location: 0, length: firstLineString.count)
However, I might be working with quite long texts so it appears to be inefficient to first split the entire string into line components when all I need is the first line component. Thus, it seems to make sense to use the firstIndex(where:)
method:
let firstNewLineIndex = textView.string.firstIndex { character -> Bool in
return CharacterSet.newlines.contains(character)
}
// Then: Create an NSRange from 0 up to firstNewLineIndex.
This doesn't work and I get an error:
Cannot convert value of type '
(Unicode.Scalar) -> Bool
' to expected argument type 'Character
'
because the contains
method accepts not a Character
but a Unicode.Scalar
as a parameter (which doesn't really make sense to me because then it should be called a UnicodeScalarSet
and not a CharacterSet
, but nevermind...).
My question is:
How can I implement this in an efficient way, without first slicing the whole string?
(It doesn't necessarily have to use the firstIndex(where:)
method, but appears to be the way to go.)
You can use
rangeOfCharacter
, which returns theRange<String.Index>
of the first character from a set in your string:You can use it like so:
A
String.Index
range for the first line instring
can be obtained withIf you need that as an
NSRange
thendoes the trick.