Символьный индекс левого / правого символа в биди-тексте в TextKit - PullRequest
0 голосов
/ 01 февраля 2019

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

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

السلام عليكم Hello السلم عليكم وHello

Реализация 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)
    }
}

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

...