SyntaxHighlighterをショートカットで表示

2010/07/22

これもWordpressでSyntaxHighlighterをインストールすると以下のように簡略化して入力できる。

[cpp]
ソース

これを

<pre class="brush:xxx">ソース</pre>

に変換するスクリプト。
調べたら「wordpress/wp-content/plugins/syntax_highlighter.php」で処理しているようだ。

てな訳で、同じ仕様で自作してみることに。

サンプルコード

function syntax_highlight_header() {
    $syntaxHighlighter = SyntaxHighlighter::getInstance();
    $syntaxHighlighter->showHeader();
}

function syntax_highlight_decode($body) {
    if ($body) {
        $syntaxHighlighter = SyntaxHighlighter::getInstance();
        $syntaxHighlighter->convertContent($body);
    }
}

class SyntaxHighlighter {

    var $types = array(
        'as3'  => array('brush' =>'AS3'),
        'bash' => array('brush' => 'Bash'),
        'cpp' => array('brush' => 'Cpp'),
        'csharp' => array('brush' => 'CSharp'),
        'css' => array('brush' => 'Css'),
        'delphi' => array('brush' => 'Delphi'),
        'coldfusion' => array('brush' => 'ColdFusion'),
        'java' => array('brush' => 'Java'),
        'javafx' => array('brush' => 'JavaFX'),
        'jscript' => array('brush' => 'JScript'),
        'diff' => array('brush' => 'Diff'),
        'erlang' => array('brush' => 'Erlang'),
        'groovy' => array('brush' => 'Groovy'),
        'perl' => array('brush' => 'Perl'),
        'php' => array('brush' => 'Php'),
        'plain' => array('brush' => 'Plain'),
        'powershell' => array('brush' => 'PowerShell'),
        'python' => array('brush' => 'Python'),
        'ruby' => array('brush' => 'Ruby'),
        'shell' => array('brush' => 'Sass'),
        'scala' => array('brush' => 'Scala'),
        'sql' => array('brush' => 'Sql'),
        'vb' => array('brush' => 'vb'),
        'xhtml' => array('brush' => 'Xml'),
    );

    private static $instance = null;

    public static function getInstance() {
        if (SyntaxHighlighter::$instance == null) {
            SyntaxHighlighter::$instance = new SyntaxHighlighter();
        }
        return SyntaxHighlighter::$instance;
    }

    public function showHeader() {
        $tags[] = $this->javascript_tag('dp.SyntaxHighlighter/src/shCore');

        if (is_array($this->types)) {
            foreach ($this->types as $key => $value) {
                $tags[] = $this->javascript_tag("dp.SyntaxHighlighter/scripts/shBrush{$value['brush']}");
            }
        }
        $tag = implode("\n", $tags);
        echo($tag);
    }

    public function convertContent($body) {
        $bodys = explode("\n", $body);
        if (is_array($bodys)) {
            $isCode = false;
            foreach($bodys as $key => $line) {
                $start_code = $this->syntaxHighliterCode($line);
                if ($start_code) {
                    $code = $start_code;
                    $tag.= "&ltpre class=\"brush:{$code}\">\n";
                } else {
                    if ($code) {
                        if ($this->isSyntaxHighliterEndTag($line, $code)) {
                            $tag.= "</pre>\n";
                            $code = null;
                        } else {
                            $tag.= "{$line}\n";
                        }
                    } else {
                        $line = html_entity_decode(strip_tags($line), ENT_QUOTES, mb_internal_encoding());
                        $line = "{$line}\n";
                        $line = nl2br($line);
                        $tag.= $line;
                    }
                }
            }
        }
        echo($tag);
    }

    private function syntaxHighliterCode($value) {
        $pattern = '/^\[[a-zA-Z0-9]+\]/';
        if (preg_match($pattern, $value, $matchs)) {
            $code = substr($matchs[0], 1, strlen($matchs[0]) - 2);
            $code = strtolower($code);
            if ($this->types[$code]) {
                return $code;
            }
        }
    }

    private function isSyntaxHighliterEndTag($value, $target) {
        $pattern = '/^\[\/[a-zA-Z0-9]+\]/';
        if (preg_match($pattern, $value, $matchs)) {
            $code = substr($matchs[0], 2, strlen($matchs[0]) - 3);
            $code = strtolower($code);
            return ($target == $code);
        }
    }

    private function javascript_tag($name) {
        if (is_string($name) && !empty($name)) {
            return "&ltscript type=\"text/javascript\" src=\"{$GLOBALS['controller']->relative_base}javascripts/{$name}.js\">\n";
        }
    }

}

解説

htmlヘッダーでsyntax_highlight_header()を呼んで、ブログの本文syntax_highlight_decode($text)で変換してやります。

あとDBに保存するときは、htmlentitiesでエスケープしました。

 htmlentities(本文, ENT_QUOTES, mb_internal_encoding());

即席でバグバグだと思うけど、とりあえずコンバートできました。 正規表現でパースする部分が美しくないし、singlton使う意味がないかも・・・