<?php if (!defined('PmWiki')) exit(); /** ZCode for PmWiki Highlight source code files extracted from tar or zip archives. Written by (c) 2017 Petko Yotov http://www.pmwiki.org/Petko This text is written for PmWiki; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. See pmwiki.php for full details and lack of warranty. */ # Version date $RecipeInfo['ZCode']['Version'] = '20170812a'; SDVA($ZCode, array( 'Archives' => 'archives/file-%s.tgz', 'DefaultVersion' => 'latest', 'VersionChars' => '-\\w.', 'FilenameChars' => '-\\w.\\/', 'FilenameExts' => 'php|tmpl|txt|css|htaccess|js|html?', 'SingleLinePad' => 4, )); SDVA($ZCode['Langs'], array('tmpl'=>'html', 'htaccess'=>'apache')); SDVA($ZCode['ExtCommands'], array( 'tgz|tar|tar\\.gz' => 'tar -f "%s" --wildcards --get "*%s" --to-stdout', 'zip'=>'unzip -p "%s" "*%s"', 'rar'=>'unrar p -inul "%s" "*%s"', '7z'=>'7z e -so -r "%s" "*%s" 2> /dev/null', )); Markup('(:zcode', 'directives', '/\\(:zcode +(.*?):\\)/', 'FmtZCode'); function FmtZCode($n) { global $ZCode, $HTMLHeaderFmt, $HTMLFooterFmt; $opt = ParseArgs($n[1], '(?>(\\w+)[=])'); if(!@$opt['file']) { if(preg_match("!^(?:(.*?):)?(.*?)(?:@(\\d.*))?$!", $opt[""][0], $n)) { list($x, $opt['version'], $opt['file'], $opt['lines']) = $n; } } $fname = preg_replace('![^'.$ZCode['FilenameChars'].']!', '', $opt['file']); $fname = preg_replace('!\\.{2,}!', '', $fname); # no double dots in file names $ext = strtolower(preg_replace('!^.*\\.(\\w+)$!', '$1', $fname)); if ( (!$fname) || ! preg_match("!^({$ZCode['FilenameExts']})$!i", $ext) ) return XL("Unsupported file name:"). " '{$opt['file']}'"; $version = ($opt['version']) ? $opt['version'] : $ZCode['DefaultVersion']; $version = preg_replace('![^'.$ZCode['VersionChars'].']!', '', $version); $archive = sprintf($ZCode['Archives'], $version); if (! file_exists($archive)) return XL("No such file:") ." '$archive'"; $command = ''; foreach($ZCode['ExtCommands'] as $e => $c) { if(! preg_match('!\\.('.$e.')$!i', $archive)) continue; $command = $c; break; } if (! $command) return XL("Unsupported archive:")." '$archive'"; $command = sprintf($command, $archive, $fname); exec($command, $output, $rval); $content = implode("\n", $output); if($rval) return sprintf(XL("Command <code>%s</code> returned error code '%s'."), $command, $rval); $lines = @$opt['lines']; if(!$lines) $lines = intval(@$opt['line']); if($lines) { $clines = explode("\n", $content); $count = count($clines); if(preg_match('!^(\\d+)(?:-+|\\.\\.)(\\d+)$!', $lines, $m)) { $start = max(1, min(intval($m[1]), intval($m[2])) ); $end = min($count, max( intval($m[1]), intval($m[2]) ) ); } elseif(preg_match('!^(\\d+)$!', $lines, $m)) { $start = max(1, min($count, intval($lines)-$ZCode['SingleLinePad'])); $end = min($count, intval($lines)+$ZCode['SingleLinePad']); } else { return XL("Unsupported line format:")." '$lines'"; } $linestart = $start-1; $linelength = abs($end - $linestart); $clines = array_slice($clines, $linestart, $linelength); $content = implode("\n", $clines); } $lang = @$opt['lang']? $opt['lang'] : (@$ZCode['Langs'][$ext] ? $ZCode['Langs'][$ext] : $ext); SDVA($HTMLHeaderFmt, array('ZCode' => ' <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script> ')); SDVA($HTMLFooterFmt, array('ZCode' => ' <script> hljs.initHighlightingOnLoad(); function spad(current, last){ // space pad current = ""+current.toString(); last = ""+last.toString(); var diff = last.length - current.length; for(var i=diff; i>0; i--) current = " "+current; return current; } setTimeout(function(){ var codes = document.querySelectorAll("pre > code[data-linestart]"); if(!codes.length) return; for(var i=0; i<codes.length; i++) { var code = codes[i]; var linestart = parseInt(code.getAttribute("data-linestart")); var html = code.innerHTML.split(/\n/); var newhtml = ""; for(var j=0; j<html.length; j++) { var current = spad(linestart+j, linestart+html.length); newhtml += "<span class=\'hljs-comment\'>"+current+"</span> "+html[j]+"\n"; } code.innerHTML = newhtml; } }, 500); </script> ')); return "<:block>" .Keep("<pre><code class='$lang' data-linestart='".($linestart+1)."'>".PHSC($content)."</code></pre>"); }