Была у меня давняя отдаленная мечта — иметь подсветку синтаксиса кода в блоге. Причем мне категорически не нравится идея делать это так, как это обычно делается: с помощью некой отдельной тулзы, которая кушает код и выдает раскрашенный HTML (мне для этого, наверное, даже тулзы бы не понадобилось, потому что экспортировать рсцвеченный код умеет тот же SciTE). Как-то все это слишком много телодвижений отнимает. Кроме того, я пользуюсь Markdown'ом, который escape'ит код всякими < и > за меня, а я всегда смотрю и редактирую просто чистые блоки кода, поэтому заменять его кашей тегов мне нравится еще меньше.

Мой идеальный подсветчик представлялся мне javascript'овой библиотечкой, которая ищет на странице код в определенных тегах и меняет его на разбитый на части HTML, а цвета и шрифты задаются в CSS.

История

Писать мне (а видимо, и не только мне) его очень не хотелось, потому что я, во-первых, ненавижу парсинг, а во-вторых не люблю искать чужие решения (именно искать, пользоваться-то ими я люблю, если они хорошие). Но вот вчера вечером я, что называется, "психанул", и решил попробовать написать, причем поставил себе условие, что если сразу не получится, много дней мучиться не буду: и так забот хватает.

Сначала полез поискать, не есть ли уже чего-нибудь похожего в наличии. Может плохо искал, но все что нашел — это "Compiler Generator In Javascript", в котором написано в частности:

AFAIK, this is the first publically availible parser generator in javascript.

Что подсказало мне, что тема не разработана :-). Сам этот генератор крут и наворочен, и я подумал, что даже просто определять грамматики для него — целая история. И после этого стал писать свой.

За вечер и полночи я придумал простенький формат грамматики, написал лексер и отладил подсветку двух языков — Python и HTML — в Firefox'е и IE (про Оперу не знаю, но должно быть нормально все). И оно работает! Оно даже отличает имена функций и классов Питона от других идентификаторов и разбирается, что в HTML атрибуты могут задаваться очень по-разному (attr="value", attr=value, attr). О, как!

"Но и это еще не все!" Помимо прочего мне надо было, чтобы вся эта благодать работала для всего кода, уже написанного в блоге, а ползать по всем статьям, выискивать код и говорить, каким языком он написан, мне было лениво. Поэтому я придумал эвристику, по которой язык кода определяется автоматически. Конечно, как любая эвристика, она неточна, но поскольку Питон, HTML и CSS, который я собираюсь вскоре добавить, синтаксически сильно различаются, она работает на удивление хорошо. А чтобы различать близкие языки, есть еще идеи, как это улучшить.

Как это работает, можно видеть например на этой странице.

Download и инструкция

Если кого это заинтересовало, то библиотечку можно брать и пользоваться: highlight.js.

Как водится, замечу, что это первая версия, написанная за несколько часов, а поэтому в ней есть баги, и она еще не много умеет.

Подключается очень просто, один файл и один инициализирующий вызов, например так:

<script type="text/javascript" src="highlight.js"></script>
<script type="text/javascript">
  window.onload = function() {initHighlighting();}
</script>

Кодом на странице считаются блоки <pre><code>...</code></pre>. Код этот размечается <span>ами с разными классами ("keyword", "comment", "string", "attribute" ...). Полный список их можно найти в самом файлике, где в начале идет описание грамматик. Параметры называются "className".

Непосредственно оформление задается в стилях примерно так:

.comment {
  color: gray;
}

.keyword {
  font-weight: bold;
}

.python .string {
  color: blue;
}

.html .atribute .value {
  color: green;
}

Грамматики, как видно из файла, довольно неподробные. Это намеренно, потому что я не большой любитель сильно цветастых кодов. Однако, формат их довольно простой (как мне кажется :-) ), поэтому кому нравится, может дорисовать себе как угодно подробно. А я потом, как руки дойдут, сделаю страничку, где все это собирать буду.


Вот. После этого запойного программного спурта ощущаю теперь удивительный подъем вкупе с некоторой сонливостью. Давно меня так не торкало :-).

Комментарии: 14

  1. zed_0xff

    Респект.
    Пока особо без надобности, но в перспективе - пригодится.
    Только цвета не очень понятные imho.
    Темно-красный от черного не сильно отличим беглым взглядом.
    Но это моё имхо. :)

  2. enternet

    Писать свой парсер - это конечно решение правильное.
    Но я бы наверное решал такую задачу через потрошение внутренностей "RSDN Authoring Pack". У него уже есть готовый раскрасочный механизм на js для кучи языков. Там, кстати, вообще забавное решение - шаблон для ворда который дергает wsc-компонент, который подключает js во внешнем файле. Впервые увидел wsc на практике.

  3. Tomaz
  4. Tomaz
  5. ELV1S

    (про Оперу не знаю, но должно быть нормально все)

    Да, в опере всё нормально. И в восьмёрке, и в девятке.

  6. Setti @ PlayStation

    Довольно элегантно получилось.

  7. Julik

    В Сафари пусто.

  8. DEkart

    Шикарная вещь! Надо будет попробовать сделать подсветку синтаксиса для Ruby и прикрутить к своему блогу

  9. Иван Сагалаев

    Было бы очень неплохо! Там наверняка понадобятся с меня разъяснения, как все это устроено, пишите мылом, расскажу.

  10. memyself

    Вот, ещё нашёл.
    http://jquery.com/demo/code/

  11. pythy

    Making dp.SyntaxHighlighter for Python Not Suck про улучшение поддержки Python в dp.SyntaxHighlighter (про него Tomaz говорил)

  12. Aleksey Aleksyeyev

    Как известно, Google ворует все свои фичи у Яндекса. Так, увидев, что какой-то мужик из Яндекса написал подсветку синтаксиса на JavaScript'е, они почти через год выпустили свою

  13. Aleksey Aleksyeyev

    Кстати, ты просил сообщать об инсталляциях — с недавних пор стоит на knotes.ru (там, правда, кода пока что мало)

  14. Ivan Sagalaev

    Пост от августа 2006 года, в Яндексе я тогда не работал. Да и сейчас highlight.js к Яндексу никакого отношения не имеет.

    А гуглокодовский prettifier сделан в октябре того же года.

Добавить комментарий