Я хочу реализовать следующую функцию: в моем подклассе NSTextView я слушаю опцию + стрелка вверх и опция + стрелка вниз. Всякий раз, когда эти ярлыки запускаются, выбор текстовых представлений должен расширяться / сворачиваться следующим образом:
- Курсор
- Текущее слово под курсором
- Текст под курсором до пробела
- Текущее предложение под курсором
- Текущий абзац под курсором
- Весь текст TextView
Однако моя реализация работает, когда бы я ни расширял выбор, я «перезаписать» позицию курсора, и поэтому я не могу снова правильно свернуть выделение. Вот пример того, чего я хочу достичь: https://caret.io/feat/feat-extend.gif
Мое текущее решение основано на поиске следующего большего выбора из текущего выбора и выглядит так:
private func selectNextTextBlock() {
let location = insertionLocation ?? selectedRange().location
let wr = wordRange(at: location)
let wgr = wordGroupRange(at: location)
let sr = sentenceRange(at: location)
let pr = paragraphRange(at: location)
if self.selectedRange().length == 0 {
self.setSelectedRangesWithUndo([wr])
} else if self.selectedRange().length >= wr.length && self.selectedRange().length < wgr.length {
self.setSelectedRangesWithUndo([wgr])
} else if self.selectedRange().length >= wgr.length && self.selectedRange().length < sr.length {
self.setSelectedRangesWithUndo([sr])
} else if self.selectedRange().length >= sr.length && self.selectedRange().length < pr.length {
setSelectedRangesWithUndo([pr])
} else {
setSelectedRangesWithUndo([NSRange(location: 0, length: string.count)])
}
}
private func selectPreviousTextBlock() {
#warning("implement?")
}
private func wordRange(at location: Int) -> NSRange {
let proposedWordRange = super.selectionRange(forProposedRange: NSRange(location: location, length: 0), granularity: .selectByWord)
guard proposedWordRange.contains(location) else { return proposedWordRange }
// treat `.` and `:` as word delimiter
return (self.string as NSString).rangeOfCharacter(until: CharacterSet(charactersIn: ".:"), at: location, range: proposedWordRange)
}
private func wordGroupRange(at location: Int) -> NSRange {
let proposedWordRange = super.selectionRange(forProposedRange: NSRange(location: location, length: 0), granularity: .selectByParagraph)
guard proposedWordRange.contains(location) else { return proposedWordRange }
// treat `whitespaces and newlines` as word delimiter
return (self.string as NSString).rangeOfCharacter(until: CharacterSet.whitespacesAndNewlines, at: location, range: proposedWordRange)
}
private func sentenceRange(at location: Int) -> NSRange {
let proposedWordRange = super.selectionRange(forProposedRange: NSRange(location: location, length: 0), granularity: .selectByParagraph)
guard proposedWordRange.contains(location) else { return proposedWordRange }
// treat `.` and `:` as paragraph delimiter
var range = (self.string as NSString).rangeOfCharacter(until: CharacterSet(charactersIn: ".:"), at: location, range: proposedWordRange)
range.length += 1
return range
}
private func paragraphRange(at location: Int) -> NSRange {
return super.selectionRange(forProposedRange: NSRange(location: location, length: 0), granularity: .selectByParagraph)
}
Есть какие-нибудь подсказки для меня о том, как реализовать selectPreviousTextBlock
? Поскольку пользователь может изменить позицию курсора вручную, я не могу гарантировать сохранение правильной последней позиции курсора в selectNextTextBlock