View source
<?php
define('GESHIFILTER_CSS_INLINE', 1);
define('GESHIFILTER_CSS_CLASSES', 2);
function geshifilter_help($section) {
switch ($section) {
case 'admin/modules#description':
return t("Provides tags for syntax-highlighting code automatically.");
}
}
function geshifilter_menu($may_cache) {
if (!$may_cache) {
drupal_add_css(drupal_get_path('module', 'geshifilter') . '/geshifilter.css');
drupal_add_css(drupal_get_path('module', 'geshifilter') . '/geshi.css');
}
else {
$items[] = array(
'path' => 'admin/settings/geshifilter',
'title' => t('GeSHi filter'),
'description' => t('Configure the general GeSHi filter settings.'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'geshifilter_admin_settings_form',
),
'access' => user_access('administer filters'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
}
function geshifilter_filter_tips($delta, $format, $long = false) {
$default_type = variable_get('geshifilter_default_type_' . $format, 0);
$types = variable_get('geshifilter_types_' . $format, array());
$start_param = variable_get('geshifilter_start_attribute', FALSE);
$line_numbers = variable_get('geshifilter_line_numbers', GESHI_NO_LINE_NUMBERS);
$inline_code = variable_get('geshifilter_inline_code_' . $format, FALSE);
if ($long) {
$text = t('<h3>Code:</h3>');
if (!$types[0]) {
$text .= t('<p>To post highlighted code, surround it code with <blockcode [type="<em>language</em>"]>...</blockcode> tags.</p><p>E.g. actionscript block code:<pre><blockcode type="<em>actionscript</em>"><br />...<br /></blockcode></pre></p>');
if ($inline_code) {
$text .= t('<p>You may also post highlighted inline code surrounding it with <code [type="<em>language</em>"]>...</code> tags.</p><p>E.g. highlight actionscript inline code:<pre><code type="<em>actionscript</em>">...</code></pre></p>');
}
if ($default_type) {
$text .= t('<p>If you don\'t use <em>type="language"</em> param or specify an unsupported language, the code will be highlighted as %default-code code.</p>', array(
'%default-code' => theme('placeholder', $default_type),
));
}
else {
$text .= t('<p>If you don\'t use <em>type="language"</em> param or specify an unsupported language, the code will not be highlighted.</p>');
}
$supported_types = array_keys($types, TRUE);
$text .= t('<p>The following languages are supported for highlight:<br />%type_list.</p>', array(
'%type_list' => theme('item_list', $supported_types),
));
}
else {
$text .= t('<p>To post code, surround it with <blockcode>...</blockcode> tags.</p><p>E.g. <pre><blockcode><br />...<br /></blockcode></pre></p>');
if ($inline_code) {
$text .= t('<p>You may also post inline code surrounding it with <code>...</code> tags.</p><p>E.g.: <pre><code>...</code></pre></p>');
}
if ($default_type) {
$text .= t('<p>By default, the code will be highlighted as %default-code code.</p>', array(
'%default-code' => theme('placeholder', $default_type),
));
}
else {
$text .= t('<p>The code will not be highlighted.</p>');
}
}
if ($line_numbers == GESHI_NORMAL_LINE_NUMBERS || $line_numbers == GESHI_FANCY_LINE_NUMBERS) {
if ($start_param) {
$text .= ' ' . t('<p>The code will be numbered. You can make the line numbers start at any number using <em>start=number</em> param</p><p>E.g. highlight actionscript code and start line number at 5: <pre><blockcode type="<em>actionscript</em>" start="<em>5</em>"><br />...<br /></blockcode></pre></p>');
}
else {
$text .= ' ' . t('<p>The code will be numbered.</p>');
}
}
return $text;
}
else {
$text = '';
if (!$types[0]) {
$text .= t('You may post block code using <blockcode [type="<em>language</em>"]>...</blockcode> tags. ');
if ($inline_code) {
$text .= t('You may also post inline code using <code [type="<em>language</em>"]>...</code> tags.');
}
}
else {
$text .= t('You may post block code using <blockcode>...</blockcode> tags. ');
if ($inline_code) {
$text .= t('You may also post inline code using <code>...</code> tags.');
}
}
return $text;
}
}
function geshifilter_admin_settings_form() {
$form = array();
$form['geshi_library'] = array(
'#type' => 'fieldset',
'#title' => t('GeSHi library'),
'#collapsible' => true,
);
$form['geshi_library']['geshifilter_geshi_dir'] = array(
'#type' => 'textfield',
'#title' => t('GeSHi Directory'),
'#default_value' => variable_get('geshifilter_geshi_dir', drupal_get_path('module', 'geshifilter') . '/geshi'),
'#description' => t('Location of directory where geshi.php is. i.e: "modules/geshifilter/geshi" (without quotes).'),
'#required' => TRUE,
);
$form['geshi_library']['geshifilter_lang_dir'] = array(
'#type' => 'textfield',
'#title' => t('Languages directory'),
'#default_value' => variable_get('geshifilter_lang_dir', drupal_get_path('module', 'geshifilter') . '/geshi/geshi'),
'#description' => t('Location where GeSHi languages files reside. Languages files are files with the names of languages, ended with .php extension. i.e: "modules/geshifilter/geshi/geshi" (without quotes).'),
'#required' => TRUE,
);
if (_geshifilter_load_geshi()) {
$form['geshi_theming'] = array(
'#type' => 'fieldset',
'#title' => t('Theming, styling and CSS'),
);
$form['geshi_theming']['geshifilter_code_container'] = array(
'#type' => 'radios',
'#title' => t('Code Container'),
'#default_value' => variable_get('geshifilter_code_container', GESHI_HEADER_PRE),
'#options' => array(
GESHI_HEADER_PRE => t('Use <pre> container'),
GESHI_HEADER_DIV => t('Use <div> container'),
GESHI_HEADER_NONE => t('No container'),
),
'#description' => t('Define the container element to put the highlighted source code in. (GeSHi documentation: !link).', array(
'!link' => l('The Code Container', 'http://qbnz.com/highlighter/geshi-doc.html#the-code-container'),
)),
);
$form['geshi_theming']['geshifilter_css_mode'] = array(
'#type' => 'radios',
'#title' => t('CSS mode'),
'#default_value' => variable_get('geshifilter_css_mode', GESHIFILTER_CSS_INLINE),
'#options' => array(
GESHIFILTER_CSS_INLINE => t('Use in-line styles'),
GESHIFILTER_CSS_CLASSES => t('Use CSS classes'),
),
'#description' => t('Using CSS classes to highlight your code instead of in-lining the styles is more compliant (the style attribute is deprecating in XHTML 2.0) and results in far less outputted code (GeSHi documentation: !link).', array(
'!link' => l('Using CSS Classes', 'http://qbnz.com/highlighter/geshi-doc.html#using-css-classes'),
)),
);
$form['geshi_theming']['geshifilter_line_numbers'] = array(
'#type' => 'radios',
'#title' => t('Line Numbers'),
'#default_value' => variable_get('geshifilter_line_numbers', GESHI_NO_LINE_NUMBERS),
'#options' => array(
GESHI_NO_LINE_NUMBERS => t('Disable line numbers'),
GESHI_NORMAL_LINE_NUMBERS => t('Use normal line numbering'),
GESHI_FANCY_LINE_NUMBERS => t('Use fancy line numbering'),
),
'#description' => t('Add line numbers to code. Fancy line numbers means that you can specify a different style for each n<sup>th</sup> line number (GeSHi documentation: !link).', array(
'!link' => l('Line Numbers', 'http://qbnz.com/highlighter/geshi-doc.html#line-numbers'),
)),
);
$form['geshi_theming']['geshifilter_fancy_number'] = array(
'#type' => 'textfield',
'#size' => 2,
'#maxlength' => 2,
'#title' => t('Fancy number each'),
'#default_value' => variable_get('geshifilter_fancy_number', 5),
'#description' => t('Line numbers will be styled with a different style every n line numbers. (GeSHi documentation: !link).', array(
'!link' => l('Line Numbers', 'http://qbnz.com/highlighter/geshi-doc.html#line-numbers'),
)),
);
$form['geshi_theming']['geshifilter_start_attribute'] = array(
'#type' => 'checkbox',
'#title' => t('Allow <em>start</em> attribute'),
'#default_value' => variable_get('geshifilter_start_attribute', FALSE),
'#description' => t('Allow users to make the line numbers start at any number using the <em>start=number</em> attribute. This feature will break XHTML strict compliancy (GeSHi documentation: !link).', array(
'!link' => l('Choosing a Start Number', 'http://qbnz.com/highlighter/geshi-doc.html#starting-line-numbers'),
)),
);
$form['inline'] = array(
'#type' => 'fieldset',
'#title' => t('In-line styles'),
'#collapsible' => true,
'#collapsed' => true,
);
$form['inline']['geshifilter_overall_style'] = array(
'#type' => 'textfield',
'#maxlength' => 255,
'#title' => t('Overall code block style'),
'#default_value' => variable_get('geshifilter_overall_style', ''),
'#description' => t('Style the overall code block. For example, you can set the border style/colour, any margins and padding etc. (GeSHi documentation: !link).', array(
'!link' => l('The Overall Styles', 'http://qbnz.com/highlighter/geshi-doc.html#the-overall-styles'),
)),
);
$form['inline']['geshifilter_number_style'] = array(
'#type' => 'textfield',
'#maxlength' => 255,
'#title' => t('Line number style'),
'#default_value' => variable_get('geshifilter_number_style', ''),
'#description' => t('(GeSHi documentation: !link).', array(
'!link' => l('Line Number Styles', 'http://qbnz.com/highlighter/geshi-doc.html#line-number-styles'),
)),
);
$form['inline']['geshifilter_fancy_number_style'] = array(
'#type' => 'textfield',
'#maxlength' => 255,
'#title' => t('Fancy line number style'),
'#default_value' => variable_get('geshifilter_fancy_number_style', 'font-weight: bold;'),
'#description' => t('(GeSHi documentation: !link).', array(
'!link' => l('Line Number Styles', 'http://qbnz.com/highlighter/geshi-doc.html#line-number-styles'),
)),
);
$form['inline']['geshifilter_code_style'] = array(
'#type' => 'textfield',
'#maxlength' => 255,
'#title' => t('Code style'),
'#default_value' => variable_get('geshifilter_code_style', 'font-weight: normal;'),
'#description' => t('Explicitly override the styles you set for line numbers (GeSHi documentation: !link).', array(
'!link' => l('Styling Line Numbers', 'http://qbnz.com/highlighter/geshi-doc.html#styling-line-numbers'),
)),
);
}
return system_settings_form($form);
}
function geshifilter_admin_settings_form_validate($form_id, $form_values) {
if (!is_dir($form_values['geshifilter_geshi_dir'])) {
form_set_error('geshifilter_geshi_dir', t('The directory "%geshi-directory" does not exist.', array(
'%geshi-directory' => $form_values['geshifilter_geshi_dir'],
)));
}
if (!is_file($form_values['geshifilter_geshi_dir'] . '/geshi.php')) {
form_set_error('geshifilter_geshi_dir', t('Unable to find the GeSHi library (geshi.php) in %geshi-directory.', array(
'%geshi-directory' => $form_values['geshifilter_geshi_dir'],
)));
}
if (!is_dir($form_values['geshifilter_lang_dir'])) {
form_set_error('geshifilter_lang_dir', t('The GeSHi languages directory %directory does not exist.', array(
'%directory' => $form_values['geshifilter_lang_dir'],
)));
}
$files = file_scan_directory($form_values['geshifilter_lang_dir'], '\\.php$', array(
'.',
'..',
'CVS',
'geshi.php',
), 0, FALSE, 'name');
if (count($files) == 0) {
drupal_set_message(t('No language pattern files found. Are you sure to have correctly installed the GeShi package?'));
}
}
function geshifilter_filter($op, $delta = 0, $format = -1, $text = '') {
switch ($op) {
case 'list':
return array(
0 => t('GeSHi filter'),
);
case 'description':
return t('Allows users to post hightlighted code verbatim using <blockcode type="<em>language</em>"> tag.');
case 'settings':
$lang_dir = variable_get('geshifilter_lang_dir', drupal_get_path('module', 'geshifilter') . '/geshi/geshi');
$files = file_scan_directory($lang_dir, '\\.php$', array(
'.',
'..',
'CVS',
'geshi.php',
), 0, FALSE, 'name');
$languages = drupal_map_assoc(array_keys($files));
uasort($languages, 'strnatcasecmp');
$languages_select = $languages;
$languages_select[0] = t('- DO NOT HIGHLIGHT -');
$form['geshifilter'] = array(
'#type' => 'fieldset',
'#title' => t('GeSHi filter'),
);
$form['geshifilter']['geshifilter_inline_code_' . $format] = array(
'#type' => 'checkbox',
'#title' => t('Highlight inline code'),
'#default_value' => variable_get('geshifilter_inline_code_' . $format, FALSE),
'#description' => t('Enable highligthing for code surrounded by <code>...</code> tags.'),
);
$form['geshifilter']['geshifilter_default_type_' . $format] = array(
'#type' => 'select',
'#title' => t('Default language'),
'#default_value' => variable_get('geshifilter_default_type_' . $format, 0),
'#options' => $languages_select,
'#description' => t('Default language pattern used to highlight posted code where type="<em>language</em>" param is omitted.'),
);
$form['geshifilter']['geshifilter_types_' . $format] = array(
'#type' => 'checkboxes',
'#title' => t('Allowed Languages'),
'#default_value' => variable_get('geshifilter_types_' . $format, array()),
'#options' => $languages,
'#description' => t('Check every languages you want to be allowed for highlighting (i.e. usable in <em>lang</em> param).'),
);
$form['geshifilter']['format'] = array(
'#type' => 'hidden',
'#default_value' => $format,
);
return $form;
case 'prepare':
return $text;
case 'process':
return _geshifilter_process_code($format, $text);
default:
return $text;
}
}
function _geshifilter_load_geshi() {
$geshi_lib = variable_get('geshifilter_geshi_dir', drupal_get_path('module', 'geshifilter') . '/geshi') . '/geshi.php';
if (file_exists($geshi_lib)) {
require_once $geshi_lib;
return TRUE;
}
else {
drupal_set_message(t('GeSHi library not found'), 'error');
return FALSE;
}
}
function _geshifilter_process_code($format, $text, $flags = '') {
if (!_geshifilter_load_geshi()) {
return $text;
}
$lang_dir = variable_get('geshifilter_lang_dir', drupal_get_path('module', 'geshifilter') . '/geshi/geshi');
$types = variable_get('geshifilter_types_' . $format, array());
$code_container = variable_get('geshifilter_code_container', GESHI_HEADER_PRE);
$line_numbers = variable_get('geshifilter_line_numbers', GESHI_NO_LINE_NUMBERS);
$fancy_number = variable_get('geshifilter_fancy_number', 5);
$start_param = variable_get('geshifilter_start_attribute', FALSE);
$overall_style = variable_get('geshifilter_overall_style', '');
$number_style = variable_get('geshifilter_number_style', '');
$fancy_number_style = variable_get('geshifilter_fancy_number_style', 'font-weight: bold;');
$code_style = variable_get('geshifilter_code_style', 'font-weight: normal;');
$inline_code = variable_get('geshifilter_inline_code_' . $format, FALSE);
$tags = 'blockcode' . ($inline_code ? '|code' : '');
if (preg_match_all('/<(' . $tags . ')((?:\\s(?:.|\\s|\\z)*?)*)\\s*>((?:.|\\s|\\z)*?)<\\/\\1\\s*>/i', $text, $match)) {
foreach ($match[3] as $key => $value) {
preg_match_all('/(type|start)\\s*=\\s*[\\"]((?:.|\\s|\\z)*?)[\\"]/i', $match[2][$key], $param);
$lang = variable_get('geshifilter_default_type_' . $format, 0);
$start = 1;
foreach ($param[2] as $p_key => $p_value) {
if ($param[1][$p_key] == 'type' && in_array($p_value, $types) && $types[$p_value]) {
$lang = $p_value;
}
if (($line_numbers == GESHI_NORMAL_LINE_NUMBERS || $line_numbers == GESHI_FANCY_LINE_NUMBERS) && $start_param) {
if ($param[1][$p_key] == 'start' && $p_value) {
$start = $p_value;
}
}
}
$matched = decode_entities($value);
$matched = preg_replace("@<br />@", "", $matched);
$matched = preg_replace("@<p>|</p>@", "", $matched);
$geshi = new GeSHi($matched, $lang, $lang_dir);
if (variable_get('geshifilter_css_mode', GESHIFILTER_CSS_INLINE) == GESHIFILTER_CSS_CLASSES) {
$geshi
->enable_classes(TRUE);
}
if ($match[1][$key] == 'code') {
$geshi
->set_header_type(GESHI_HEADER_NONE);
}
else {
$geshi
->set_header_type($code_container);
}
if ($match[1][$key] != 'code') {
$geshi
->set_overall_class('geshifilter');
}
if ($line_numbers != GESHI_NO_LINE_NUMBERS && $match[1][$key] != 'code') {
$geshi
->enable_line_numbers($line_numbers, $line_numbers == GESHI_FANCY_LINE_NUMBERS ? $fancy_number : null);
if ($start_param) {
$geshi
->start_line_numbers_at($start);
}
}
$geshi
->set_overall_style($overall_style);
$geshi
->set_line_style($number_style, $fancy_number_style);
$geshi
->set_code_style($code_style);
if ($match[1][$key] == 'code') {
$text = str_replace($match[0][$key], '<code class="geshifilter' . ($lang ? ' ' . $lang : '') . '">' . $geshi
->parse_code() . '</code>', $text);
}
else {
$text = str_replace($match[0][$key], $geshi
->parse_code(), $text);
}
}
}
return $text;
}