geshifilter-8.x-2.0-beta1/src/GeshiFilterProcess.php
src/GeshiFilterProcess.php
<?php namespace Drupal\geshifilter; use Drupal\Component\Utility\Html; /** * Helpers functions related to processing the source code with geshi. */ class GeshiFilterProcess { /** * Geshifilter wrapper for highlight_string() processing of PHP. * * @param string $source_code * The source code. * @param bool $inline_mode * When to use inline styles(TRUE) or a css. * * @return string * The source code after being processed. */ public static function highlightStringProcess($source_code, $inline_mode) { // Make sure that the source code starts with < ?php and ends with ? >. $text = trim($source_code); if (substr($text, 0, 5) != '<?php') { $source_code = '<?php' . $source_code; } if (substr($text, -2) != '?>') { $source_code = $source_code . '?>'; } // Use the right container. $container = $inline_mode ? 'span' : 'div'; // Process with highlight_string() $text = '<' . $container . ' class="codeblock geshifilter">' . highlight_string($source_code, TRUE) . '</' . $container . '>'; // Remove newlines (added by highlight_string()) to avoid issues with the // linebreak filter. $text = str_replace("\n", '', $text); return $text; } /** * Geshifilter wrapper for GeSHi processing. * * @param string $source_code * Source code to process. * @param string $lang * Language from sourcecode. * @param int $line_numbering * The line numbering mode, one of LINE_NUMBERS_* from GeshiFilter class. * @param int $linenumbers_start * The line number to start from. * @param bool $inline_mode * When to write all styles inline or from a css. * @param string $title * The title to use in code. * @param array $special_lines * Special lines to highlight. * * @return string * The sourcecode after process by Geshi. */ public static function geshiProcess($source_code, $lang, $line_numbering = 0, $linenumbers_start = 1, $inline_mode = FALSE, $title = NULL, array $special_lines = []) { $config = \Drupal::config('geshifilter.settings'); // Load GeSHi library (if not already). $geshi_library = GeshiFilter::loadGeshi(); if (!$geshi_library['loaded']) { \Drupal::messenger()->addError($geshi_library['error message']); return $source_code; } $source_code = trim($source_code, "\n\r"); // Create GeSHi object. $geshi = self::geshiFactory($source_code, $lang); // CSS mode. $ccs_mode = $config->get('css_mode'); if ($ccs_mode == GeshiFilter::CSS_CLASSES_AUTOMATIC || $ccs_mode == GeshiFilter::CSS_CLASSES_ONLY) { $geshi->enable_classes(TRUE); } self::overrideGeshiDefaults($geshi, $lang); // Some more GeSHi settings and parsing. if ($inline_mode) { // Inline source code mode. $geshi->set_header_type(GESHI_HEADER_NONE); // To make highlighting work we have to manually set a class on the code // element we will wrap the code in. // To counter a change between GeSHi version 1.0.7.22 and 1.0.8 (svn // commit 1610), we use both the language and overall_class for the class, // to mimic the 1.0.8 behavior, which is backward compatible. // $language and $overall_class are protected with $geshi, with no get // functions, recreate them manually. $overall_class = 'geshifilter-' . $lang; $code_class = "{$lang} {$overall_class}"; $source_code = '<span class="geshifilter"' . (isset($title) ? ' title="' . Html::escape($title) . '"' : '') . '><code class="' . $code_class . '">' . $geshi->parse_code() . '</code></span>'; } else { $geshi->highlight_lines_extra($special_lines); // How many spaces to use for tabs. $geshi->set_tab_width($config->get('tab_width')); // Block source code mode. $geshi->set_header_type((int) $config->get('code_container', GESHI_HEADER_PRE)); if ($line_numbering == 1) { $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS); $geshi->start_line_numbers_at($linenumbers_start); } elseif ($line_numbering >= 2) { $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, $line_numbering); $geshi->start_line_numbers_at($linenumbers_start); } if (isset($title)) { $source_code = '<div class="geshifilter-title">' . Html::escape($title) . '</div>'; } else { $source_code = ''; } $source_code .= '<div class="geshifilter">' . $geshi->parse_code() . '</div>'; } return $source_code; } /** * Helper function for overriding some GeSHi defaults. * * @param \Geshi $geshi * Geshi object. * @param string $langcode * The language. */ public static function overrideGeshiDefaults(\Geshi &$geshi, $langcode) { $config = \Drupal::config('geshifilter.settings'); // Override the some default GeSHi styles (e.g. GeSHi uses Courier by // default, which is ugly). $geshi->set_line_style('font-family: monospace; font-weight: normal;', 'font-family: monospace; font-weight: bold; font-style: italic;'); $geshi->set_code_style('font-family: monospace; font-weight: normal; font-style: normal'); // Overall class needed for CSS. $geshi->set_overall_class('geshifilter-' . $langcode); // Set keyword linking. $geshi->enable_keyword_links($config->get('enable_keyword_urls', TRUE)); } /** * General geshifilter processing function for a chunk of source code. * * @param string $source_code * Source code to process. * @param string $lang * Language from sourcecode. * @param int $line_numbering * The line numbering mode, one of LINE_NUMBERS_* from GeshiFilter class. * @param int $linenumbers_start * The line number to start from. * @param bool $inline_mode * When to write all styles inline or from a css. * @param string $title * The title to use in code. * @param array $special_lines * An array with the number of lines to highlight. * * @paran array $special_lines * Lines to highlight. * * @return string * The sourcecode after process by Geshi. */ public static function processSourceCode($source_code, $lang, $line_numbering = 0, $linenumbers_start = 1, $inline_mode = FALSE, $title = NULL, array $special_lines = []) { $config = \Drupal::config('geshifilter.settings'); // Process. if ($lang == 'php' && $config->get('use_highlight_string_for_php', FALSE)) { return self::highlightStringProcess($source_code, $inline_mode); } else { // Process with GeSHi. return self::geshiProcess($source_code, $lang, $line_numbering, $linenumbers_start, $inline_mode, $title, $special_lines); } } /** * Helper function for generating a GeSHi object. * * @param string $source_code * The source code to process. * @param string $language * The language to generate a GeSHi object for. * * @return \GeSHi * Return a Geshi class object. */ public static function geshiFactory($source_code, $language) { $available_languages = GeshiFilter::getAvailableLanguages(); $geshi = new \GeSHi($source_code, $language); $geshi->set_language_path($available_languages[$language]['language_path']); return $geshi; } }