Swift公式のLanguage Server(v0.0.1)をVSCodeに導入する


SwiftのLanguage ServerをSwift.orgで作る[宣言](https://forums.swift.org/t/new-lsp-language-service-supporting-swift-and-c-family-languages-for-any-editor-and-platform/17024)から一ヶ月。ついに[sourcekit-lsp](https://github.com/apple/sourcekit-lsp)のリポジトリが誕生しました。

まだ開発初期のため、機能は限定的で、導入手順も自前ビルドが必要な状況ですが、使い勝手を確認すべくVSCodeへの導入を試してみました。

ここでは私が試したmacOS環境における手順を紹介します。
詳細な手順 及び Linux環境向けの手順等は、以下の各種Readmeを参照ください。

* [Readme.md](https://github.com/apple/sourcekit-lsp/blob/master/README.md)
* [Editors/README.md](https://github.com/apple/sourcekit-lsp/blob/master/Editors/README.md)
* [Editors/vscode/README.md](https://github.com/apple/sourcekit-lsp/blob/master/Editors/vscode/README.md)


### 検証環境
* macOS Mojave
* Xcode10.1 (Swift4.2.1)


### 動かした様子

| Quick Help | Code completion |
|:-:|:-:|
|![SourceKitLSP_QuickHelp.png](https://qiita-image-store.s3.amazonaws.com/0/160901/988fddf8-a7f2-b3bb-9609-0a666d577445.png "SourceKitLSP_QuickHelp.png")|![SourceKitLSP_Completion.png](https://qiita-image-store.s3.amazonaws.com/0/160901/9ed5c5e8-19ee-67b5-1eb1-fbc36f4ba1af.png "SourceKitLSP_Completion.png")|


## 導入手順の概要

* sourcekit-lspが参照するSwiftツールチェーンを準備する。
* sourcekit-lspをビルドして、出来上がった実行ファイルの場所を確認する。
* Node.jsをインストールする。
* sourcekit-lspのVSCode拡張機能をビルド&インストールする。
* VSCode拡張機能の設定を行う。


## Swiftツールチェーンを準備する

sourcekit-lspが参照するSwiftツールチェーンを準備し、後のVSCode拡張機能の設定で使用する絶対パスを確認します。推奨な方法 と 怠慢な方法 の２つを紹介します。どちらかを実施してください。

### 推奨な方法

まだ開発初期ということもあり、執筆時点のReadmeでは、`swift-DEVELOPMENT-SNAPSHOT-2018-11-01-a` のツールチェーンを使用する事が[推奨されています](https://github.com/apple/sourcekit-lsp#recommended-toolchain)。

このツールチェーンをmacOS環境で全ユーザ用にインストールしたときは、`/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2018-11-01-a.xctoolchain`のディレクトリ配下に各種ツールが展開されます。このディレクトリの絶対パスをメモしてください。

参考： [代替ツールチェーンの活用](https://developer.apple.com/jp/documentation/ToolsLanguages/Conceptual/Xcode_Overview/AlternativeToolchains.html)

### 怠慢な方法

代替ツールチェーンの準備を怠けたい私は、不要な不具合に遭遇することを覚悟の上で、Xcode付属のSwiftツールチェーンを使用することにしました。Xcodeに付属するswiftコマンドのパスは、以下のコマンドで確認することができます。

```sh:
$ xcrun -f swift
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift
```

Xcodeに付属するツールチェーンのパスは`/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain`となります。この絶対パスをメモしてください。


## sourcekit-lspをビルドする
Language Serverとなるsourcekit-lspをGitからクローンして、ビルドします。

執筆時点のReadmeを見る限りでは、sourcekit-lspをビルドするためのSwiftツールチェーンに関しては特に指定が無いようです。今回、私が試したところでは、Xcode10.1付属のSwift4.2.1コンパイラで難なくビルドできました。 [^3a]

[^3a]: `swift-DEVELOPMENT-SNAPSHOT-2018-11-01-a` のツールチェーンによるビルドは試してないです。すみません。

```sh:
$ git clone https://github.com/apple/sourcekit-lsp.git
$ cd sourcekit-lsp
$ swift build -c release 
```

ビルド後は、以下のような場所に実行ファイルが生成されます。
出来上がったsourcekit-lspの絶対パスをメモしてください。後のVSCode拡張機能の設定で使用します。

```sh:
# リリースビルド後は、以下の場所に実行ファイルが生成される。
$ ls .build/release/sourcekit-lsp
.build/release/sourcekit-lsp
```



## Node.jsをインストールする 

Language ServerのクライアントとなるVSCode拡張機能をビルドするために、Node.jsをインストールします。

macOS環境向けの手順の参考: [MacにNode.jsをインストール](https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09)

```sh:
# nodebrew(node.jsのバージョン管理ツール)をInstallする
$ brew install nodebrew
```

```sh:
# nodebrew の作業ディレクトリ(~/.nodebrew/*)を作る
$ nodebrew setup_dirs
```

```sh:
# 最新Verのnode.jsをInstallする
$ nodebrew install-binary latest
```

```sh:
# Installしたnode.jsのバージョンを確認する
$ nodebrew list
v11.1.0

current: none
```

```sh:
# Installしたバージョンのnode.jsを使用する
$ nodebrew use v11.1.0
$ nodebrew list
v11.1.0

current: v11.1.0
```

仕上げに、currentに設定したNode.jsのツールに対して`PATH`を通します。

```sh:.bash_profile
# nodebiew's node.js toolchain.
export PATH=$HOME/.nodebrew/current/bin:$PATH
```



## VSCode拡張機能をビルド＆インストールする

`npm`が使えるようになったので、VSCode拡張機能をビルド＆インストールします。

```sh:
# カレント・ディレクトリが sourcekit-lsp/ である状態からの続き
$ cd Editors/vscode
# ビルドする。
$ npm run createDevPackage
# VSCodeにインストールする。 
$ code --install-extension out/sourcekit-lsp-vscode-dev.vsix
```

参考: [ターミナルからVisual Studio Codeを起動する方法【公式の方法】](https://qiita.com/naru0504/items/c2ed8869ffbf7682cf5c)


## VSCode拡張機能の設定

VSCodeを起動し、設定画面を開き、SourceKit-LSPの設定欄へ移動します。

* Server Path: ビルドしたsourcekit-lspの実行ファイルの絶対パスを設定します。
* Toolchain Path: 冒頭で確認したSwiftツールチェーンの絶対パスを設定します。

<img width="941" alt="SourceKitLSP_Config5.png" src="https://qiita-image-store.s3.amazonaws.com/0/160901/1550f32c-9d90-2a0c-4cba-00b0bf6af55b.png">

### 環境変数`SOURCEKIT_TOOLCHAIN_PATH`

sourcekit-lspは、幾つかの方法でSwiftツールチェーンの場所を探します。このとき環境変数`SOURCEKIT_TOOLCHAIN_PATH`が存在する場合は、この環境変数に設定された場所を優先的に使用するようです[^5a]。

VSCode拡張機能がsourcekit-lspを起動する際は、　プロセスの環境変数として`SOURCEKIT_TOOLCHAIN_PATH`へToolchain Pathのパスが設定されます[^5b]。

そのため以下のように`.bash_profile`で`SOURCEKIT_TOOLCHAIN_PATH`を設定している場合は、Toolchain Pathの設定は空のままでも大丈夫です[^5c]。

```sh:.bash_profile
# 怠慢な方法で準備したSwiftツールチェーンの場所
export SOURCEKIT_TOOLCHAIN_PATH=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain
```

[^5a]: sourcekit-lsp/Sources/SKCore/ToolchainRegistry.swift
[^5b]: sourcekit-lsp/Editors/vscode/src/extension.ts
[^5c]: なお、次優先的には標準的なインストール場所やPATHの場所を探すようです。そのためswiftコマンドのPATHが通っている状態ならば、確実性が低くなりますが、`SOURCEKIT_TOOLCHAIN_PATH`やToolchain Pathの設定を行わずとも、sourcekit-lspが動作可能なようです。


## さぁ、使ってみよう！！

以上で導入手順は完了です。
手元にある適当なSwiftPMパッケージのフォルダをVSCodeで開いてみましょう！