'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; } } /** * Implementation of hook_filter_tips() */ 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('

Code:

'); //some language are allowed, type param is supported if (!$types[0]) { $text .= t('

To post highlighted code, surround it code with <blockcode [type="language"]>...</blockcode> tags.

E.g. actionscript block code:

<blockcode type="actionscript">
...
</blockcode>

'); if ($inline_code) { $text .= t('

You may also post highlighted inline code surrounding it with <code [type="language"]>...</code> tags.

E.g. highlight actionscript inline code:

<code type="actionscript">...</code>

'); } if ($default_type) { $text .= t('

If you don\'t use type="language" param or specify an unsupported language, the code will be highlighted as %default-code code.

', array('%default-code' => theme('placeholder', $default_type))); } else { $text .= t('

If you don\'t use type="language" param or specify an unsupported language, the code will not be highlighted.

'); } $supported_types = array_keys($types, TRUE); $text .= t('

The following languages are supported for highlight:
%type_list.

', array('%type_list' => theme('item_list', $supported_types))); } //no languages allowed, type param is not supported else { $text .= t('

To post code, surround it with <blockcode>...</blockcode> tags.

E.g.

<blockcode>
...
</blockcode>

'); if ($inline_code) { $text .= t('

You may also post inline code surrounding it with <code>...</code> tags.

E.g.:

<code>...</code>

'); } if ($default_type) { $text .= t('

By default, the code will be highlighted as %default-code code.

', array('%default-code' => theme('placeholder', $default_type))); } else { $text .= t('

The code will not be highlighted.

'); } } if ($line_numbers == GESHI_NORMAL_LINE_NUMBERS || $line_numbers == GESHI_FANCY_LINE_NUMBERS) { //line numbers if ($start_param) { $text .= ' '. t('

The code will be numbered. You can make the line numbers start at any number using start=number param

E.g. highlight actionscript code and start line number at 5:

<blockcode type="actionscript" start="5">
...
</blockcode>

'); } else { $text .= ' '. t('

The code will be numbered.

'); } } return $text; } else { $text=''; //some language are allowed, type param is supported if (!$types[0]) { $text .= t('You may post block code using <blockcode [type="language"]>...</blockcode> tags. '); if ($inline_code) { $text .= t('You may also post inline code using <code [type="language"]>...</code> tags.'); } } //no languages allowed, type param is not supported 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; } } /** * Admin page linked from menu */ function geshifilter_admin_settings_form() { $form = array(); // GeSHi library $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 ); // load GeSHi library for defined constants and present the // GeSHi filter settings if successful if (_geshifilter_load_geshi()) { $form['geshi_theming'] = array( '#type' => 'fieldset', '#title' => t('Theming, styling and CSS'), ); // Code container $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'))), ); // CSS mode $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'))), ); // Line numbers $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 nth 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 start attribute'), '#default_value' => variable_get('geshifilter_start_attribute', FALSE), '#description' => t('Allow users to make the line numbers start at any number using the start=number 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'))), ); // inline styles $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); } /* * Validate the settings form */ function geshifilter_admin_settings_form_validate($form_id, $form_values) { // Check if geshi directory exists. 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']))); } // Check if geshi.php exists 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']))); } // Check if languages directory exists. 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']))); } // Check if there are some language files in the directory $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?')); } } /** * Implementation of hook_filter() */ function geshifilter_filter($op, $delta = 0, $format = -1, $text = '') { //disable cache for developpement cause nocache doesn't work switch ($op) { case 'list': return array(0 => t('GeSHi filter')); case 'description': return t('Allows users to post hightlighted code verbatim using <blockcode type="language"> tag.'); case 'settings': $lang_dir = variable_get('geshifilter_lang_dir', drupal_get_path('module', 'geshifilter') .'/geshi/geshi'); // Find languages in the directory, we get a table where key == value $files = file_scan_directory($lang_dir, '\.php$', array('.', '..', 'CVS', 'geshi.php'), 0, FALSE, 'name'); //produce an associative array whit keys equal to values $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="language" 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 lang param).'), ); //pass the format value, so filter_admin_configure_validate can know which format is being processed $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; } } /** * Helper function for loading the GeSHi library */ 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 = '') { // load the GeSHi library and just return text if not successful 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)) { // $match[0][xx] .... fully matched string ... // $match[1][xx] .... tag // $match[2][xx] .... full params string type="language"... // $match[3][xx] .... code to highlight foreach ($match[3] as $key => $value) { preg_match_all('/(type|start)\s*=\s*[\"]((?:.|\s|\z)*?)[\"]/i', $match[2][$key], $param); //let lang and language tags for backward compatibility // $param[0][xx] .... fully matched string type="language" // $param[1][xx] .... param name // $param[2][xx] .... param value //default values $lang = variable_get('geshifilter_default_type_'. $format, 0); $start = 1; foreach ($param[2] as $p_key => $p_value) { //if lang is known, allowed and found if ($param[1][$p_key] == 'type' && in_array($p_value, $types) && $types[$p_value]) { $lang = $p_value; } //if start param has been allowed if (($line_numbers == GESHI_NORMAL_LINE_NUMBERS ||$line_numbers == GESHI_FANCY_LINE_NUMBERS) && $start_param) { //if start param is found if ($param[1][$p_key] == 'start' && $p_value) { $start = $p_value; } } } // geshi will reencode these $matched = decode_entities($value); // undo nl and p formatting $matched = preg_replace("@
@", "", $matched); $matched = preg_replace("@

|

@", "", $matched); $geshi = new GeSHi($matched, $lang, $lang_dir); // enable usage of CSS classes instead of inline styles // (should be the first method of the GeSHi object to call according to // http://qbnz.com/highlighter/geshi-doc.html#enabling-css-classes) 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'); } //line numbers 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); } } //styles $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], ''. $geshi->parse_code() .'', $text); } else { $text = str_replace($match[0][$key], $geshi->parse_code(), $text); } } } return $text; }