Символьный индекс левого / правого символа в биди-тексте в TextKit

Я работаю с подклассом NSTextView и хотел бы знать индекс символа рядом с текущей точкой вставки. Точнее, я хочу получить их индекс символов для перемещения курсора с помощью клавиши со стрелкой, но без использования NSResponder. moveLeft(_:) или же moveRight(_:) семьи.

Это легко с помощью обычного горизонтального однонаправленного текста, потому что index-1 левый и index+1 является правильным (если вы забудете о том, что буквы состоят из нескольких символов). Однако при использовании двухстороннего текста, в котором смешаны слева направо и справа налево, порядок визуальных символов, отображаемый в представлении, не совпадает с фактическим индексом символов.

Реализация по умолчанию NSTextView, кажется, выполняет биди-текст как-то. Поэтому я хотел бы получить то же поведение перемещения курсора NSTextView, но я не смог найти подходящий публичный API для него.

До сих пор я нашел метод NSLayoutManager getGlyphs(in:glyphs:properties:characterIndexes:bidiLevels:) это кажется правильным методом, чтобы получить биди условие. Поэтому я написал метод расширения, подобный следующему. Но тогда, даже если бы я мог получить состояние RTL определенного местоположения, я не уверен, что индекс символа следующего, когда индекс находится на границе букв RTL и LTR.

extension NSLayoutManager {

    func isRTL(at index: Int) -> Bool {

        let glyphIndex = self.glyphIndexForCharacter(at: index)

        guard glyphIndex > 0 else { return false }

        var bidiLevels: [UInt8] = [0]
        self.getGlyphs(in: NSRange((glyphIndex-1)..<glyphIndex), glyphs: nil, properties: nil, characterIndexes: nil, bidiLevels: &bidiLevels)

        return (bidiLevels[0] % 2 == 1)
    }
}

Другой подход, который я сейчас пробую, это получить его из координаты вида, как показано ниже. Но затем метод пропускает символы нулевой ширины.

extension NSTextView {

    func leftIndex(of index: Int) -> Int {

        guard
            let layoutManager = self.layoutManager,
            let textContainer = self.textContainer
            else { assertionFailure(); return index }

        let glyphIndex = layoutManager.glyphIndexForCharacter(at: index)
        let rect = layoutManager.boundingRect(forGlyphRange: NSRange(glyphIndex..<(glyphIndex+1)), in: textContainer)
            .offset(by: self.textContainerOrigin)

        let point = NSPoint(x: rect.minX - 1, y: rect.midY)

        return self.characterIndexForInsertion(at: point)
    }
}

У кого-нибудь есть идея выполнить мое требование?

0 ответов

Другие вопросы по тегам