追記(2015/12/08): SourceKittのソースコードが公開されたので、安心して使ってつかってよさそうです。めでたい。
sourcekittenという、Swift SourceKitのフロントエンドがあります。これを使うと、おそらくXcodeが内部的に使っているものと同じコード解析エンジンをつかってSwiftソースコードをハイライトできます。ただし、これはXcode/Swift toolchainの非公開APIなので、いつまで安定して使えるかはわかりません。
インストールはsourcekittenを git clone
して ./install.sh
をするだけ。これでsourcekittenをビルドして /usr/local/bin/sourcekitten
にコマンドとしてインストールします。
これで、たとえば次のようなSwiftソースコードがあるとします。
import func Foundation.NSLog
class C {}
// Using Foundation
NSLog("Hello, Swift!")
これを sourcekitten --syntax hello.swift
で処理すると次のようなJSONになります。
[
{
"offset" : 0,
"length" : 6,
"type" : "source.lang.swift.syntaxtype.keyword"
},
{
"offset" : 7,
"length" : 4,
"type" : "source.lang.swift.syntaxtype.keyword"
},
{
"offset" : 12,
"length" : 10,
"type" : "source.lang.swift.syntaxtype.identifier"
},
{
"offset" : 23,
"length" : 5,
"type" : "source.lang.swift.syntaxtype.identifier"
},
{
"offset" : 30,
"length" : 5,
"type" : "source.lang.swift.syntaxtype.keyword"
},
{
"offset" : 36,
"length" : 1,
"type" : "source.lang.swift.syntaxtype.identifier"
},
{
"offset" : 42,
"length" : 20,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 62,
"length" : 5,
"type" : "source.lang.swift.syntaxtype.identifier"
},
{
"offset" : 68,
"length" : 15,
"type" : "source.lang.swift.syntaxtype.string"
}
]
それぞれのtokenにtypeが与えられていますね。たとえばHTML化は次のようなスクリプトでできるでしょう。すべてのtokenにtypeが与えられるわけではないので、tokenのリストを末尾からもとのソースコードに適用することでtypeが与えられているtokenだけ処理するようにしています。
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use JSON ();
chomp(my $sourcekitten = `which sourcekitten`);
$sourcekitten or die "sourcekitten(1) is not installed.\n";
foreach my $file (@ARGV) {
my $source = do {
open my($in), "<", $file;
local $/;
<$in>;
};
my $json = `"$sourcekitten" --syntax "$file"` or die "failed to parse";
foreach my $syntax(reverse @{JSON::decode_json($json)}) {
my $offset = $syntax->{offset};
my $length = $syntax->{length};
my $type = $syntax->{type};
my $class = (split /\./, $type)[-1];
my $token = substr($source, $offset, $length);
substr($source, $offset, $length, qq{<span class="$class">$token</span>});
}
print $source;
}
前述のhello.swiftを処理すると次のようになります。あとはCSSて適当に色を付けるだけですね。
<span class="keyword">import</span> <span class="keyword">func</span> <span class="identifier">Foundation</span>.<span class="identifier">NSLog</span>
<span class="keyword">class</span> <span class="identifier">C</span> {}
<span class="comment">// Using Foundation
</span><span class="identifier">NSLog</span>(<span class="string">"Hello, Swift!"</span>)