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 $conf; 201 202 $registry = new ModeRegistry($conf['syntax']); 203 $registry->getModes(); 204 $categories = $registry->getCategories(); 205 206 $doc = ''; 207 $doc .= '<div class="table"><table class="inline"><tbody>'; 208 foreach ($categories as $type => $modes) { 209 $doc .= '<tr>'; 210 $doc .= '<td class="leftalign">'; 211 $doc .= $type; 212 $doc .= '</td>'; 213 $doc .= '<td class="leftalign">'; 214 $doc .= implode(', ', $modes); 215 $doc .= '</td>'; 216 $doc .= '</tr>'; 217 } 218 $doc .= '</tbody></table></div>'; 219 return $doc; 220 } 221 222 /** 223 * lists all known syntax modes and their sorting value 224 * 225 * @return string 226 */ 227 protected function renderSyntaxModes() 228 { 229 global $conf; 230 $modes = (new ModeRegistry($conf['syntax']))->getModes(); 231 232 $compactmodes = []; 233 foreach ($modes as $mode) { 234 $compactmodes[$mode['sort']][] = $mode['mode']; 235 } 236 $doc = ''; 237 $doc .= '<div class="table"><table class="inline"><tbody>'; 238 239 foreach ($compactmodes as $sort => $modes) { 240 $rowspan = ''; 241 if (count($modes) > 1) { 242 $rowspan = ' rowspan="' . count($modes) . '"'; 243 } 244 245 foreach ($modes as $index => $mode) { 246 $doc .= '<tr>'; 247 $doc .= '<td class="leftalign">'; 248 $doc .= $mode; 249 $doc .= '</td>'; 250 251 if ($index === 0) { 252 $doc .= '<td class="rightalign" ' . $rowspan . '>'; 253 $doc .= $sort; 254 $doc .= '</td>'; 255 } 256 $doc .= '</tr>'; 257 } 258 } 259 260 $doc .= '</tbody></table></div>'; 261 return $doc; 262 } 263 264 /** 265 * Render all currently registered event handlers 266 * 267 * @param Doku_Renderer $renderer 268 */ 269 protected function renderHooks(Doku_Renderer $renderer) 270 { 271 global $EVENT_HANDLER; 272 273 $list = $EVENT_HANDLER->getEventHandlers(); 274 ksort($list); 275 276 $renderer->listu_open(); 277 foreach ($list as $event => $handlers) { 278 $renderer->listitem_open(1); 279 $renderer->listcontent_open(); 280 $renderer->cdata($event); 281 $renderer->listcontent_close(); 282 283 $renderer->listo_open(); 284 foreach ($handlers as $sequence) { 285 foreach ($sequence as $handler) { 286 $renderer->listitem_open(2); 287 $renderer->listcontent_open(); 288 $renderer->cdata($handler[0]::class . '::' . $handler[1] . '()'); 289 $renderer->listcontent_close(); 290 $renderer->listitem_close(); 291 } 292 } 293 $renderer->listo_close(); 294 $renderer->listitem_close(); 295 } 296 $renderer->listu_close(); 297 } 298 299 /** 300 * Adds a TOC item 301 * 302 * @param string $text 303 * @param int $level 304 * @param Doku_Renderer_xhtml $renderer 305 * @return string 306 */ 307 protected function addToToc($text, $level, Doku_Renderer_xhtml $renderer) 308 { 309 global $conf; 310 311 $hid = ''; 312 if (($level >= $conf['toptoclevel']) && ($level <= $conf['maxtoclevel'])) { 313 $hid = $renderer->_headerToLink($text, true); 314 $renderer->toc[] = [ 315 'hid' => $hid, 316 'title' => $text, 317 'type' => 'ul', 318 'level' => $level - $conf['toptoclevel'] + 1 319 ]; 320 } 321 return $hid; 322 } 323} 324