LoginSignup
28
24

More than 5 years have passed since last update.

Swift SourceKitを使ってSwiftソースコードをハイライトする

Last updated at Posted at 2014-12-28

追記(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>)
28
24
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
24