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