You are here

codefilter.module in Code Filter 6

Same filename and directory in other branches
  1. 8 codefilter.module
  2. 5 codefilter.module
  3. 7 codefilter.module

File

codefilter.module
View source
<?php

/**
 * Implementation of hook_filter_tips()
 */
function codefilter_filter_tips($delta, $format, $long = false) {
  if ($long) {
    return t('To post pieces of code, surround them with &lt;code&gt;...&lt;/code&gt; tags. For PHP code, you can use &lt;?php ... ?&gt;, which will also colour it based on syntax.');
  }
  else {
    return t('You may post code using &lt;code&gt;...&lt;/code&gt; (generic) or &lt;?php ... ?&gt; (highlighted PHP) tags.');
  }
}

/**
 * Implementation of hook_init()
 *
 * Adds the codefilter stylesheet to the page
 */
function codefilter_init() {
  drupal_add_css(drupal_get_path('module', 'codefilter') . '/codefilter.css');
}

/**
 * Processes chunks of escaped PHP code into HTML.
 */
function codefilter_process_php($matches) {

  // 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('\\"', '"', $matches[1]));

  // 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">' . highlight_string("<?php\n{$text}\n?>", 1) . '</div>';

  // Remove newlines to avoid clashing with the linebreak filter
  $text = str_replace("\n", '', $text);
  return codefilter_fix_spaces($text);
}

/**
 * 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 PHP's 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($matches) {

  // Undo linebreak escaping
  $text = str_replace('&#10;', "\n", $matches[1]);

  // 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('/&lt;\\?php.+?\\?&gt;/s', 'codefilter_process_php_inline', $text);
  $text = '<code>' . codefilter_fix_spaces(str_replace(' ', '&nbsp;', $text)) . '</code>';
  if ($multiline) {
    $text = '<div class="codeblock">' . $text . '</div>';
  }

  // Remove newlines to avoid clashing with the linebreak filter
  return str_replace("\n", '', $text);
}
function codefilter_fix_spaces($text) {
  $text = preg_replace('@&nbsp;(?!&nbsp;)@', ' ', $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 />&nbsp;$1', $text);
  return $text;
}

/**
 * Escape code blocks during input filter 'prepare'.
 *
 * @param $text
 *   The string to escape.
 * @param $type
 *   The type of code block, either 'code' or 'php'.
 * @return
 *   The escaped string.
 */
function codefilter_escape($text, $type = 'code') {

  // 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(
    '',
    '&#10;',
  ), $text);

  // Add codefilter escape tags
  $text = "[codefilter_{$type}]{$text}[/codefilter_{$type}]";
  return $text;
}

/**
 * Callback to replace <code> elements.
 */
function _codefilter_escape_code_tag($matches) {
  return codefilter_escape($matches[1], 'code');
}

/**
 * Callback to replace <?php ?>, [?php ?], <% %>, and [% %] elements.
 */
function _codefilter_escape_php_tag($matches) {
  return codefilter_escape($matches[2], 'php');
}

/**
 * Implementation of hook_filter()
 */
function codefilter_filter($op, $delta = 0, $format = -1, $text = '') {
  switch ($op) {
    case 'list':
      return array(
        0 => t('Code filter'),
      );
    case 'description':
      return t('Allows users to post code verbatim using &lt;code&gt; and &lt;?php ?&gt; tags.');
    case 'prepare':

      /**
       * We replace <code> </code>, <?php ?>, [?php ?], to prevent other filters
       * from acting on them.
       */
      $text = preg_replace_callback('@<code>(.+?)</code>@s', '_codefilter_escape_code_tag', $text);
      $text = preg_replace_callback('@[\\[<](\\?php)(.+?)(\\?)[\\]>]@s', '_codefilter_escape_php_tag', $text);
      return $text;
    case 'process':
      $text = preg_replace_callback('@\\[codefilter_code\\](.+?)\\[/codefilter_code\\]@s', 'codefilter_process_code', $text);
      $text = preg_replace_callback('@\\[codefilter_php\\](.+?)\\[/codefilter_php\\]@s', 'codefilter_process_php', $text);
      return $text;
    default:
      return $text;
  }
}

Functions

Namesort descending Description
codefilter_escape Escape code blocks during input filter 'prepare'.
codefilter_filter Implementation of hook_filter()
codefilter_filter_tips Implementation of hook_filter_tips()
codefilter_fix_spaces
codefilter_init Implementation of hook_init()
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 to replace <code> elements.
_codefilter_escape_php_tag Callback to replace <?php ?>, [?php ?], <% %>, and [% %] elements.