pukiwiki/texthighlight.inc.php のバックアップの現在との差分(No.9)

更新


  • 追加された行はこの色です。
  • 削除された行はこの色です。
[[公開メモ]]

#contents

* pukiwiki 上でソースコードをカラー表示するためのプラグイン [#c4d9ad0a]

http://shjs.sourceforge.net/index.html にある SHJS という
ライブラリを使って JavaScript で色を付けることができます。

pukiwiki 文法ではソースコードなどを記述するには文頭に空白を
置きます。

たとえば、こんな感じですね。

 printf("Hello, world!\n");

このプラグインを入れて、ソースコードブロックの一行目に、" LANG:C++" と書くと、

 LANG:C++
 printf("Hello, world!\n");

となります。

また、" LANG:C++(linenumber)" とすると、左側に行番号を付ける事もできます。~
行番号を付けた場合にも、ソースコード部分のみを選択&コピーできるようになっています。

 LANG:C++(linenumber)
 printf("Hello, world!\n");
 printf("Hello, world!\n");
 printf("Hello, world!\n");

下記の php ソースであれば " LANG:php" と書いてあります。

SHJS は C++, php の他にも、下記の多くの言語に対応していて、
この機能を pukiwiki 上でそのまま使う事ができます。

|Bison |          Java properties files |          PHP |
|C |              JavaScript |                     Prolog |
|C++ |            JavaScript with DOM |            Python |
|C# |             LaTeX |                          RPM spec files |
|ChangeLog |      LDAP files |                     Ruby |
|CSS |            Log files |                      S-Lang |
|Desktop files |  LSM (Linux Software Map) files | Scala |
|Diff |           M4 |                             Shell |
|Flex |           Makefile |                       SQL |
|GLSL |           Objective Caml |                 Standard ML |
|Haxe |           Oracle SQL |                     Tcl |
|HTML |           Pascal |                         XML |
|Java|            Perl|                            Xorg configuration files|

あるいは、文法ファイルを頑張って手で書けば、
その他の言語にも割と簡単に対応させることができます。

役に立ちそうだったらご利用ください。

* ソースコード [#s3f0331d]

 LANG:php(linenumber)
 <?php
 /*
  *  シンタックスハイライトプラグイン - texthighlight 2.0
  * 
  * プログラムコードなどをシンタックスハイライト (+行番号付け) して
  * 表示するプラグイン。内部で shjs というライブラリを使っています。
  * 
  * by Osamu TAKEUCHI <osamu@big.jp> http://dora.bk.tsukuba.ac.jp/~takeuchi/
  * 
  * 利用・配布・改変は自由に行ってください。
  * ただし、結果について作者は保証しません。
  * 各自の責任で行うようにしてください。
  * 
  * 
  * 使い方:
  * 
  * インストールはまず pukiwiki の plugin フォルダに texthighlight.inc.php 
  * を放り込む。
  * 
  * http://shjs.sourceforge.net/index.html から shjs を落としてきて、
  * pukiwiki フォルダの直下(plugin フォルダと同じ階層)に shjs という
  * 名前のフォルダを掘ってそこに展開する。
  * 
  * このプログラムは実際にはプラグインではなくフィルタのようなものなので、
  * plugin フォルダに入れるだけでは動かない。
  *
  * スキンファイル (skin/pukiwiki.skin.php など) を以下の要領で変更する。
  *
  * return $body; となっている部分を return texthighlight($body); とする。
  * その直前に require_once("plugin/texthighlight.inc.php"); も必要。
  *
  * ヘッダ部分で shjs ライブラリへのリンクを張る
  *   <link rel="stylesheet" type="text/css" href="shjs/css/sh_ide-eclipse.css" />
  *   <script type="text/javascript" src="shjs/sh_main.js"></script>
  * 
  * body onLoad で shjs を呼び出す
  *   <body onLoad="sh_highlightDocument('shjs/lang/', '.js');">
  *
  */
 
 function texthighlight($body)
 {
     // 本当は以下のように preg_replace_callback 一発で終わらせたいの
     // だけれども、これだと $body が長くなるとうまくいかないのでちまちまと
 
 //  return preg_replace_callback(
 //      "#<pre>(?:LANG(?:UAGE)?:".
 //            "([a-zA-Z0-9\#\+\-]+)(\(([^\)]*)\))?\n)?((\n|.)*?)</pre>#",
 //      'do_texthighlight', 
 //      $body);
 
     $newbody= "";
     while( trye ){
         $pos= stripos( $body, "<pre>LANG" );
         if($pos===FALSE)
             break;
         $newbody.= substr($body, 0, $pos);
         $body= substr($body, $pos);
         $end= stripos( $body, "</pre>" );
         $pre= substr($body, 0, $end);
         $body= substr($body, $end+6);
         if( preg_match("#<pre>\s*(?:LANG(?:UAGE)?:".
                 "([a-zA-Z0-9\#\+\-]+)(\(([^\)]*)\))?\s*\n)?#", 
                 $pre, $matches) ) {
             $newbody.= do_texthighlight($matches, substr($pre, strlen($matches[0])));
         }else{
             $newbody.= $pre;
         }
     }
     return $newbody . $body;
 }
 
 function do_texthighlight($matches, $source)
 {
     $language= strtolower($matches[1]);
     $args= $matches[3] ? split(",", $matches[3]) : array();
     $source= html_entity_decode($source);
 
     // 別名に対応
     if($language == "c#") $language= "csharp";
     if($language == "c++") $language= "cpp";
     if($language == "s-lang") $language= "slang";
 
     if( in_array("linenumber", $args) ){
         // 行番号付け
         $n= count(split("\n", $source));
         $numbers= "";
         for($line=1; $line<=$n; $line++)
             $numbers .= sprintf("%d:\n", $line);
         return '<table class="sh_linenumber"><tr><td><pre class="sh_linenumber">' .
                $numbers . '</pre></td><td><pre class="sh_' . $language . '">' . 
                htmlspecialchars($source) . '</pre></td></tr></table>';
     }else
         if( $language ){
         // 横幅を制限するために table に入れている。
         return '<table class="sh_bound"><tr><td><pre class="sh_' . $language . '">' . 
                htmlspecialchars($source) . '</pre></td></tr></table>';
     }else{
         // 横幅を制限するために table に入れている。
         return '<table class="sh_bound"><tr><td><pre>' .
                htmlspecialchars($source) . '</pre></td></tr></table>';
     }
 }
 
 ?>

スタイルシート(pukiwiki.css.php など) の末尾に追加する内容:

 LANG:CSS(linenumber)
 	/* texthighlight.inc.php 関連 */
 
 pre {
   background-color:#f0f0ff !important;
   border: 1px #66e dashed;
   overflow:auto;
   margin:0px;
   padding:.5em;
 }
 
 table.sh_bound {
   min-width:40em;
   margin:0px;
   margin-right:2em;
   margin-left:0.5em;
 }
 
 pre.sh_console {
   background-color:black !important;
   color:white;
   border: 0px;
 }
 
 table.sh_linenumber tr td {
   margin:0px;
   padding:0px;
   border:0px;
   background-color:#f0f0ff;
 }
 
 table.sh_linenumber tr {
   margin:0px;
   padding:0px;
   border:0px;
 }
 
 pre.sh_linenumber {
   color:grey;
   text-align:right;
 }
 
 table.sh_linenumber tr td pre {
   border:0px;
   margin:0px;
   padding:.5em;
 }
 
 table.sh_linenumber {
   background-color:#f0f0ff;
   border: 1px #66e dashed;
   margin:0px;
   margin-right:2em;
   margin-left:0.5em;
 }

* Verilog 用の言語ファイル [#i7e26802]

sh_verilog.js
 LANG:javascript(linenumber)
 if (! this.sh_languages) {
   this.sh_languages = {};
 }
 sh_languages['verilog'] = [
     [
         [ /\/\/[ \t]*synthesis[ \t]+attribute[ \t]/gi, 'sh_preproc', 5 ],
         [ /^[ \t]*`\w/gi, 'sh_preproc', 5 ],
         [ /\#[\w._]+/g, 'sh_preproc', -1 ],
         [ /\/\//g, 'sh_comment', 1 ],
         [ /\/\*/g, 'sh_comment', 2 ],
         [ /\(\*\)/g, 'sh_symbol', -1 ],
         [ /\(\*/g, 'sh_preproc', 4 ],
         [ /\b\d+\b|(?:\b\d+)?'b[01xz]+\b|(?:\b\d+)?'h[0-9a-fxz]+\b|(?:\b\d+)?'d[\dxz]+\b/gi, 'sh_number', -1],
         [ /"/g, 'sh_string', 3 ],
         [ /\$\w+\b/g, 'sh_function', -1 ],
         [ /(?:\.|\$)\w+\s*(?=\()/g, 'sh_function', -1 ],
         [ /\b(?:shortint|int|longint|byte|bit|logic|reg|integer|time|signed|unsigned|real|shortreal|void|candle|event|string)\b/g, 'sh_type', -1 ],
         [ /\b(?:always|end|ifnone|or|rpmos|tranif1|and|endcase|initial|output|rtran|tri|assign|endmodule|inout|parameter|rtr|nif0|tri0|begin|endfunction|input|pmos|rtranif1|tri1|buf|endprimitive|integer|posedge|scalared|triand|bufif0|endspecify|join|primitive|small|trior|bufif1|endtable|large|pull0|specify|trireg|case|endtask|macromodule|pull1|specparam|vectored|casex|event|medium|pullup|strong0|wait|casez|for|module|pulldown|strong1|wand|cmos|force|nand|rcmos|supply0|weak0|deass|gn|forever|negedge|real|supply1|weak1|default|for|nmos|realtime|table|while|defparam|function|nor|reg|task|wire|disable|highz0|not|release|time|wor|edge|highz1|notif0|repeat|tran|xnor|else|if|notif1|rnmos|tranif0|xor)\b/g, 'sh_keyword', -1 ],
         [ /\b(?:generate|endgenerate|genvar|typedef|class|enum|union|struct|localparam|export|import|context|fork)\b/g, 'sh_keyword', -1 ],
         [ /~|!|%|\^|\*|\(|\)|-|\+|=|\[|\]|\\|:|;|,|\.|\/|\?|&|<|>|\||@/g, 'sh_symbol', -1 ],
     ],
     [   // 1
         [ /$/g, null, -2 ],
         [ /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
           'sh_url', -1 ],
     ],
     [   // 2
         [ /\*\//g, null, -2 ],
         [ /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
           'sh_url', -1 ],
     ],
     [   // 3
         [ /\\"|\\\\/g, null, -1 ],
         [ /"/g, 'sh_string', -2 ],
     ],
     [   // 4
         [ /\*\)/g, 'sh_preproc', -2 ],
     ],
     [   // 5
         [ /$/g, 'sh_preproc', -2 ],
     ],
 ];

手書きで適当に書いたので不具合もありそうなのですが。

* 等幅フォントについて [#r30b10b5]

ソースファイルの表示には等幅フォントを使わないと、
インデントがずれて気持ちの悪いことになってしまいます。

&attachref(proportional.PNG);

実は等幅フォント(monospace)を指定しても、firefox 
では日本語フォントと英語フォントとで幅が2:1にならずにずれてしまいました。

また、標準で使われる 'MS ゴシック' の英語フォントでゼロとオーの区別が
つかなかったり、そもそも圧倒的にダサいのも問題です・・・

&attachref(monospace.png);

最近はWebフォントというのがあって、ローカルにインストールされていないフォントで
ブラウザ上に文字を表示することが可能になっているため、これを使って上記の問題を何とか解決しようと
試みています。

今のところ、このサイトでは Google Fonts の Inconsolata を使っています。

http://www.google.com/fonts/specimen/Inconsolata ~
http://www.google.com/fonts#UsePlace:use/Collection:Inconsolata ~

 LANG:javascript
 function MMMMiiii() {                   // コメント
     var data = [                        // コメント
         '日本語データ',  12345,         // コメント
         'Alphabet data', 12345];        // コメント
     for(var i=0; i<data.length; i++) {  // コメント
         alert(data[i]);                 // コメント
     }

Windows 上で MSゴシック と合わせる限り、firefox においても
かなりズレが小さくてすむことから採用している物です。
なぜか(?) Windows 版の IE や Chrome ではまったくずれないようです。

等幅 Google Fonts との組み合わせをいろいろ試してみた結果はこちらです。~
http://dora.bk.tsukuba.ac.jp/~takeuchi/Monospace%20WebFonts.html ~
これまたなぜだか texthighlight に使った場合とズレ方が大きく異なるのですが、参考まで。

* いまごろですが IE8 への対応 [#ub48439f]

IE8 では sh_main.js にて "catch ステートメントでは適用されますが、throw ステートメントでは適用されません。" というエラーが出てうまく動いていないことに今頃になって気付きました。

これは、http://d.hatena.ne.jp/uupaa/20100127/1264566103 にあるように、throw で文字列を投げているのが理由だそうです。

そこで、sh_main.js にて

 LANG:javascript
          throw 'HTTP error: status ' + request.status;

等となっていたところを、

 LANG:javascript
          throw new Error('HTTP error: status ' + request.status);

と直したところ、曲がりなりにも動いているようです?

* GitHub は [#mc810989]

https://github.com/github/linguist

を使っているらしく、いずれこちらに乗り換えたいと思う。

* コメント [#x8544523]

#article_kcaptcha


Counter: 10789 (from 2010/06/03), today: 1, yesterday: 0