Swift その2の14日目を担当させていただく@ushisantoasobuと申します。よろしくお願いします
概要
今日のテーマはSourceKit
になります。
先月SourceKit
の機能を利用できるSourceKitten
というライブラリについてLTをしてきました
このアドベントカレンダーでは、それを文章としてまとめあげたものにすればまあいいだろうと高を括っていましたが、Swiftのオープンソース化に伴いSourceKit
自体のソースも読めるようになったので、そこらへんについてもほんのちょっと触れるようにはしたいと思います
SourceKitとは
あの憎っくき?
Swiftが世に出はじめたころからXcodeでSwiftを書いてきた人で、このクラッシュモーダルに遭遇したことはないという人はおそらくいないと思います。
意気揚々とSwiftを書いていると、突然このようなモーダルが表示されてXcodeが動かなくなるという・・・。クラッシュメッセージが、
SourceKitService Terminated
ということから、当時「SourceKitのせいでXcodeが動かなくなった、SourceKitさん頼むよー」といった内容のツイートが多く散見されましたが、自分もあの憎っくきSourceKitめみたいな認識が冗談半分にありました
Xcodeのサポートツール
SourceKit
とは一言で言うと、Swiftのコードをパース・解析して、その結果をもとに開発者をサポートしてくれるツールになります。
Xcodeの6.x
以降、実はSourceKit
は別プロセスとしてXcodeとともに起動していて(正確にはSwiftのファイルをロードしたとき)、XPC経由で処理のやりとりをしています
- シンタックスハイライト
- オートコンプリート(補完)
- 定義元ジャンプ
- コードフォーマット
など、当たり前のように提供されているIDEの機能は、Xcode 6.x
以降でSwiftを書くときにはSourceKitによるものということですね(Xcodeの6.x
以前(あくまでLLVM/Clang
以降)については、ここらへんがよくわかっていないのですが、コンパイラであるClang(LibClang
?)がやっていくれていたという認識です)
プロセスが起動していることを確認する
Xcode(6.x
以降)を起動して.swfit
のファイルを開くと、以下のようなコマンドでSourceKitService
が起動していることが確認できます。
$ ps aux | grep sourcekit
ushisantoasobu 70314 0.0 0.0 2423356 208 s014 R+ 6:17PM 0:00.00 grep sourcekit
ushisantoasobu 70311 0.0 0.1 2514388 4764 ?? Ss 6:17PM 0:00.21 /Applications/Xcode 7.0.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/sourcekitd.framework/Versions/A/XPCServices/SourceKitService.xpc/Contents/MacOS/SourceKitService
ログを出力してみる
Xcode・SourceKit
間の処理のやりとりをログ出力することができます。以下のようにXcodeを起動してみてください
export SOURCEKIT_LOGGING=3 && /Applications/Xcode\ 7.0.1.app/Contents/MacOS/Xcode
.swift
のファイルをいろいろいじると(ファイルを開く、カーソルをコードの上に合わせる、だけでも)ログが出力されると思います
sourcekit: [2:sourcekitd_send_request_sync-before:1299:666.2319] {
key.request: source.request.editor.formattext,
key.name: "/Users/ushisantoasobu/Documents/Twitilized/Twitilized/models/Setting.swift",
key.line: 13,
key.length: 1,
key.sourcetext: "",
key.editor.format.options: {
key.editor.format.indentwidth: 4,
key.editor.format.tabwidth: 4,
key.editor.format.usetabs: 0
}
}
...
key.request
をみていくと、各処理でどのようなことがやりとりされているのかがわかると思います(source.request.indexsource
、source.request.cursorinfo
、source.request.editor.replacetext
などなど)
ソースが読めるようになった
先述したように、Swiftがオープンソース化されてSourceKit
自体のソースも読めるようになりました
SourceKitten
とは
Realm
のJP Simard
さんという方がつくったもので、SourceKit
の機能を利用することができるライブラリになります。
SourceKit
はこれまで(オープンソース化以前)は完全にドキュメントも存在しない非公開のAPIだったのですが、先述のログ出力の結果から解析してつくったもののようです。こちらに詳しく説明があります。
コマンドラインツールを使ってみる
SourceKitten
はコマンドラインツールとしても提供されているので、少し試してみましょう
$ brew install sourcekitten
でインストールできます。help
を叩いてみましょう。提供されているコマンドがわかります
$ sourcekitten help
Available commands:
complete Generate code completion options.
doc Print Swift docs as JSON or Objective-C docs as XML
help Display general or command-specific help
structure Print Swift structure information as JSON
syntax Print Swift syntax information as JSON
version Display the current version of SourceKitten
次にsyntax
コマンドを打ってみましょう。以下のようにHoge.swift
ファイルを指定します
$ sourcekitten syntax --file ./Hoge.swift
以下のような結果が表示されます(長いので後半は省略)
[
{
"offset" : 0,
"length" : 3,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 3,
"length" : 26,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 29,
"length" : 15,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 44,
"length" : 3,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 47,
"length" : 43,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 90,
"length" : 61,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 151,
"length" : 3,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 155,
"length" : 6,
"type" : "source.lang.swift.syntaxtype.keyword"
},
{
"offset" : 162,
"length" : 5,
"type" : "source.lang.swift.syntaxtype.identifier"
},
{
"offset" : 168,
"length" : 6,
"type" : "source.lang.swift.syntaxtype.keyword"
},
{
"offset" : 175,
"length" : 13,
"type" : "source.lang.swift.syntaxtype.identifier"
},
{
"offset" : 190,
"length" : 16,
"type" : "source.lang.swift.syntaxtype.comment"
},
{
"offset" : 207,
"length" : 4,
"type" : "source.lang.swift.syntaxtype.keyword"
},
{
"offset" : 212,
"length" : 14,
"type" : "source.lang.swift.syntaxtype.identifier"
},
{
"offset" : 232,
"length" : 7,
"type" : "source.lang.swift.syntaxtype.typeidentifier"
},
(長いので省略...)
]
SourceKitten
を利用してできること
さて、SourceKitten
を利用してなにができるのでしょうか?
さきのsyntax
コマンドの出力結果をみて「それがどうしたの?」と思った方も多いはずです。
SourceKitten
はあくまでSourceKit
のラッパライブラリとしての責務を担うもので、それを利用したより実践的なライブラリを2つ紹介して終わりたいと思います(ともに、作者というか一番のコントリビュータは同じJP Simard
さんです)
SwiftLint
SwiftのLinterです。使い方等は以前Qiitaも書きました(こちら)ので、良ければそちらをみてください
jazzy
SwiftDocのジェネレータです。Appleのリファレンスと同じようなドキュメントを生成してくれるようです