codefilter.module in Code Filter 7
Same filename and directory in other branches
Text filter for highlighting PHP source code.
File
codefilter.moduleView source
<?php
/**
* @file
* Text filter for highlighting PHP source code.
*/
/**
* Processes chunks of escaped PHP code into HTML.
*/
function codefilter_process_php($text) {
// Note, pay attention to odd preg_replace-with-/e behaviour on slashes.
// Undo possible linebreak filter conversion.
$text = preg_replace('@</?(br|p)\\s*/?>@', '', str_replace('\\"', '"', $text));
// Undo the escaping in the prepare step.
$text = decode_entities($text);
// Trim leading and trailing linebreaks.
$text = trim($text, "\r\n");
// Highlight as PHP.
$text = '<div class="codeblock"><pre>' . highlight_string("<?php\n{$text}\n?>", 1) . '</pre></div>';
// Remove newlines to avoid clashing with the linebreak filter.
$text = str_replace("\n", '', $text);
return codefilter_fix_spaces($text);
}
/**
* Callback to replace content of the <?php ?> elements.
*/
function _codefilter_process_php_callback($matches) {
return codefilter_process_php($matches[1]);
}
/**
* Helper function for codefilter_process_code().
*/
function codefilter_process_php_inline($matches) {
// Undo nl2br.
$text = str_replace('<br />', '', $matches[0]);
// Decode entities (the highlighter re-entifies) and highlight text.
$text = highlight_string(decode_entities($text), 1);
// Remove PHPs own added code tags.
$text = str_replace(array(
'<code>',
'</code>',
"\n",
), array(
'',
'',
'',
), $text);
return $text;
}
/**
* Processes chunks of escaped code into HTML.
*/
function codefilter_process_code($text, $attributes = NULL) {
// Undo linebreak escaping.
$text = str_replace(' ', "\n", $text);
// Inline or block level piece?
$multiline = strpos($text, "\n") !== FALSE;
// Note, pay attention to odd preg_replace-with-/e behaviour on slashes.
$text = preg_replace("/^\n/", '', preg_replace('@</?(br|p)\\s*/?>@', '', str_replace('\\"', '"', $text)));
// Trim leading and trailing linebreaks.
$text = trim($text, "\n");
// Escape newlines.
$text = nl2br($text);
// PHP code in regular code.
$text = preg_replace_callback('/<\\?php.+?\\?>/s', 'codefilter_process_php_inline', $text);
$text = '<code' . $attributes . '>' . codefilter_fix_spaces(str_replace(' ', ' ', $text)) . '</code>';
$text = $multiline ? '<div class="codeblock">' . $text . '</div>' : $text;
// Remove newlines to avoid clashing with the linebreak filter.
return str_replace("\n", '', $text);
}
/**
* Callback to replace content of the <code> elements.
*
* @param array $matches
* An array of matches passed by preg_replace_callback().
*
* @return string
* A formatted string.
*/
function _codefilter_process_code_callback($matches) {
return codefilter_process_code($matches[2], $matches[1]);
}
/**
* Replace html space elements with literal space characters.
*
* @param string $text
* A string to fix spaces for.
*
* @return string
* A formatted string.
*/
function codefilter_fix_spaces($text) {
$text = preg_replace('@ (?! )@', ' ', $text);
// A single space before text is ignored by browsers. If a single space
// follows a break tag, replace it with a non-breaking space.
$text = preg_replace('@<br /> ([^ ])@', '<br /> $1', $text);
return $text;
}
/**
* Escape code blocks during input filter 'prepare'.
*
* @param string $text
* The string to escape.
* @param string $type
* The type of code block, either 'code' or 'php'.
* @param string|null $attributes
* (optional) The HTML attributes of the code block.
*
* @return string
* The escaped string.
*/
function codefilter_escape($text, $type = 'code', $attributes = NULL) {
// Note, pay attention to odd preg_replace-with-/e behaviour on slashes.
$text = check_plain(str_replace('\\"', '"', $text));
// Protect newlines from line break converter.
$text = str_replace(array(
"\r",
"\n",
), array(
'',
' ',
), $text);
// Prepare the class HTML attribute for the codefilter tag.
if (isset($attributes)) {
$attributes = ' ' . $attributes;
}
// Add codefilter escape tags.
$text = "[codefilter_{$type}{$attributes}]{$text}[/codefilter_{$type}]";
return $text;
}
/**
* Callback to escape content of <code> elements.
*/
function _codefilter_escape_code_tag_callback($matches) {
// Extract a potentially existing class HTML attribute.
$attributes = NULL;
if (!empty($matches[1]) && preg_match('@class="[^"]+"@', $matches[1], $class_matches)) {
$attributes = $class_matches[0];
}
return codefilter_escape($matches[2], 'code', $attributes);
}
/**
* Callback to escape content of <?php ?>, [?php ?], <% %>, and [% %] elements.
*/
function _codefilter_escape_php_tag_callback($matches) {
return codefilter_escape($matches[2], 'php');
}
/**
* Implements hook_filter_info().
*/
function codefilter_filter_info() {
$filters['codefilter'] = array(
'title' => t('Code filter'),
'description' => t('Allows users to post code verbatim using <code> and <?php ?> tags.'),
'prepare callback' => '_codefilter_prepare',
'process callback' => '_codefilter_process',
'settings callback' => '_codefilter_settings',
'default settings' => array(
'nowrap_expand' => FALSE,
'codefilter_prism' => FALSE,
),
'tips callback' => '_codefilter_tips',
);
return $filters;
}
/**
* Implements hook_filter_FILTER_prepare().
*
* Escape code tags to prevent other filters from acting on them.
* <code> </code>, <?php ?>, [?php ?], <% %>, and [% %] tags are escaped.
*/
function _codefilter_prepare($text, $format) {
$callback_prefix = $format->settings['codefilter_prism'] ? '_codefilter_prism' : '_codefilter';
$text = preg_replace_callback('@<code([^>]*)>(.+?)</code>@s', "{$callback_prefix}_escape_code_tag_callback", $text);
$text = preg_replace_callback('@[\\[<](\\?php)(.+?)(\\?)[\\]>]@s', "{$callback_prefix}_escape_php_tag_callback", $text);
return $text;
}
/**
* Implements hook_filter_FILTER_process().
*/
function _codefilter_process($text, $format) {
if ($format->settings['codefilter_prism'] && function_exists('_codefilter_prism_process_code_callback')) {
$text = preg_replace_callback('@\\[codefilter_prism_code( [^\\]]+)?\\](.+?)\\[/codefilter_prism_code\\]@s', '_codefilter_prism_process_code_callback', $text);
$text = preg_replace_callback('@\\[codefilter_prism_php\\](.+?)\\[/codefilter_prism_php\\]@s', '_codefilter_prism_process_php_callback', $text);
}
else {
$text = preg_replace_callback('@\\[codefilter_code( [^\\]]+)?\\](.+?)\\[/codefilter_code\\]@s', '_codefilter_process_code_callback', $text);
$text = preg_replace_callback('@\\[codefilter_php\\](.+?)\\[/codefilter_php\\]@s', '_codefilter_process_php_callback', $text);
}
// A hack, so we can conditionally nowrap based on filter settings.
// @todo Refactor how replacements are done so we can do this more cleanly.
if ($format->settings['nowrap_expand']) {
$text = str_replace('class="codeblock"', 'class="codeblock nowrap-expand"', $text);
}
return $text;
}
/**
* Implements hook_filter_FILTER_tips().
*/
function _codefilter_tips($format, $long = FALSE) {
if ($long) {
return t('To post pieces of code, surround them with <code>...</code> tags. For PHP code, you can use <?php ... ?>, which will also colour it based on syntax.');
}
else {
return t('You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.');
}
}
/**
* Settings callback for the codefilter filter.
*
* @see hook_filter_info()
* @see hook_filter_FILTER_settings()
*/
function _codefilter_settings($form, &$form_state, $filter, $format, $defaults) {
$filter->settings += $defaults;
$elements = array();
$elements['nowrap_expand'] = array(
'#type' => 'checkbox',
'#title' => t('Expand code boxes on hover.'),
'#description' => t('By default, code boxes inherit text wrapping from the active theme. With this setting, code boxes will not wrap, but will expand to full width on hover (with Javascript).'),
'#default_value' => $filter->settings['nowrap_expand'],
);
if (module_exists('codefilter_prism')) {
$elements['codefilter_prism'] = array(
'#type' => 'checkbox',
'#title' => t('Prism Library Support'),
'#description' => t('Enable code styling using the <a href="http://prismjs.com/">Prism library</a> (requires Javascript). To enable highlighting, download the prism.js and prism.js and add them to your site\'s libraries folder.'),
'#default_value' => $filter->settings['codefilter_prism'],
);
}
return $elements;
}
Functions
Name | Description |
---|---|
codefilter_escape | Escape code blocks during input filter 'prepare'. |
codefilter_filter_info | Implements hook_filter_info(). |
codefilter_fix_spaces | Replace html space elements with literal space characters. |
codefilter_process_code | Processes chunks of escaped code into HTML. |
codefilter_process_php | Processes chunks of escaped PHP code into HTML. |
codefilter_process_php_inline | Helper function for codefilter_process_code(). |
_codefilter_escape_code_tag_callback | Callback to escape content of <code> elements. |
_codefilter_escape_php_tag_callback | Callback to escape content of <?php ?>, [?php ?], <% %>, and [% %] elements. |
_codefilter_prepare | Implements hook_filter_FILTER_prepare(). |
_codefilter_process | Implements hook_filter_FILTER_process(). |
_codefilter_process_code_callback | Callback to replace content of the <code> elements. |
_codefilter_process_php_callback | Callback to replace content of the <?php ?> elements. |
_codefilter_settings | Settings callback for the codefilter filter. |
_codefilter_tips | Implements hook_filter_FILTER_tips(). |