Sotomajor.org.ua - development, photography and a lot of stuff: Плагин подсветки синтаксиса для TextPattern

Не нужно проводить психологические исследования, чтобы понять: плохо отформатированный код никто читать не будет. Стандартных средств подсветки синтаксиса в textpattern не нашлось, поэтому я полез в Google за плагином…

corner icon
Volovec - Play Dead Sea and Jerusalem -> Dead sea. Far coast is Jordan. Safari in Ramat Gan Sights of Tel Aviv Lviv Racetrack L'viv sights Zaporizhzhia, Kyiv

Плагин подсветки синтаксиса для TextPattern

2008-01-12 23:16 // // Раздел:

Не нужно проводить психологические исследования, чтобы понять: плохо отформатированный код никто читать не будет. Стандартных средств подсветки синтаксиса в textpattern не нашлось, поэтому я полез в Google за плагином.

Плагин нашёлся довольно быстро и называется он труднопроизносимым словом krl_geshiSyntaxHighlight. Это расширение использует опенсорсный движок подсветки синтаксиса GeSHi, что расшифровывается как Generic Syntax Highlighter, который прийдётся скачать отдельно.

Немного удручило то, что первый и последий релиз плагина был в далеком январе 2005 года, сразу появились смутные сомнения о совместимости плагина и свежего TextPattern, которые в некотором роде подтвердились. Итак...

Изначально плагин выглядел таким образом:
php:
  1. <?php
  2. function krl_geshiSyntaxHighlight($attributes, $node_value="") {
  3.  
  4.     $language = isset($attributes["language"]) ? $attributes["language"] : "PHP";
  5.     $linenumbers = isset($attributes["linenumbers"]) ? $attributes["linenumbers"] : true;
  6.     $start_line_numbers_at = isset($attributes["startLineNumbersAt"]) ? $attributes["startLineNumbersAt"] : 1;
  7.     $width = isset($attributes["width"]) ? $attributes["width"] : "530";
  8.     $height = isset($attributes["height"]) ? $attributes["height"] : "180";
  9.  
  10.     $code_file = isset($attributes["file"]) ? $attributes["file"] : "";
  11.     if ($code_file == "") {
  12.         $code_to_highlight = strip_tags($node_value);
  13.     } else {
  14.         $code_directory = isset($attributes["directory"]) ? $attributes["directory"] : "highlighted_source/";
  15.         // for some reason $_SERVER["DOCUMENT_ROOT"] on my Windows PC seems to be missing the trailing slash
  16.         // so I normalise it once per page then use the normalised version.
  17.         if (!defined("_KRL_DOCUMENT_ROOT")) {
  18.             define("_KRL_DOCUMENT_ROOT", $_SERVER["DOCUMENT_ROOT"]{count($_SERVER["DOCUMENT_ROOT"])} == "/" ? $_SERVER["DOCUMENT_ROOT"] : $_SERVER["DOCUMENT_ROOT"]."/");
  19.         }
  20.         $code_to_highlight = file_get_contents(_KRL_DOCUMENT_ROOT.$code_directory.$code_file);
  21.     }
  22.  
  23.     $code_to_highlight = trim($code_to_highlight, "\r\n");
  24.  
  25.     require_once('geshi.php');
  26.     $geshi = new GeSHi($code_to_highlight, $language);
  27.     //$geshi->enable_classes();
  28.     $geshi->set_encoding("ISO-8859-1");
  29.     $geshi->enable_line_numbers($linenumbers);
  30.     $geshi->set_header_type(GESHI_HEADER_DIV);
  31.     if ($linenumbers) {
  32.         $geshi->start_line_numbers_at($start_line_numbers_at);
  33.     }
  34.  
  35.     // layout code to put code in a scrolling div borrowed from:
  36.     // http://www.flashant.org/index.php?p=225&more=1&c=1
  37.     $return_str  = '<div class="krl_highlighted_code">';
  38.     $return_str .= '<div class="header">'.$language.':</div>';
  39.     $return_str .= '<div class="codeblock" style="width: '.$width.'px; height: '.$height.'px;">';
  40.     $return_str .= $geshi->parse_code();
  41.     $return_str .= "</div></div>";
  42.  
  43.     return $return_str;
  44.  
  45. }
  46. ?>

Вставлять код в статьи и страницы предлагается одним из следующих способов:

code:
<krl_geshiSyntaxHighlight language=”language” file=”filename”
или
<krl_geshiSyntaxHighlight language=”language”><notextile>code to highlight</notextile></krl_geshiSyntaxHighlight>

Соответственно, первый способ - для вставки кода из внешнего файла, а второй для прямой вставки. Аттрибуты тега krl_geshiSyntaxHighlight:

  • file – если нужно вывести содержимое внешнего файла, то нужно указать его имя [optional – если не указано, то выведется содержимое тега]
  • directory – если внешний файл находится не рядом со скриптом, то нужно указать путь к его директории от корня веб-сервера [optional – по умолчанию "highlighted_source"]
  • language – один из языков, которые поддерживаются GeSHi [optional – по умолчанию PHP]
  • linenumbers – выводить или нет нумерацию строк [optional – по умолчанию true]
  • startLineNumbersAt – если выводить нумерацию, то с какого числа начинать [optional – по умолчанию 1]
  • width – длина в пикселях окошка с кодом [optional – значение по умолчанию задается в плагине]
  • height – высота окошка с кодом [optional – значение по умолчанию задается в плагине]

Исправления, которые пришлось внести в плагин:

