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:
(It doesn't necessarily have to use the firstIndex(where:)
method, but appears to be the way to go.)
A String.Index
range for the first line in string
can be obtained with
let range = string.lineRange(for: ..<string.startIndex)
If you need that as an NSRange
then
let nsRange = NSRange(range, in: string)
does the trick.