From fa48de33c2f6cefbac8bfec7cde75b75390d5f39 Mon Sep 17 00:00:00 2001 From: redmatrix Date: Wed, 15 Jun 2016 19:44:15 -0700 Subject: provide syntax based [colour] highlighting on code blocks for popular languages. I'm not happy with the line height on the list elements but couldn't see where this was defaulted. This uses the syntax [code=xxx]some code snippet[/code], where xxx represents a code/language style - with about 18 builtins. --- .../Text/Highlighter/Renderer/Html.php | 465 +++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 library/Text_Highlighter/Text/Highlighter/Renderer/Html.php (limited to 'library/Text_Highlighter/Text/Highlighter/Renderer/Html.php') diff --git a/library/Text_Highlighter/Text/Highlighter/Renderer/Html.php b/library/Text_Highlighter/Text/Highlighter/Renderer/Html.php new file mode 100644 index 000000000..5d6e56ae1 --- /dev/null +++ b/library/Text_Highlighter/Text/Highlighter/Renderer/Html.php @@ -0,0 +1,465 @@ + + * @copyright 2004-2006 Andrey Demenev + * @license http://www.php.net/license/3_0.txt PHP License + * @version CVS: $Id$ + * @link http://pear.php.net/package/Text_Highlighter + */ + +/** + * @ignore + */ + +require_once 'Text/Highlighter/Renderer.php'; +require_once 'Text/Highlighter/Renderer/Array.php'; + +// BC trick : only define constants if Text/Highlighter.php +// is not yet included +if (!defined('HL_NUMBERS_LI')) { + /**#@+ + * Constant for use with $options['numbers'] + */ + /** + * use numbered list, deprecated, use HL_NUMBERS_OL instaed + * @deprecated + */ + define ('HL_NUMBERS_LI' , 1); + /** + * Use 2-column table with line numbers in left column and code in right column. + */ + define ('HL_NUMBERS_TABLE' , 2); + /**#@-*/ +} + + +/**#@+ + * Constant for use with $options['numbers'] + */ +/** + * Use numbered list + */ +define ('HL_NUMBERS_OL', 1); +/** + * Use non-numbered list + */ +define ('HL_NUMBERS_UL', 3); +/**#@-*/ + + +/** + * HTML renderer + * + * Elements of $options argument of constructor (each being optional): + * + * - 'numbers' - Line numbering style 0 or {@link HL_NUMBERS_TABLE} + * or {@link HL_NUMBERS_UL} or {@link HL_NUMBERS_OL} + * - 'numbers_start' - starting number for numbered lines + * - 'tabsize' - Tab size + * - 'style_map' - Mapping of keywords to formatting rules using inline styles + * - 'class_map' - Mapping of keywords to formatting rules using class names + * - 'doclinks' - array that has keys "url", "target" and "elements", used for + * generating links to online documentation + * - 'use_language' - class names will be prefixed with language, like "php-reserved" or "css-code" + * + * Example of setting documentation links: + * $options['doclinks'] = array( + * 'url' => 'http://php.net/%s', + * 'target' => '_blank', + * 'elements' => array('reserved', 'identifier') + * ); + * + * Example of setting class names map: + * $options['class_map'] = array( + * 'main' => 'my-main', + * 'table' => 'my-table', + * 'gutter' => 'my-gutter', + * 'brackets' => 'my-brackets', + * 'builtin' => 'my-builtin', + * 'code' => 'my-code', + * 'comment' => 'my-comment', + * 'default' => 'my-default', + * 'identifier' => 'my-identifier', + * 'inlinedoc' => 'my-inlinedoc', + * 'inlinetags' => 'my-inlinetags', + * 'mlcomment' => 'my-mlcomment', + * 'number' => 'my-number', + * 'quotes' => 'my-quotes', + * 'reserved' => 'my-reserved', + * 'special' => 'my-special', + * 'string' => 'my-string', + * 'url' => 'my-url', + * 'var' => 'my-var', + * ); + * + * Example of setting styles mapping: + * $options['style_map'] = array( + * 'main' => 'color: black', + * 'table' => 'border: 1px solid black', + * 'gutter' => 'background-color: yellow', + * 'brackets' => 'color: blue', + * 'builtin' => 'color: red', + * 'code' => 'color: green', + * 'comment' => 'color: orange', + * // .... + * ); + * + * + * @author Andrey Demenev + * @category Text + * @package Text_Highlighter + * @copyright 2004-2006 Andrey Demenev + * @license http://www.php.net/license/3_0.txt PHP License + * @version Release: @package_version@ + * @link http://pear.php.net/package/Text_Highlighter + */ + +class Text_Highlighter_Renderer_Html extends Text_Highlighter_Renderer_Array +{ + + /**#@+ + * @access private + */ + + /** + * Line numbering style + * + * @var integer + */ + var $_numbers = 0; + + /** + * For numberered lines - where to start + * + * @var integer + */ + var $_numbers_start = 0; + + /** + * Tab size + * + * @var integer + */ + var $_tabsize = 4; + + /** + * Highlighted code + * + * @var string + */ + var $_output = ''; + + /** + * Mapping of keywords to formatting rules using inline styles + * + * @var array + */ + var $_style_map = array(); + + /** + * Mapping of keywords to formatting rules using class names + * + * @var array + */ + var $_class_map = array( + 'main' => 'hl-main', + 'table' => 'hl-table', + 'gutter' => 'hl-gutter', + 'brackets' => 'hl-brackets', + 'builtin' => 'hl-builtin', + 'code' => 'hl-code', + 'comment' => 'hl-comment', + 'default' => 'hl-default', + 'identifier' => 'hl-identifier', + 'inlinedoc' => 'hl-inlinedoc', + 'inlinetags' => 'hl-inlinetags', + 'mlcomment' => 'hl-mlcomment', + 'number' => 'hl-number', + 'prepro' => 'hl-prepro', + 'quotes' => 'hl-quotes', + 'reserved' => 'hl-reserved', + 'special' => 'hl-special', + 'string' => 'hl-string', + 'types' => 'hl-types', + 'url' => 'hl-url', + 'var' => 'hl-var', + ); + + /** + * Setup for links to online documentation + * + * This is an array with keys: + * - url, ex. http://php.net/%s + * - target, ex. _blank, default - no target + * - elements, default is array('reserved', 'identifier') + * + * @var array + */ + var $_doclinks = array(); + + /**#@-*/ + + + /** + * Resets renderer state + * + * @access protected + * + * + * Descendents of Text_Highlighter call this method from the constructor, + * passing $options they get as parameter. + */ + function reset() + { + $this->_output = ''; + if (isset($this->_options['numbers'])) { + $this->_numbers = (int)$this->_options['numbers']; + if ($this->_numbers != HL_NUMBERS_LI + && $this->_numbers != HL_NUMBERS_UL + && $this->_numbers != HL_NUMBERS_OL + && $this->_numbers != HL_NUMBERS_TABLE + ) { + $this->_numbers = 0; + } + } + if (isset($this->_options['tabsize'])) { + $this->_tabsize = $this->_options['tabsize']; + } + if (isset($this->_options['numbers_start'])) { + $this->_numbers_start = intval($this->_options['numbers_start']); + } + if (isset($this->_options['doclinks']) && + is_array($this->_options['doclinks']) && + !empty($this->_options['doclinks']['url']) + ) { + + $this->_doclinks = $this->_options['doclinks']; // keys: url, target, elements array + + if (empty($this->_options['doclinks']['elements'])) { + $this->_doclinks['elements'] = array('reserved', 'identifier'); + } + } + if (isset($this->_options['style_map'])) { + $this->_style_map = $this->_options['style_map']; + } + if (isset($this->_options['class_map'])) { + $this->_class_map = array_merge($this->_class_map, $this->_options['class_map']); + } + $this->_htmlspecialchars = true; + + } + + + /** + * Given a CSS class name, returns the class name + * with language name prepended, if necessary + * + * @access private + * + * @param string $class Token class + */ + function _getFullClassName($class) + { + if (!empty($this->_options['use_language'])) { + $the_class = $this->_language . '-' . $class; + } else { + $the_class = $class; + } + return $the_class; + } + + /** + * Signals that no more tokens are available + * + * @access public + */ + function finalize() + { + + // get parent's output + parent::finalize(); + $output = parent::getOutput(); + + $html_output = ''; + + $numbers_li = false; + + if ( + $this->_numbers == HL_NUMBERS_LI || + $this->_numbers == HL_NUMBERS_UL || + $this->_numbers == HL_NUMBERS_OL + ) + { + $numbers_li = true; + } + + // loop through each class=>content pair + foreach ($output AS $token) { + + if ($this->_enumerated) { + $key = false; + $the_class = $token[0]; + $content = $token[1]; + } else { + $key = key($token); + $the_class = $key; + $content = $token[$key]; + } + + $span = $this->_getStyling($the_class); + $decorated_output = $this->_decorate($content, $key); + + + if ($numbers_li == true) { + // end span tags before end of li, and re-open on next line + $lastSpanTag = str_replace("%s", "", $span); + $span = sprintf($span, $decorated_output); + $span = str_replace("\n", "\n
  • $lastSpanTag ", $span); + $html_output .= $span; + } else { + $html_output .= sprintf($span, $decorated_output); + } + + + } + + // format lists + if (!empty($this->_numbers) && $numbers_li == true) { + + + // additional whitespace for browsers that do not display + // empty list items correctly + $this->_output = '
  •  ' . $html_output . '
  • '; + + $start = ''; + if ($this->_numbers == HL_NUMBERS_OL && intval($this->_numbers_start) > 0) { + $start = ' start="' . $this->_numbers_start . '"'; + } + + $list_tag = 'ol'; + if ($this->_numbers == HL_NUMBERS_UL) { + $list_tag = 'ul'; + } + + + $this->_output = '<' . $list_tag . $start + . ' ' . $this->_getStyling('main', false) . '>' + . $this->_output . ''; + + // render a table + } else if ($this->_numbers == HL_NUMBERS_TABLE) { + + + $start_number = 0; + if (intval($this->_numbers_start)) { + $start_number = $this->_numbers_start - 1; + } + + $numbers = ''; + + $nlines = substr_count($html_output,"\n")+1; + for ($i=1; $i <= $nlines; $i++) { + $numbers .= ($start_number + $i) . "\n"; + } + $this->_output = '_getStyling('table', false) . ' width="100%">' . + '
    _getStyling('gutter', false) .' align="right" valign="top">' . + '
    ' . $numbers . '
    _getStyling('main', false) . + ' valign="top">
    ' .
    +                             $html_output . '
    '; + } + if (!$this->_numbers) { + $this->_output = '
    ' . $html_output . '
    '; + } + $this->_output = '
    _getStyling('main', false) . '>' . $this->_output . '
    '; + } + + + /** + * Provides additional formatting to a keyword + * + * @param string $content Keyword + * @return string Keyword with additional formatting + * @access public + * + */ + function _decorate($content, $key = false) + { + // links to online documentation + if (!empty($this->_doclinks) && + !empty($this->_doclinks['url']) && + in_array($key, $this->_doclinks['elements']) + ) { + + $link = '_doclinks['target'])) { + $link.= ' target="' . $this->_doclinks['target'] . '"'; + } + $link .= '>'; + $link.= $content; + $link.= ''; + + $content = $link; + + } + + return $content; + } + + /** + * Returns class and/or style attribute, + * optionally enclosed in a span tag + * + * @param string $class Class name + * @paran boolean $span_tag Whether or not to return styling attributes in a >span< tag + * @return string span tag or just a class and/or style attributes + * @access private + */ + function _getStyling($class, $span_tag = true) + { + $attrib = ''; + if (!empty($this->_style_map) && + !empty($this->_style_map[$class]) + ) { + $attrib = 'style="'. $this->_style_map[$class] .'"'; + } + if (!empty($this->_class_map) && + !empty($this->_class_map[$class]) + ) { + if ($attrib) { + $attrib .= ' '; + } + $attrib .= 'class="'. $this->_getFullClassName($this->_class_map[$class]) .'"'; + } + + if ($span_tag) { + $span = '%s'; + return $span; + } else { + return $attrib; + } + + } +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * c-hanging-comment-ender-p: nil + * End: + */ + +?> -- cgit v1.2.3