Во-первых, неприятно удивила необходимость указывать путь к GeSHi вручную (строка 25). Небольшой хак позволил избежать этого при условии, что мы как и положено копируем GeSHi в textpattern/include:

php:
function krl_geshiSyntaxHighlight($attributes, $node_value="") {
    global $txpcfg;
//.......
    require_once($txpcfg['txpath'].'\include\geshi.php');
//.......
}

Тем самым мы используем глобальную конфигурационную переменную TextPattern, которая содержит пут к директории движка, который мы указали при установке.

Во-вторых, тэги TextPattern. Скорее всего здесь оправдались мои подозрения и из-за версии движка, стало нужно писать в открывающемся и закрывающемся теге не krl_geshiSyntaxHighlight, а txp:krl_geshiSyntaxHighlight, т.е. так:

code:
<txp:krl_geshiSyntaxHighlight language=”language” file=”filename” />
<txp:krl_geshiSyntaxHighlight language=”language”><notextile>code to highlight</notextile></tхp:krl_geshiSyntaxHighlight>

(Для любителей копипастить: в закрывающемся тэге txp:krl_geshiSyntaxHighlight буква x русская)

Третье и самое, на мой взгяд, главное. Оригинальный плагин режет все тэги HTML (да и не только) функцией strip_tags, что полностью лишает нас возможности постить HTML код. Это делается в строке 12. Здесь возможны два варианта: либо старая версия GeSHi (он-то ведь тоже обновлялся с того времени) не умела работать с HTML cущностями, либо автор плагина не предусмотрел необходимости выкладывать HTML код. Убрав strip_tags всё выводится нормально. Например:

html4strict:
<strong>Вывод HTML тэгов</strong>

Вывод:

Таким образом, получился плагин, который отлично подсвечивает синтаксис 86 языков (столько было в дистрибутиве GeSHi). Чут ниже можно взять модифицированный код. Стили, которые используются для красивого вывода дива с кодом можно найти на странице оригинального плагина.
php:
  1. function krl_geshiSyntaxHighlight($attributes, $node_value="") {
  2.     global $txpcfg;
  3.  
  4.  $language = isset($attributes["language"]) ? $attributes["language"] : "PHP";
  5.  $linenumbers = isset($attributes["linenumbers"]) ? $attributes["linenumbers"] : true;
  6.  $start_line_numbers_at = isset($attributes["startLineNumbersAt"]) ? $attributes["startLineNumbersAt"] : 1;
  7.  $width = isset($attributes["width"]) ? $attributes["width"] : "510";
  8.  $height = isset($attributes["height"]) ? $attributes["height"] : "180";
  9.  
  10.  $code_file = isset($attributes["file"]) ? $attributes["file"] : "";
  11.  if ($code_file == "") {
  12.   $code_to_highlight = $node_value;
  13.   //$code_to_highlight = htmlentities($node_value);
  14.  } else {
  15.   $code_directory = isset($attributes["directory"]) ? $attributes["directory"] : "highlighted_source/";
  16.   // for some reason $_SERVER["DOCUMENT_ROOT"] on my Windows PC seems to be missing the trailing slash
  17.   // so I normalise it once per page then use the normalised version.
  18.   if (!defined("_KRL_DOCUMENT_ROOT")) {
  19.    define("_KRL_DOCUMENT_ROOT", $_SERVER["DOCUMENT_ROOT"]{count($_SERVER["DOCUMENT_ROOT"])} == "/" ? $_SERVER["DOCUMENT_ROOT"] : $_SERVER["DOCUMENT_ROOT"]."/");
  20.   }
  21.   $code_to_highlight = file_get_contents(_KRL_DOCUMENT_ROOT.$code_directory.$code_file);
  22.  }
  23.  
  24.     $code_to_highlight = trim($code_to_highlight, "\r\n");
  25.  
  26.  require_once($txpcfg['txpath'].'/include/geshi/geshi.php');
  27.  $geshi = new GeSHi($code_to_highlight, $language);
  28.     //$geshi->enable_classes();
  29.  $geshi->set_encoding("ISO-8859-1");
  30.  $geshi->enable_line_numbers($linenumbers);  
  31.  $geshi->set_tab_width(1);
  32.  $geshi->set_header_type(GESHI_HEADER_DIV);
  33.  if ($linenumbers) {
  34.   $geshi->start_line_numbers_at($start_line_numbers_at);
  35.  }
  36.  
  37.  // layout code to put code in a scrolling div borrowed from:
  38.  // http://www.flashant.org/index.php?p=225&more=1&c=1
  39.  $return_str  = '<div class="krl_highlighted_code">';
  40.  $return_str .= '<div class="header">'.$language.':</div>';
  41.  $return_str .= '<div class="codeblock" style="width: '.$width.'px; height: '.$height.'px;">';
  42.  $return_str .= $geshi->parse_code();
  43.  $return_str .= "</div></div>";
  44.  
  45.  return $return_str;
  46.  
  47. }
  • — Написал: дмитрий · 2008-11-03 14:55 · #

    плагин действительно полезный!

  • — Написал: Devaka · 2009-05-26 21:49 · #

    Спасибо за обзор недостатков плагина!
    Сегодня поставил себе на блог, но проблема с пустыми строками. Когда добавляю пустую строку, то добавляются HTML теги (textile) и кавычки заменяются спецсимволами. Не знаю кто виноват, геши или карл :)

    У вас какая версия txp?

  • — Написал: Devaka · 2009-05-26 21:54 · #

    и startLineNumbersAt почему-то не работает :( все время с единицы получается <OL>

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