1<?php 2 3use dokuwiki\Parsing\Handler; 4use dokuwiki\Extension\SyntaxPlugin; 5use dokuwiki\Extension\PluginInterface; 6use dokuwiki\Parsing\ModeRegistry; 7 8/** 9 * Info Plugin: Displays information about various DokuWiki internals 10 * 11 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 12 * @author Andreas Gohr <andi@splitbrain.org> 13 * @author Esther Brunner <wikidesign@gmail.com> 14 */ 15class syntax_plugin_info extends SyntaxPlugin 16{ 17 /** 18 * What kind of syntax are we? 19 */ 20 public function getType() 21 { 22 return ModeRegistry::CATEGORY_SUBSTITUTION; 23 } 24 25 /** 26 * What about paragraphs? 27 */ 28 public function getPType() 29 { 30 return 'block'; 31 } 32 33 /** 34 * Where to sort in? 35 */ 36 public function getSort() 37 { 38 return 155; 39 } 40 41 /** 42 * Connect pattern to lexer 43 */ 44 public function connectTo($mode) 45 { 46 $this->Lexer->addSpecialPattern('~~INFO:\w+~~', $mode, 'plugin_info'); 47 } 48 49 /** 50 * Handle the match 51 * 52 * @param string $match The text matched by the patterns 53 * @param int $state The lexer state for the match 54 * @param int $pos The character position of the matched text 55 * @param Handler $handler The Doku_Handler object 56 * @return array Return an array with all data you want to use in render 57 */ 58 public function handle($match, $state, $pos, Handler $handler) 59 { 60 $match = substr($match, 7, -2); //strip ~~INFO: from start and ~~ from end 61 return [strtolower($match)]; 62 } 63 64 /** 65 * Create output 66 * 67 * @param string $format string output format being rendered 68 * @param Doku_Renderer $renderer the current renderer object 69 * @param array $data data created by handler() 70 * @return boolean rendered correctly? 71 */ 72 public function render($format, Doku_Renderer $renderer, $data) 73 { 74 if ($format == 'xhtml') { 75 /** @var Doku_Renderer_xhtml $renderer */ 76 //handle various info stuff 77 match ($data[0]) { 78 'syntaxmodes' => $renderer->doc .= $this->renderSyntaxModes(), 79 'syntaxtypes' => $renderer->doc .= $this->renderSyntaxTypes(), 80 'syntaxplugins' => $this->renderPlugins('syntax', $renderer), 81 'adminplugins' => $this->renderPlugins('admin', $renderer), 82 'actionplugins' => $this->renderPlugins('action', $renderer), 83 'rendererplugins' => $this->renderPlugins('renderer', $renderer), 84 'helperplugins' => $this->renderPlugins('helper', $renderer), 85 'authplugins' => $this->renderPlugins('auth', $renderer), 86 'remoteplugins' => $this->renderPlugins('remote', $renderer), 87 'helpermethods' => $this->renderHelperMethods($renderer), 88 'hooks' => $this->renderHooks($renderer), 89 'datetime' => $renderer->doc .= date('r'), 90 default => $renderer->doc .= "no info about " . htmlspecialchars($data[0]), 91 }; 92 return true; 93 } 94 return false; 95 } 96 97 /** 98 * list all installed plugins 99 * 100 * uses some of the original renderer methods 101 * 102 * @param string $type 103 * @param Doku_Renderer $renderer 104 */ 105 protected function renderPlugins($type, Doku_Renderer $renderer) 106 { 107 global $lang; 108 $plugins = plugin_list($type); 109 $plginfo = []; 110 111 // remove subparts 112 foreach ($plugins as $p) { 113 $po = plugin_load($type, $p); 114 if (! $po instanceof PluginInterface) continue; 115 [$name, /* part */] = explode('_', $p, 2); 116 $plginfo[$name] = $po->getInfo(); 117 } 118 119 // list them 120 $renderer->listu_open(); 121 foreach ($plginfo as $info) { 122 $renderer->listitem_open(1); 123 $renderer->listcontent_open(); 124 $renderer->externallink($info['url'], $info['name']); 125 $renderer->cdata(' '); 126 $renderer->emphasis_open(); 127 $renderer->cdata($info['date']); 128 $renderer->emphasis_close(); 129 $renderer->cdata(' ' . $lang['by'] . ' '); 130 $renderer->emaillink($info['email'], $info['author']); 131 $renderer->linebreak(); 132 $renderer->cdata($info['desc']); 133 $renderer->listcontent_close(); 134 $renderer->listitem_close(); 135 } 136 $renderer->listu_close(); 137 } 138 139 /** 140 * list all installed plugins 141 * 142 * uses some of the original renderer methods 143 * 144 * @param Doku_Renderer_xhtml $renderer 145 */ 146 protected function renderHelperMethods(Doku_Renderer_xhtml $renderer) 147 { 148 $plugins = plugin_list('helper'); 149 foreach ($plugins as $p) { 150 $po = plugin_load('helper', $p); 151 if (!$po instanceof PluginInterface) continue; 152 153 if (!method_exists($po, 'getMethods')) continue; 154 $methods = $po->getMethods(); 155 $info = $po->getInfo(); 156 157 $hid = $this->addToToc($info['name'], 2, $renderer); 158 $doc = '<h2><a name="' . $hid . '" id="' . $hid . '">' . hsc($info['name']) . '</a></h2>'; 159 $doc .= '<div class="level2">'; 160 $doc .= '<p>' . strtr(hsc($info['desc']), ["\n" => "<br />"]) . '</p>'; 161 $doc .= '<pre class="code">$' . $p . " = plugin_load('helper', '" . $p . "');</pre>"; 162 $doc .= '</div>'; 163 foreach ($methods as $method) { 164 $title = '$' . $p . '->' . $method['name'] . '()'; 165 $hid = $this->addToToc($title, 3, $renderer); 166 $doc .= '<h3><a name="' . $hid . '" id="' . $hid . '">' . hsc($title) . '</a></h3>'; 167 $doc .= '<div class="level3">'; 168 $doc .= '<div class="table"><table class="inline"><tbody>'; 169 $doc .= '<tr><th>Description</th><td colspan="2">' . $method['desc'] . 170 '</td></tr>'; 171 if ($method['params']) { 172 $c = count($method['params']); 173 $doc .= '<tr><th rowspan="' . $c . '">Parameters</th><td>'; 174 $params = []; 175 foreach ($method['params'] as $desc => $type) { 176 $params[] = hsc($desc) . '</td><td>' . hsc($type); 177 } 178 $doc .= implode('</td></tr><tr><td>', $params) . '</td></tr>'; 179 } 180 if ($method['return']) { 181 $doc .= '<tr><th>Return value</th><td>' . hsc(key($method['return'])) . 182 '</td><td>' . hsc(current($method['return'])) . '</td></tr>'; 183 } 184 $doc .= '</tbody></table></div>'; 185 $doc .= '</div>'; 186 } 187 unset($po); 188 189 $renderer->doc .= $doc; 190 } 191 } 192 193 /** 194 * lists all known syntax types and their registered modes 195 * 196 * @return string 197 */ 198 protected function renderSyntaxTypes() 199 { 200 global $PARSER_MODES; 201 $doc = ''; 202 203 $doc .= '<div class="table"><table class="inline"><tbody>'; 204 foreach ($PARSER_MODES as $mode => $modes) { 205 $doc .= '<tr>'; 206 $doc .= '<td class="leftalign">'; 207 $doc .= $mode; 208 $doc .= '</td>'; 209 $doc .= '<td class="leftalign">'; 210 $doc .= implode(', ', $modes); 211 $doc .= '</td>'; 212 $doc .= '</tr>'; 213 } 214 $doc .= '</tbody></table></div>'; 215 return $doc; 216 } 217 218 /** 219 * lists all known syntax modes and their sorting value 220 * 221 * @return string 222 */ 223 protected function renderSyntaxModes() 224 { 225 $modes = p_get_parsermodes(); 226 227 $compactmodes = []; 228 foreach ($modes as $mode) { 229 $compactmodes[$mode['sort']][] = $mode['mode']; 230 } 231 $doc = ''; 232 $doc .= '<div class="table"><table class="inline"><tbody>'; 233 234 foreach ($compactmodes as $sort => $modes) { 235 $rowspan = ''; 236 if (count($modes) > 1) { 237 $rowspan = ' rowspan="' . count($modes) . '"'; 238 } 239 240 foreach ($modes as $index => $mode) { 241 $doc .= '<tr>'; 242 $doc .= '<td class="leftalign">'; 243 $doc .= $mode; 244 $doc .= '</td>'; 245 246 if ($index === 0) { 247 $doc .= '<td class="rightalign" ' . $rowspan . '>'; 248 $doc .= $sort; 249 $doc .= '</td>'; 250 } 251 $doc .= '</tr>'; 252 } 253 } 254 255 $doc .= '</tbody></table></div>'; 256 return $doc; 257 } 258 259 /** 260 * Render all currently registered event handlers 261 * 262 * @param Doku_Renderer $renderer 263 */ 264 protected function renderHooks(Doku_Renderer $renderer) 265 { 266 global $EVENT_HANDLER; 267 268 $list = $EVENT_HANDLER->getEventHandlers(); 269 ksort($list); 270 271 $renderer->listu_open(); 272 foreach ($list as $event => $handlers) { 273 $renderer->listitem_open(1); 274 $renderer->listcontent_open(); 275 $renderer->cdata($event); 276 $renderer->listcontent_close(); 277 278 $renderer->listo_open(); 279 foreach ($handlers as $sequence) { 280 foreach ($sequence as $handler) { 281 $renderer->listitem_open(2); 282 $renderer->listcontent_open(); 283 $renderer->cdata($handler[0]::class . '::' . $handler[1] . '()'); 284 $renderer->listcontent_close(); 285 $renderer->listitem_close(); 286 } 287 } 288 $renderer->listo_close(); 289 $renderer->listitem_close(); 290 } 291 $renderer->listu_close(); 292 } 293 294 /** 295 * Adds a TOC item 296 * 297 * @param string $text 298 * @param int $level 299 * @param Doku_Renderer_xhtml $renderer 300 * @return string 301 */ 302 protected function addToToc($text, $level, Doku_Renderer_xhtml $renderer) 303 { 304 global $conf; 305 306 $hid = ''; 307 if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])) { 308 $hid = $renderer->_headerToLink($text, true); 309 $renderer->toc[] = [ 310 'hid' => $hid, 311 'title' => $text, 312 'type' => 'ul', 313 'level' => $level - $conf['toptoclevel'] + 1 314 ]; 315 } 316 return $hid; 317 } 318} 319