様々な言語に対応したシンタックスハイライトツールHighlightについて。
ソースのダウンロード、展開。
wget http://www.andre-simon.de/zip/highlight-2.16.tar.bz2 tar -xvf highlight-2.16.tar.bz2 cd highlight-2.16/
パッケージにはconfigureは含まれておらず、標準では/usrにインストールされる。 /usr以外にインストールする場合は、以下のようにmakefileを直接編集する。
11c11 < PREFIX = /usr --- > PREFIX = /usr/localPREFIX = /usr/local]]>
make, make installする。
make sudo make install
ここまでの操作ではコマンドラインインターフェイスのみしかビルドされない。 GUIが必要な場合は、以下のコマンドでビルドする。
make gui sudo make install-gui
インストールできたら、確認をかねてhighlight -pでハイライトできる言語の一覧を表示してみる。
$ highlight -p Installed language definitions (located in /usr/local/share/highlight/langDefs/): Informix : 4gl ASCEND : a4c Advanced Backus-Naur Form: abnf ABAP/4 : abp : :
examples/swig/highlight.iにSWIGのインターフェイス定義ファイルが用意されているので、これを使ってC#用バインディングを作成する。 なお、ここで使用したSWIGのバージョンは1.3.36である。
用意されているmakefileはPython, Perl用のバインディングを作成するようにしか書かれていないので、これに追記してC#用バインディングを作成するmakefileを書く。 追記する内容は以下の通り。
2a3 > CSC=gmcs 25a27,33 > csharp: > ${MAKE} -C ../../ -f ./makefile > swig -c++ -csharp -o highlight_wrap.cpp -dllimport libhighlight -namespace highlight highlight.i > ${CXX} -c highlight_wrap.cpp -I${HL_SRC} > ${CXX} -shared -s highlight_wrap.o -L${HL_SRC} -lhighlight -o libhighlight.so > patch -d . -p0 < highlight.patch > ${CSC} /t:library /out:highlight.dll *.cs 34c42 < .PHONY: python python-clean perl perl-clean clean --- > .PHONY: python python-clean perl perl-clean clean csharp csharp-cleanCSC=gmcs 25a27,33 > csharp: > ${MAKE} -C ../../ -f ./makefile > swig -c++ -csharp -o highlight_wrap.cpp -dllimport libhighlight -namespace highlight highlight.i > ${CXX} -c highlight_wrap.cpp -I${HL_SRC} > ${CXX} -shared -s highlight_wrap.o -L${HL_SRC} -lhighlight -o libhighlight.so > patch -d . -p0 < highlight.patch > ${CSC} /t:library /out:highlight.dll *.cs 34c42 < .PHONY: python python-clean perl perl-clean clean --- > .PHONY: python python-clean perl perl-clean clean csharp csharp-clean]]>
ここでswigに渡しているオプションの詳細は次の通り。
また、swigが生成するRegexDef.cs, ReGroup.cs, RegexElement.csをそのままコンパイルするとエラーとなってしまうので、修正する必要がある。 上記のmakefile内で自動的にソースを修正するようにしてあるので、以下の内容でパッチを作成しておく。
Index: RegexDef.cs =================================================================== --- RegexDef.cs.org 2009-11-01 08:43:58.000000000 +0900 +++ RegexDef.cs 2009-11-01 08:44:51.000000000 +0900 @@ -48,9 +48,7 @@ if (highlightPINVOKE.SWIGPendingException.Pending) throw highlightPINVOKE.SWIGPendingException.Retrieve(); } get { - SWIGTYPE_p_string ret = new SWIGTYPE_p_string(highlightPINVOKE.RegexDef_reString_get(swigCPtr), true); - if (highlightPINVOKE.SWIGPendingException.Pending) throw highlightPINVOKE.SWIGPendingException.Retrieve(); - return ret; + return highlightPINVOKE.RegexDef_reString_get(swigCPtr); } } Index: ReGroup.cs =================================================================== --- ReGroup.cs.org 2009-11-01 08:43:58.000000000 +0900 +++ ReGroup.cs 2009-11-01 08:44:51.000000000 +0900 @@ -86,9 +86,7 @@ if (highlightPINVOKE.SWIGPendingException.Pending) throw highlightPINVOKE.SWIGPendingException.Retrieve(); } get { - SWIGTYPE_p_string ret = new SWIGTYPE_p_string(highlightPINVOKE.ReGroup_name_get(swigCPtr), true); - if (highlightPINVOKE.SWIGPendingException.Pending) throw highlightPINVOKE.SWIGPendingException.Retrieve(); - return ret; + return highlightPINVOKE.ReGroup_name_get(swigCPtr); } } Index: RegexElement.cs =================================================================== --- RegexElement.cs.org 2009-11-01 08:43:58.000000000 +0900 +++ RegexElement.cs 2009-11-01 08:44:51.000000000 +0900 @@ -112,9 +112,7 @@ if (highlightPINVOKE.SWIGPendingException.Pending) throw highlightPINVOKE.SWIGPendingException.Retrieve(); } get { - SWIGTYPE_p_string ret = new SWIGTYPE_p_string(highlightPINVOKE.RegexElement_langName_get(swigCPtr), true); - if (highlightPINVOKE.SWIGPendingException.Pending) throw highlightPINVOKE.SWIGPendingException.Retrieve(); - return ret; + return highlightPINVOKE.RegexElement_langName_get(swigCPtr); } }
makefileへの追記が済んだらmake csharpでmakeする。
$ make csharp make -C ../../ -f ./makefile make[1]: ディレクトリ `/srv/files/build/highlight/highlight-2.16' に入ります make -C ./src -f ./makefile HL_DATA_DIR=/usr/local/share/highlight/ HL_CONFIG_DIR=/etc/highlight/ make[2]: ディレクトリ `/srv/files/build/highlight/highlight-2.16/src' に入ります c++ -o highlight arg_parser.o cmdlineoptions.o main.o help.o -L. -lhighlight make[2]: ディレクトリ `/srv/files/build/highlight/highlight-2.16/src' から出ます make[1]: ディレクトリ `/srv/files/build/highlight/highlight-2.16' から出ます swig -c++ -csharp -o highlight_wrap.cpp -dllimport libhighlight -namespace highlight highlight.i ../../src/core/codegenerator.h:86: Warning(503): Can't wrap 'operator =' unless renamed to a valid identifier. g++ -c highlight_wrap.cpp -I../../src/ g++ -shared -s highlight_wrap.o -L../../src/ -lhighlight -o libhighlight.so patch -d . -p0 < highlight.patch patching file RegexDef.cs patching file ReGroup.cs patching file RegexElement.cs gmcs /t:library /out:highlight.dll *.cs
これでライブラリhighlight.soおよびラッパhighlight.dllが作成される。 作成したラッパが動作するかテストコードを作ってテストしてみる。
using System; using highlight; class testmod { public static void Main(string[] args) { var gen = CodeGenerator.getInstance(OutputType.HTML); var input = @"public class Test { public static void Main(string[] args) { Console.WriteLine(""Hello, world!""); } }"; gen.initTheme("/usr/local/share/highlight/themes/ide-msvs2008.style"); gen.initLanguage("/usr/local/share/highlight/langDefs/cs.lang"); gen.setIncludeStyle(true); gen.setEncoding("UTF-8"); Console.WriteLine(gen.generateString(input)); CodeGenerator.deleteInstance(gen); } }
上記のコードをコンパイル・実行すると、HTMLでマークアップされたハイライト済みのテキストが出力される。
$ gmcs -r:./highlight.dll testmod.cs && mono testmod.exe
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Source file</title>
<style type="text/css">
<!--
body.hl { background-color:#ffffff; }
pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:'Courier New';}
.hl.num { color:#000000; }
.hl.esc { color:#a31515; }
.hl.str { color:#a31515; }
.hl.dstr { color:#0000ff; }
.hl.slc { color:#008000; }
.hl.com { color:#008000; }
.hl.dir { color:#0000ff; }
.hl.sym { color:#000000; }
.hl.line { color:#2b91af; }
.hl.mark { background-color:#ffffbb;}
.hl.kwa { color:#0000ff; }
.hl.kwb { color:#0000ff; }
.hl.kwc { color:#2b91af; }
.hl.kwd { color:#000000; }
//-->
</style>
</head>
<body class="hl">
<pre class="hl"><span class="hl kwa">public class</span> Test <span class="hl sym">{</span>
<span class="hl kwa">public static</span> <span class="hl kwb">void</span> <span class="hl kwd">Main</span><span class="hl sym">(</span><span class="hl kwb">string</span><span class="hl sym">[]</span> args<span class="hl sym">)</span>
<span class="hl sym">{</span>
Console<span class="hl sym">.</span><span class="hl kwd">WriteLine</span><span class="hl sym">(</span><span class="hl str">"Hello, world!"</span><span class="hl sym">);</span>
<span class="hl sym">}</span>
<span class="hl sym">}</span>
</pre>
</body>
</html>
<!--HTML generated by highlight 2.13, http://www.andre-simon.de/-->