Есть документ, с 5 000 000 строками кода.
Крутим скроллбар вниз.
Отрисовка символов естественно только видимых на экране
Цвет символа нужно определять в соответствии с разными правилами, смотря что за символы были ранее, слева, и что за символы будут справа
например если есть комментарий такого типа /* */ то получается, нужно каждый раз при рендеринге, проходиться по всему документу сначала в поисках /* а потом */
Это же очень затормозит работу. Есть ли другие решения вопроса, более простые и более производительные?
да да, с 5000 строк кода программа справится без проблем, но не с 5кк, но всё же

Если хочется быстро, то вряд ли получится просто... Можно так:
Храним "карту" документа как массив (условно) из экземпляров простого класса блока "позиция начала; позиция конца; тип блока; вложенные".
При изменении на строке - ищем в карте затронутые блоки, и в зависимости от типа изменения (добавлены или удалены символы), получаем направление поиска (какую позицию каждого затронутого блока обновить), затем собственно обновляем. То есть, пытаемся сократить время обработки уменьшением объема данных для поиска.
Изменения в документе должны обрабатываться все (по принципу FIFO), поэтому потребуется как-то организовать буферы для этих изменений (лучше всего хранить не сами изменения, а их свойства).
Нужно будет сортировать массив по позициям, для удобной обработки ситуации удаления открытия/закрытия блока.
Неудобно то что при удалении блоков верхних уровней вложенности, нужно будет таскать данные в карте. Альтернативный подход - структура блока на основе элемента связанного списка, с добавлением переменных для позиций блока и уровня его вложенности.
разок пройти по тексту, посчитать какие стили, с какого по какой символ
при прокрутке ориентироваться по этому первому анализу
при редактировании обновлять =\
удалили или добавили символов с заданной позиции - обновить все последующие стили
Можно создавать синтаксическое дерево разбора (примерно как в компиляторах, только упрощённое), каждый элемент которого связан с соответствующей ему строкой (и каждая строка, в свою очередь, тоже указывает на свой элемент дерева). При изменении строки переходим к соответствующему элементу дерева, определяем какие ещё элементы будут затронуты его изменением (в древовидной структуре это не составит большого труда), и делаем повторный разбор лишь для строк связанных с этими элементами.