dokuwiki 处理嵌套语法

在 DokuWiki 中,如果你自定义一个语法标记,而这个标记内部包含多个子指令(嵌套的语法元素),你需要使用 DokuWiki 的嵌套处理机制来正确渲染它们。

处理嵌套内容的关键步骤

  1. 定义允许的子语法类型:通过 getAllowedTypes() 方法指定你的语法插件内部允许哪些类型的语法元素
  2. 使用 Doku_Handler_Nest 处理嵌套内容:在 handle() 方法中使用嵌套处理器
  3. render() 方法中使用 $renderer->nest() 渲染嵌套内容

具体实现方法

1. 定义允许的子语法类型

首先,你需要在你的插件中通过 getAllowedTypes() 方法指定允许哪些类型的语法元素嵌套在你的标记内部:

public function getAllowedTypes() {  
    // 允许格式化和替换类型的语法元素在插件内部使用  
    return ['formatting', 'substition'];  
}

2. 在 handle() 方法中处理嵌套内容

handle() 方法中,你需要使用 Doku_Handler_Nest 类来处理嵌套内容:

public function handle($match, $state, $pos, \Doku_Handler $handler) {  
    switch ($state) {  
        case DOKU_LEXER_ENTER:  
            // 处理开始标记  
            return ['state' => $state];  

        case DOKU_LEXER_UNMATCHED:  
            // 这里是关键 - 创建一个嵌套处理器来处理内部内容  
            $nestHandler = new \dokuwiki\Parsing\Handler\Nest($handler->getCallWriter());  
            // 解析嵌套内容  
            $instructions = p_get_instructions($match);  
            // 存储解析后的指令  
            return ['state' => $state, 'instructions' => $instructions];  

        case DOKU_LEXER_EXIT:  
            // 处理结束标记  
            return ['state' => $state];  
    }  
    return false;  
}

3. 在 render() 方法中渲染嵌套内容

最后,在 render() 方法中,你需要使用 $renderer->nest() 方法来渲染嵌套内容:

public function render($format, \Doku_Renderer $renderer, $data) {  
    if ($format == 'xhtml') {  
        switch ($data['state']) {  
            case DOKU_LEXER_ENTER:  
                // 开始你的自定义容器  
                $renderer->doc .= '<div class="my-custom-container">';  
                break;  

            case DOKU_LEXER_UNMATCHED:  
                if (isset($data['instructions'])) {  
                    // 使用 nest() 方法渲染嵌套内容  
                    $renderer->nest($data['instructions']);  
                } else {  
                    // 如果没有嵌套指令,就直接输出文本  
                    $renderer->doc .= $renderer->_xmlEntities($data['text']);  
                }  
                break;  

            case DOKU_LEXER_EXIT:  
                // 结束你的自定义容器  
                $renderer->doc .= '</div>';  
                break;  
        }  
        return true;  
    }  
    return false;  
}

完整示例

下面是一个完整的示例,展示如何创建一个支持嵌套内容的自定义语法插件:

<?php  
/**  
 * 自定义容器语法插件示例 - 支持嵌套内容  
 */  
class syntax_plugin_example_container extends \dokuwiki\Extension\SyntaxPlugin {  
    /**  
     * 返回插件类型  
     */  
    public function getType() {  
        return 'container';  
    }  

    /**  
     * 返回段落类型  
     */  
    public function getPType() {  
        return 'block';  
    }  

    /**  
     * 返回允许的模式类型 - 这里是关键  
     */  
    public function getAllowedTypes() {  
        // 允许这些类型的语法元素在我们的容器内部使用  
        return ['formatting', 'substition', 'disabled', 'protected'];  
    }  

    /**  
     * 返回模式排序值  
     */  
    public function getSort() {  
        return 50;  
    }  

    /**  
     * 将模式连接到词法分析器  
     */  
    public function connectTo($mode) {  
        $this->Lexer->addEntryPattern('<mycontainer>(?=.*?</mycontainer>)', $mode, 'plugin_example_container');  
    }  

    public function postConnect() {  
        $this->Lexer->addExitPattern('</mycontainer>', 'plugin_example_container');  
    }  

    /**  
     * 处理匹配的数据  
     */  
    public function handle($match, $state, $pos, \Doku_Handler $handler) {  
        switch ($state) {  
            case DOKU_LEXER_ENTER:  
                return ['state' => $state];  

            case DOKU_LEXER_UNMATCHED:  
                // 创建一个嵌套处理器  
                $nestHandler = new \dokuwiki\Parsing\Handler\Nest($handler->getCallWriter());  
                // 解析嵌套内容  
                $instructions = p_get_instructions($match);  
                // 返回解析后的指令  
                return ['state' => $state, 'instructions' => $instructions];  

            case DOKU_LEXER_EXIT:  
                return ['state' => $state];  
        }  
        return false;  
    }  

    /**  
     * 创建输出  
     */  
    public function render($format, \Doku_Renderer $renderer, $data) {  
        if ($format == 'xhtml') {  
            switch ($data['state']) {  
                case DOKU_LEXER_ENTER:  
                    $renderer->doc .= '<div class="my-custom-container">';  
                    break;  

                case DOKU_LEXER_UNMATCHED:  
                    if (isset($data['instructions'])) {  
                        // 渲染嵌套内容  
                        $renderer->nest($data['instructions']);  
                    }  
                    break;  

                case DOKU_LEXER_EXIT:  
                    $renderer->doc .= '</div>';  
                    break;  
            }  
            return true;  
        }  
        return false;  
    }  
}

关键点解释

  1. nest() 方法:DokuWiki 的渲染器提供了 nest() 方法,专门用于渲染嵌套的指令。这个方法在 Doku_Renderer 类中定义: renderer.php:136-143
  2. 嵌套处理:当 DokuWiki 渲染嵌套内容时,它会递归地处理每条指令,并调用相应的渲染器方法: renderer.php:138-142
  3. 允许的类型:通过 getAllowedTypes() 方法,你可以控制哪些类型的语法元素可以在你的插件内部使用: SyntaxPlugin.php:111-129

实际应用

使用这种方法,你可以创建复杂的自定义语法结构,例如:

<mycontainer>  
这是**粗体文本**,这是//斜体文本//,  
这是一个[[内部链接]],这是一个{{图片}}。  

甚至可以包含代码块:  
<code>  
function example() {  
    return true;  
}  
</code>  
</mycontainer>

所有这些嵌套的语法元素都会被正确解析和渲染,只要你在 getAllowedTypes() 方法中允许了相应的类型。

Notes

处理嵌套内容是 DokuWiki 语法插件开发中较为复杂的部分,但通过正确使用 getAllowedTypes()nest() 方法,你可以创建支持丰富内容的自定义语法结构。

需要注意的是,p_get_instructions() 函数用于将文本转换为指令数组,而 $renderer->nest() 方法则用于渲染这些指令。这两个函数是处理嵌套内容的核心。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