xref: /plugin/combo/syntax/highlightwiki.php (revision 0bb301e4810e02240c0e53e1eea739c8f546dd14)
1<?php
2
3use ComboStrap\BrandColors;
4use ComboStrap\ColorRgb;
5use ComboStrap\ExceptionCombo;
6use ComboStrap\LogUtility;
7use ComboStrap\PluginUtility;
8use ComboStrap\Site;
9use ComboStrap\TagAttributes;
10
11
12/**
13 *
14 * Taking over {@link \dokuwiki\Parsing\ParserMode\Formatting monospace}
15 *
16 * Known as code
17 * https://spec.commonmark.org/0.30/#code-spans
18 *
19 * note supported but specific highlight is done with two `==`
20 * in some processor
21 * https://www.markdownguide.org/extended-syntax/#highlight
22 *
23 */
24class syntax_plugin_combo_highlightwiki extends DokuWiki_Syntax_Plugin
25{
26
27
28    const TAG = "highlightwiki";
29    // Only on one line
30    const ENTRY_PATTERN = "\x27\x27(?=[^\n]*\x27\x27)(?!\n)";
31
32
33    const CONF_HIGHLIGHT_WIKI_ENABLE = "highlightWikiEnable";
34    const CONF_DEFAULT_HIGHLIGHT_WIKI_ENABLE_VALUE = 1;
35    const EXIT_PATTERN = "\x27\x27";
36
37    const CANONICAL = self::TAG;
38
39    const HTML_TAG = "mark";
40
41    public static function getOpenTagHighlight(string $tag): string
42    {
43        $htmlTag = self::HTML_TAG;
44        if (!Site::isBrandingColorInheritanceEnabled()) {
45            return "<$htmlTag>";
46        }
47        $primaryColor = Site::getPrimaryColor();
48        if ($primaryColor === null) {
49            return "<$htmlTag>";
50        }
51        $tagAttributes = TagAttributes::createEmpty($tag);
52        try {
53            $colorRgb = BrandColors::toBackgroundColor($primaryColor);
54            $tagAttributes->addComponentAttributeValue(ColorRgb::BACKGROUND_COLOR, $colorRgb
55                ->toRgbHex());
56        } catch (ExceptionCombo $e) {
57            LogUtility::msg("Error on highlight color calculation");
58        }
59        return $tagAttributes->toHtmlEnterTag($htmlTag);
60    }
61
62    public function getSort(): int
63    {
64        /**
65         * It's 49 (on less than the original of 100) named monospace
66         * {@link \dokuwiki\Parsing\ParserMode\Formatting}
67         */
68        return 49;
69    }
70
71    public function getType(): string
72    {
73        return 'formatting';
74    }
75
76
77    /**
78     *
79     * How Dokuwiki will add P element
80     *
81     *  * 'normal' - The plugin can be used inside paragraphs (inline)
82     *  * 'block'  - Open paragraphs need to be closed before plugin output - block should not be inside paragraphs
83     *  * 'stack'  - Special case. Plugin wraps other paragraphs. - Stacks can contain paragraphs
84     *
85     * @see DokuWiki_Syntax_Plugin::getPType()
86     *
87     * This is the equivalent of inline or block for css
88     */
89    public function getPType(): string
90    {
91        return 'normal';
92    }
93
94    /**
95     * @return array
96     * Allow which kind of plugin inside
97     *
98     * No one of array('baseonly','container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs')
99     * because we manage self the content and we call self the parser
100     *
101     * Return an array of one or more of the mode types {@link $PARSER_MODES} in Parser.php
102     */
103    function getAllowedTypes(): array
104    {
105        return array('formatting', 'substition', 'protected', 'disabled');
106    }
107
108
109    public function connectTo($mode)
110    {
111        $enabled = PluginUtility::getConfValue(self::CONF_HIGHLIGHT_WIKI_ENABLE, self::CONF_DEFAULT_HIGHLIGHT_WIKI_ENABLE_VALUE);
112        if ($enabled) {
113            $this->Lexer->addEntryPattern(self::ENTRY_PATTERN, $mode, PluginUtility::getModeFromTag($this->getPluginComponent()));
114        }
115
116    }
117
118    public function postConnect()
119    {
120
121        $this->Lexer->addExitPattern(self::EXIT_PATTERN, PluginUtility::getModeFromTag($this->getPluginComponent()));
122
123    }
124
125
126    /**
127     * Handle the syntax
128     *
129     * At the end of the parser, the `section_open` and `section_close` calls
130     * are created in {@link action_plugin_combo_headingpostprocessing}
131     * and the text inside for the toc is captured
132     *
133     * @param string $match
134     * @param int $state
135     * @param int $pos
136     * @param Doku_Handler $handler
137     * @return array
138     */
139    public function handle($match, $state, $pos, Doku_Handler $handler): array
140    {
141        switch ($state) {
142
143            case DOKU_LEXER_EXIT:
144            case DOKU_LEXER_ENTER:
145                return array(
146                    PluginUtility::STATE => $state
147                );
148            case DOKU_LEXER_UNMATCHED :
149
150                return PluginUtility::handleAndReturnUnmatchedData(self::TAG, $match, $handler);
151
152        }
153        return array();
154    }
155
156    public function render($format, $renderer, $data): bool
157    {
158
159        switch($format) {
160            case "xhtml":
161            {
162                /**
163                 * @var Doku_Renderer_xhtml $renderer
164                 */
165                $state = $data[PluginUtility::STATE];
166                switch ($state) {
167
168                    case DOKU_LEXER_ENTER:
169                        $renderer->doc .= self::getOpenTagHighlight(self::TAG);
170                        return true;
171                    case DOKU_LEXER_UNMATCHED:
172                        $renderer->doc .= PluginUtility::renderUnmatched($data);
173                        return true;
174                    case DOKU_LEXER_EXIT:
175                        $htmlTag = self::HTML_TAG;
176                        $renderer->doc .= "</$htmlTag>";
177                        return true;
178
179                }
180                break;
181            }
182            case "metadata":
183                /**
184                 * @var Doku_Renderer_metadata $renderer
185                 */
186                $state = $data[PluginUtility::STATE];
187                switch ($state) {
188                    case DOKU_LEXER_UNMATCHED:
189                        $renderer->doc .= PluginUtility::renderUnmatched($data);
190                }
191                break;
192        }
193
194        return false;
195    }
196
197
198}
199