Проблема
Мне нужно понять, как работает TextKit и как я могу использовать его для создания текстового редактора. Мне нужно выяснить, как рисовать ТОЛЬКО видимый текст, с которым взаимодействует конечный пользователь, или определить, как я буду лениво применять атрибуты к видимому тексту только без применения атрибутов ко всему измененному диапазону текста в методе processEditing.
Фон
iOS 7 вышел с TextKit. У меня есть токенизатор и код, который полностью реализует TextKit (см. Проект Apple TextKitDemo - ссылка приведена ниже)... и он работает. Однако он ДЕЙСТВИТЕЛЬНО медленный. Когда текст анализируется, NSTextStorage требует, чтобы вы раскрашивали диапазон ENTRE отредактированного текста в методе processEditing в том же потоке. Разгрузка работы в поток не помогает. Это просто слишком медленно. Я дошел до того, что я могу повторно атрибутировать только измененные диапазоны, но если диапазон слишком велик, процесс будет медленным. В некоторых условиях весь документ может быть признан недействительным после внесения изменений.
Вот некоторые идеи, которые у меня есть. Пожалуйста, дайте мне знать, будет ли кто-нибудь из них работать или, возможно, подтолкнет меня в правильном направлении.
1) Несколько NSTextContainers
Чтение документов показывает, что я могу добавить несколько NSTextContainers в NSLayoutManager. Я предполагаю, что, делая это, я должен уметь определять не только количество строк, которые могут быть нарисованы в NSTextContainer, но также я должен знать, какой NSTextContainer виден конечным пользователям. Я знаю, что если я пойду по этому маршруту, мне нужно будет потратить много времени, чтобы убедиться, насколько это возможно. Первоначальное тестирование предполагает, что вам нужен только один NSTextContainer. Поэтому мне пришлось бы подклассифицировать NSLayout или создать оболочку, в которой диспетчер компоновки определяет, какой текст переходит в текстовый контейнер. Тьфу. Кроме того, я не знаю, как TextKit позволяет мне знать, что пришло время рисовать конкретный NSTextContainer... возможно, это не так, как это работает!
2) Недействительные диапазоны с NSLayoutManager
Недействительность layoutManager с использованием invalidateLayoutForCharacterRange: actualCharacterRange:. Но что это на самом деле делает и как он выгрузит фазу атрибуции текста? Когда это позволяет мне знать, что конкретный текст нужно выделить? Кроме того, я вижу, что NSLayoutManager будет лениво рисовать глифы... как? когда? Как это мне помогает? Как я могу использовать этот вызов, чтобы привязать строку поддержки до того, как она на самом деле выведет текст?
3) Перегрузка NSLayoutManager drawGlyphsForGlyphRange: atPoint: метод.
Я действительно не хочу этого делать. При этом в Mac OS X NSAttributedStrings имеет эту концепцию временных атрибутов, где информация стиля используется только для представления. Это ускоряет процесс выделения БОЛЬШОГО! Проблема в том, что она отсутствует в инфраструктуре iOS 7 TextKit (или она есть, и я просто не знаю об этом). Я верю, что перевернув этот метод, он даст мне тот же тип скоростей, который вы получите с помощью временных атрибутов... поскольку я мог бы ответить на все вопросы макета, цвета и форматирования в этом методе, не затрагивая при этом атрибут NSTextStorage строка. Единственная проблема заключается в том, что я не знаю, как этот метод работает в отношении других методов, предоставляемых в классе NSLayoutManager. Сохраняет ли оно ширину и высоту? Изменяет ли размер NSTextContainer, когда он слишком мал? Кроме того, он только рисует глифы для символов, которые были добавлены в текстовый буфер. Он не перерисовывает весь экран. только крошечная его часть... и это прекрасно. У меня есть некоторые идеи о том, как я могу работать с этим... но у меня действительно нет желания компоновать глифы. Это слишком много работы, и я не нашел хорошего примера, который делает это.
Я был бы очень признателен за любую помощь, которую вы можете предложить.
В качестве благодарности я перечисляю все фреймворки и ссылки, которые я использовал в течение последних нескольких лет, которые помогли мне добраться туда, где я сейчас нахожусь в надежде, что они вам полезны.
Рамки выделения синтаксиса:
- http://colorer.sourceforge.net/
- https://github.com/MikeJ1971/Glint (не поддерживает строки, комментарии и т.д.)
- https://projects.gnome.org/gtksourceview/features.html (Предоставляет достойную библиотеку для создания токенов. Работает с GTK, но может быть переписана для другого менеджера макетов)
- http://parsekit.com/(Хороший парсер. Однако вам нужно обернуть API для создания конечного автомата при необходимости исправления диапазонов).
- http://svn.gna.org/viewcvs/etoile/trunk/Etoile/Languages/LanguageKit/
- https://github.com/CodaFi/IDEKit (Удивительная работа. В этом коде есть много хороших идей. Моя проблема в том, что я абсолютно не знаю, как это исправлять диапазоны, или даже если это произойдет)
- http://www.crimsoneditor.com/ (старый редактор кода Windows. Он имеет очень хороший токенизатор - хотя и немного трудночитаемый. Он не использует выражения регулярных выражений. При этом я основывал свою токенную логику на этом коде, и он намного быстрее, чем любая из перечисленных выше фреймворков).
Ресурсы
- http://cocoafactory.com/blog/2012/10/29/how-to-use-custom-nsattributedstring-attributes/
- https://github.com/objcio/issue-5-textkit
- http://alexgorbatchev.com/SyntaxHighlighter/
- http://docs.xamarin.com/samples/TextKitDemo/ (демонстрация Apple)
- http://cocoadev.com/ImplementSyntaxHighlighting (Обязательно прочитайте все детские статьи. Отличный материал)
Большинство из этих структур одинаковы. Они либо не учитывают переключение контекста (или вам нужно написать оболочку для предоставления контекста) для диапазонов, либо они не восстанавливают диапазоны контекста, поскольку пользователь изменяет текст (например, строки, многострочные комментарии и т.д.). Последнее требование ОЧЕНЬ важно. Потому что, если токенизатор не может определить, на какие диапазоны влияет изменение, вам придется снова проанализировать и приписать всю строку. Единственным исключением из этого является Crimson Editor. Проблема с этим токенизатором заключается в том, что он не сохраняет состояние во время токенизации. Во время рисования алгоритм использует токены для определения состояния рисования. Он начинается с верхней части документа, пока он не попадет в видимый диапазон текста. Излишне говорить, что я оптимизировал это, кэшируя состояние документа в определенных частях документа.
Другая проблема заключается в том, что фреймворки не соответствуют тому же шаблону MVC, который Apple делает - чего и следовало ожидать. В инфраструктурах, в которых есть полный рабочий редактор, используются крючки, предоставляемые API-интерфейсом, на котором они построены (т.е. GTK, Windows и т.д.), Который предоставляет им информацию о том, где и когда рисовать, в какую часть экрана. В моем случае TextKit, по-видимому, требует от вас атрибута всего измененного диапазона в processEditing.
Возможно, мои наблюдения ошибочны. (Надеюсь, они!) Может быть, например, ParseKit будет работать для того, что мне нужно, и я просто не понимаю, как его использовать. Если это так, пожалуйста, дайте мне знать! И еще раз спасибо!