1<?php 2 3/** 4 * DokuWiki Plugin gh (Syntax Component) 5 * 6 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 7 * @author Andreas Gohr <andi@splitbrain.org> 8 */ 9class syntax_plugin_gh extends DokuWiki_Syntax_Plugin 10{ 11 12 /** 13 * Extension to highlighting language mapping 14 * 15 * When a extenison is not found here it's assumed the extension name equals the language 16 * 17 * @var array 18 */ 19 protected $ext2lang = array( 20 'as' => 'actionscript3', 21 'bas' => 'gwbasic', 22 'h' => 'c', 23 'hpp' => 'cpp', 24 'hs' => 'haskell', 25 'htm' => 'html5', 26 'html' => 'html5', 27 'js' => 'javascript', 28 'pas' => 'pascal', 29 'pl' => 'perl6', 30 'py' => 'python', 31 'rb' => 'ruby', 32 'sh' => 'bash', 33 'yml' => 'yaml', 34 ); 35 36 /** 37 * @return string Syntax mode type 38 */ 39 public function getType() 40 { 41 return 'substition'; 42 } 43 44 /** 45 * @return string Paragraph type 46 */ 47 public function getPType() 48 { 49 return 'block'; 50 } 51 52 /** 53 * @return int Sort order - Low numbers go before high numbers 54 */ 55 public function getSort() 56 { 57 return 155; 58 } 59 60 /** 61 * Connect lookup pattern to lexer. 62 * 63 * @param string $mode Parser mode 64 */ 65 public function connectTo($mode) 66 { 67 $this->Lexer->addSpecialPattern('{{gh>[^}]*}}', $mode, 'plugin_gh'); 68 69 } 70 71 /** @inheritDoc */ 72 public function handle($match, $state, $pos, Doku_Handler $handler) 73 { 74 $match = trim(substr($match, 5, -2)); 75 list($url, $lines) = explode(' ', $match, 2); 76 list($from, $to) = explode('-', $lines, 2); 77 78 $data = array( 79 'from' => (int)$from, 80 'to' => (int)$to 81 ); 82 83 if (preg_match('/([\w.\-]+)\/([\w-]+\/[\w-]+(\/[\w-]+)?)\/blob\/([\w-]+)\/(.*)$/', $url, $m)) { 84 $data['base'] = $m[1]; 85 $data['repo'] = $m[2]; 86 $data['blob'] = $m[4]; 87 $data['file'] = $m[5]; 88 } 89 90 return $data; 91 } 92 93 /** @inheritDoc */ 94 public function render($mode, Doku_Renderer $renderer, $data) 95 { 96 if ($mode != 'xhtml') return false; 97 98 if (!$data['base']) return false; 99 if (!$data['repo']) return false; 100 if (!$data['blob']) return false; 101 if (!$data['file']) return false; 102 103 global $ID; 104 global $INPUT; 105 106 if ($data['base'] == 'github.com') { 107 $raw = 'https://raw.githubusercontent.com/' . $data['repo'] . '/' . $data['blob'] . '/' . $data['file']; 108 } else { 109 $raw = 'https://' . $data['base'] . '/' . $data['repo'] . '/raw/' . $data['blob'] . '/' . $data['file']; 110 } 111 $url = 'https://' . $data['base'] . '/' . $data['repo'] . '/blob/' . $data['blob'] . '/' . $data['file']; 112 113 // check if there's a usable cache 114 $text = false; 115 $cache = getCacheName($raw, '.ghplugin'); 116 $tcache = @filemtime($cache); 117 $tpage = @filemtime(wikiFN($ID)); 118 if ($tcache && $tpage && !$INPUT->bool('purge')) { 119 $now = time(); 120 if ($now - $tcache < ($now - $tpage) * 2) { 121 // use cache when it's younger than twice the age of the page 122 $text = io_readFile($cache); 123 } 124 } 125 126 // no cache loaded, get from HTTP 127 if (!$text) { 128 $http = new DokuHTTPClient(); 129 $text = $http->get($raw); 130 131 if ($text) { 132 // save to cache 133 io_saveFile($cache, $text); 134 } else if ($tcache) { 135 // HTTP failed but there's an old cache - use it 136 $text = io_readFile($cache); 137 } 138 } 139 140 // WTF? there's nothing. we're done here 141 if (!$text) return true; 142 143 // apply line ranges 144 if ($data['from'] || $data['to']) { 145 $len = $data['to'] - $data['from']; 146 if ($len <= 0) $len = null; 147 148 $lines = explode("\n", $text); 149 $lines = array_slice($lines, $data['from'], $len); 150 $text = join("\n", $lines); 151 } 152 153 // add icon 154 list($ext) = mimetype($data['file'], false); 155 $class = preg_replace('/[^_\-a-z0-9]+/i', '_', $ext); 156 $class = 'mediafile mf_' . $class; 157 158 // add link 159 $renderer->doc .= '<dl class="file">' . DOKU_LF; 160 $renderer->doc .= '<dt><a href="' . $url . '" class="' . $class . '">'; 161 $renderer->doc .= hsc($data['file']); 162 $renderer->doc .= '</a></dt>' . DOKU_LF . '<dd>'; 163 164 if (isset($this->ext2lang[$ext])) { 165 $lang = $this->ext2lang[$ext]; 166 } else { 167 $lang = $ext; 168 } 169 170 $renderer->file($text, $lang); 171 $renderer->doc .= '</dd>'; 172 $renderer->doc .= '</dl>'; 173 return true; 174 } 175} 176