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