xref: /dokuwiki/lib/plugins/info/syntax.php (revision 65ba535c52baa1db9e09d5ad176b79f30f40d7ab)
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