специальная несинтаксическая подсветка в Pygments - PullRequest
0 голосов
/ 01 октября 2018

Я использую Pygments как часть MarkDown, Python и LaTeX (до minted).По этим причинам я не могу легко перейти на другой инструмент и хотел бы найти решение в Pygments.

Чего я хочу добиться, так это иметь «специальную подсветку» помимо простой подсветки синтаксиса.Это включает, например, сохранение определенного вывода терминала в его исходном цвете.Или добавление дополнительных стилей для облегчения выделения аргументов для заполнения пользователем. Пример, безусловно, облегчит это понимание.

В руководстве Swift, написанном Apple, аргументы, которые вы можете использоватьзаполнить выделены воздушными шарами.Это значительно облегчает их идентификацию, и воздушный шар может охватывать диапазон токенов:

enter image description here

Я хочу добиться чего-то подобного с помощью Pygments.Простое изменение стиля не работает.Вы хотите, чтобы эти вещи обычно стилизовались для их типа токена, когда они не находятся внутри шарика, и вы не хотите какой-либо особой подсветки типа, когда он находится внутри шарика.Я не думаю эти типы воздушных шаров возможны в текущих ванильных Пегментах.Я думаю Мне нужен токен нового типа, чтобы достичь того, чего я хочу.Я хотел бы использовать это для различных языков, поэтому в идеале я хочу найти способ сделать это с наименьшим количеством модификаций.К сожалению, я не думаю Я могу добиться того, чего хочу, с помощью фильтров Pygments.Мне кажется, что мне нужно переписать лексеры для всех языков, которые я хочу использовать, но я думаю Я могу сделать это, разбив их на подклассы.

Подводя итог, что я хочузаключается в том, что я передаю код, такой как

§label name§: while §condition§ {

, и что, например, при выводе HTML получается что-то вроде

<code><pre><span class="balloon">label name</span>: <span class="k">while</span><span class="balloon">condition</span> { 

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

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

1 Ответ

0 голосов
/ 02 октября 2018

Благодаря комментарию Уэйлана я был на правильном пути и нашел решение, которое работает:

from pygments import token
from pygments.lexer import inherit
from pygments.lexers import Python3Lexer, SwiftLexer


# create a new token and associate with it a new short style name
token.STANDARD_TYPES[token.Token.Balloon] = "balloon"
Balloon = token.Token.Balloon


# create a callback which ignores the special § characters
def process_balloon(_, match):
    yield match.start(), Balloon, match.group(1)


# subclass the Python 3 lexer to identify ballooned text
# when subclassing, the tokens dictionaries will be merged
class Python3BalloonLexer(Python3Lexer):
    tokens = {
        "root": [(r'§(.*?)§', process_balloon),  # balloons are processed first
                 inherit]  # and then merge the superclass tokens here
    }

# do the same for the Swift language with a one-liner
class SwiftBalloonLexer(SwiftLexer):
    tokens = { "root": [(r'§(.*?)§', process_balloon), inherit] }


# example output below
from pygments import highlight
from pygments.formatters import HtmlFormatter
my_lexer_python = Python3BalloonLexer()
my_lexer_swift = SwiftBalloonLexer()
print(highlight('print(§"Hello World"§)', my_lexer_python, HtmlFormatter()))
print(highlight('§label name§: while §condition§ {\n  §statements§\n}', 
      my_lexer_swift, HtmlFormatter()))

В двух словах, это решение создает новый токен, чтобы гарантировать отсутствие конфликта с существующимжетоны.Затем для каждого языка, на котором требуется всплывающее окно, этот язык разделяется на подклассы для добавления поддержки нового токена.Этот токен обрабатывается функцией обратного вызова, которая принимает содержимое только между символами §.Как только все воздушные шары найдены, обычный лексер вступает во владение и обрабатывает остальную часть языка.

Это решение, кажется, ставит большинство флажков, за исключением необходимости подкласса каждого языка один за другим.Это немного громоздко, но не слишком большая проблема.Подход все еще немного хрупок, поскольку предполагает, что § используется только для выделения этих шариков.

Аналогичный подход можно использовать для принудительного определения определенных стилей для , например, текста, который всегда должен быть одного цвета, просто добавляя / укладывая дополнительные расширения лексера с помощью подклассов.Это, конечно, увеличивает риск потенциальных коллизий, поскольку это означает добавление дополнительных специальных символов, таких как §, которые уже могут использоваться в других местах вашего кода.

...