123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- <?php
- /*
- * PicoGeSHi
- */
- class PicoGeSHi extends AbstractPicoPlugin
- {
- const API_VERSION = 3;
- protected $enabled = null;
- // only act if this var is set to true
- private $yeah = FALSE;
- public function onConfigLoaded(array &$config)
- {
- $this->debug = FALSE;
- $this->geshi_class = 'geshi';
- $this->geshi_line_numbers = FALSE;
- $this->geshi_fancy_line_numbers = 0;
- $this->geshi_line_start = 0;
- $this->geshi_template = "post";
- $this->geshi_enable_ids = FALSE;
- $this->geshi_col_enabled = TRUE;
- // default CSS template - path is relative to plugin dir (where __FILE__ resides)
- $this->css_template = "default.template.css";
- // not (currently) configurable
- // parsedown prepends this to the language for code block classes, e.g.: <code class="language-php">...
- $this->langprefix = "language-";
- // colors used for stylesheet
- $this->colorname = array('fg_def','fg_alt','bg_def','bg_alt','red_norm','red_bold','green_norm','green_bold','yellow_norm','yellow_bold','blue_norm','blue_bold','magenta_norm','magenta_bold','cyan_norm','cyan_bold');
- if($config['debug'] === TRUE) {
- $this->debug = TRUE;
- ini_set('display_errors', 'On');
- error_reporting(E_ALL);
- echo "function ". __FUNCTION__ ." in ". __FILE__ .'<br/>';
- }
- // reading config values or setting fallback config values - importing them to this plugin's context
- if (isset($config['geshi']['class'])) $this->geshi_class = $config['geshi']['class'];
- if (isset($config['geshi']['line-numbers'])) $this->geshi_line_numbers = $config['geshi']['line-numbers'];
- if (isset($config['geshi']['fancy-line-numbers']) && $config['geshi']['fancy-line-numbers'] > 1) $this->geshi_fancy_line_numbers = $config['geshi']['fancy-line-numbers'];
- if (isset($config['geshi']['line-start']) && $config['geshi']['line-start'] >= 0) $this->geshi_line_start = $config['geshi']['line-start'];
- if (isset($config['geshi']['template']) && $config['geshi']['template'] != "") $this->geshi_template = $config['geshi']['template'];
- if (isset($config['geshi']['enable-ids'])) $this->geshi_enable_ids = $config['geshi']['enable-ids'];
- // check geshi colors defined in some config .yml
- if (isset($config['geshi_col']['enabled'])) $this->geshi_col_enabled = $config['geshi_col']['enabled'];
- // - use fallback if desired (geshi_col.enabled is TRUE) but undefined
- if ($this->geshi_col_enabled == TRUE)
- {
- // fallback colors, with a light (dark text on light background) theme in mind
- // names from here: www.w3schools.com/cssref/css_colors.asp
- $fallback=array('Black','DimGrey','Mocassin','OldLace','DarkRed','FireBrick','DarkGreen','ForestGreen','DarkGoldenRod','DarkOrange','CadetBlue','CornflowerBlue','DarkViolet','DarkOrchid','DarkCyan','DeepSkyBlue');
- for($i=0;$i<16;$i++) {
- $color = $this->colorname[$i];
- if(isset($config['geshi_col'][$color])) $this->$color = $config['geshi_col'][$color];
- else $this->$color = $fallback[$i];
- }
- }
- // define default css twig template if not user-defined
- if (isset($config['geshi']['css_template'])) $this->css_template = $config['geshi']['css_template'];
- }
- public function onMetaParsed(array $meta)
- {
- if($this->debug === TRUE) echo "function ". __FUNCTION__ ." found template \"". $meta['template'] ."\" in ". __FILE__ .'<br/>';
- // Only Do Things if we have the correct template
- if($meta['template'] === $this->geshi_template || $this->geshi_template === "all" ) $this->yeah = TRUE;
- }
- public function onContentParsed(&$content)
- {
- if($this->debug === TRUE) echo "function ". __FUNCTION__ ." in ". __FILE__ .'<br/>';
- if($this->yeah === FALSE ) {
- if($this->debug === TRUE) echo "We're not doing anything. Bye!".'<br/>';
- return;
- }
- if(trim($content)=="") {
- if($this->debug === TRUE) echo "Content is empty. Bye!".'<br/>';
- return;
- }
- $doc = new DOMDocument('1.0', 'utf-8');
- // enable user error handling
- // stackoverflow.com/questions/8218230/php-domdocument-loadhtml-not-encoding-utf-8-correctly
- libxml_use_internal_errors(true);
- if(!$doc->loadHTML($content))
- {
- foreach (libxml_get_errors() as $error) {
- $this->content['err'][] = $error;
- }
- libxml_clear_errors();
- return;
- }
- $doc->encoding="UTF-8"; // someone on the 'net wrote this should be done _after_ loadHTML
- $nodes = $doc->getElementsByTagName('code'); // it is possible to put a language class on a single line code element
- foreach($nodes as $node)
- {
- if($this->debug === TRUE) echo "We have at least one 'code' tag...";
- $lang = $node->getAttribute('class');
- // is there at least one with a language-class?
- $len = strlen($this->langprefix);
- if(substr($lang,0,$len) === $this->langprefix)
- // if yes, we start for real:
- {
- if($this->debug === TRUE) echo "...with a language:<br/>";
- //////////////////////////////////////
- require_once 'geshi-1.0/src/geshi.php';
- //////////////////////////////////////
- $geshi = new GeSHi('dummytext','php'); // so we need to open this only once for the whole page
- $geshi->set_encoding('UTF-8');
- $geshi->enable_strict_mode(TRUE);
- $geshi->enable_keyword_links(false);
- if($this->geshi_line_numbers === TRUE) $geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
- if($this->geshi_fancy_line_numbers > 1) $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS,$this->geshi_fancy_line_numbers);
- $geshi->start_line_numbers_at($this->geshi_line_start);
- if($this->geshi_enable_ids) {
- $geshi->enable_ids(TRUE);
- $geshi->set_overall_id($this->geshi_class);
- }
- $geshi->enable_classes();
- $geshi->set_header_type(GESHI_HEADER_PRE);
- foreach($nodes as $node)
- {
- $lang = $node->getAttribute('class');
- // no "language-" class? No highlighting desired.
- $len = strlen($this->langprefix);
- if(substr($lang,0,$len) !== $this->langprefix) continue;
-
- $str = $node->nodeValue;
- $glang = substr($lang,$len); // remove classprefix, usually "language-"
- $glang = preg_replace('/[^[:alnum:]]/','',$glang); // remove dots or curly brackets - everything but letters and digits
- switch($glang) {
- case 'sh': $glang = 'bash'; break;
- case 'patch': $glang = 'diff'; break;
- }
- if($this->debug === TRUE) echo "--- ".$lang." becomes ".$glang."<br/>";
- $geshi->set_source($str);
- $geshi->set_language($glang);
- $str = $geshi->parse_code();
-
- $code = $doc->createElement('code');
- $code->setAttribute("class",$this->geshi_class .' '.$glang.' '.$lang);
- $code->setAttribute("id",$this->geshi_class);
- $tmpDoc = new DOMDocument();
- $tmpDoc->loadHTML($str);
- $tmpDoc->encoding="UTF-8";
- foreach ($tmpDoc->getElementsByTagName('pre')->item(0)->childNodes as $tmpnode) {
- $tmpnode = $doc->importNode($tmpnode, true);
- $code->appendChild($tmpnode);
- }
- $node->parentNode->replaceChild($code,$node);
- }
- $content = $doc->saveXML($doc->documentElement);
- $len = strlen('<html><body>');
- if(substr($content,0,$len) === '<html><body>') $content = substr($content,$len);
- $len = '-'.strlen('</body></html>');
- if(substr($content,$len) === '</body></html>') $content = substr($content,0,$len);
- // applying CSS colors
- if($this->geshi_col_enabled === TRUE) {
- $styles = file_get_contents(dirname(__FILE__).'/'.$this->css_template);
- if($styles !== '')
- {
- $styles = str_replace('%class%',$this->geshi_class,$styles);
- for($i=0;$i<16;$i++) {
- $color = $this->colorname[$i];
- $styles = str_replace('%'.$color.'%',$this->$color,$styles);
- }
- //// MINIFY ON THE FLY
- // Remove comments
- $styles = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $styles);
- // Remove space after colons
- $styles = str_replace(': ', ':', $styles);
- // Remove newlines and tabs
- $styles = str_replace(array("\r\n", "\r", "\n", "\t"), '', $styles);
- // Collapse adjacent spaces into a single space
- $styles = preg_replace('!\s+!', ' ',$styles);
- // Remove spaces that might still be left where we know they aren't needed
- $srch = array('} ', '{ ', '; ' ,', ' ,' }' ,' {' ,' ;' ,' ,' );
- $rplc = array('}' , '{' , ';' ,',' ,'}' ,'{' ,';' ,',' );
- $styles = str_replace($srch,$rplc,$styles);
- $content = '<style>'.$styles.'</style>'.$content;
- }
- }
- }
- else {
- if($this->debug === TRUE) echo "...but it doesn't have a language.<br/>";
- continue;
- }
- // this was not the real loop, we were only testing if we had at least one, can break now
- break;
- }
- }
- }
|