XcodeにWarningやErrorを好きな所に表示したい #Xcode #typo #spellchecker

[iOS Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ios) 3日目の[かっくん(@fromkk)](https://twitter.com/fromkk)です。
XcodeでiOSアプリなどを開発してて独自のwarningをXcode上に表示したいなと思う事がありました。
調べてみると`Run Script`に標準出力で決まった記法で表示すると独自のワーニングやエラーを表示する事が出来る事が分かったのでまとめておきます。

## ファイルなどの指定無し

```sh
# warning
echo "warning: some warning message"
# error
echo "error: some error message"
```

これをRun Scriptに記入するだけでワーニングとエラーが表示されます。

<img width="308" alt="スクリーンショット 2019-11-24 18.19.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846/6f8ee8e4-c09f-8c1e-9631-208018b98f96.png">


## ファイル指定


```sh
# warning
echo "/path/to/your/file: warning: some warning message"
# error
echo "/path/to/your/file: error: some error message"
```

これだけでファイルを指定してワーニングとエラーが表示されます。

<img width="455" alt="スクリーンショット 2019-11-24 18.21.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846/3e0c05f5-3283-5656-dd35-e01428eeb696.png">


## 行数と文字の箇所指定

```sh
line=61
column=28

# warning
echo "/path/to/your/file:$line:$column: warning: some warning message"
# error
echo "/path/to/your/file:$line:$column: error: some error message"
```

と指定すれば該当の行数と文字の箇所にワーニングとエラーが表示されます。  

<img width="403" alt="スクリーンショット 2019-11-24 18.24.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846/c01a055b-341b-aaa1-a602-165b270170be.png">

尚、`Run Script`でエラーを表示するだけではビルドは止まりません。
(`exit 0`以外のステータスを返せば止まるはず)


# typoを見つける為のツールを作ってみた

上記のフォーマットを利用してtypoを見つけるために[SpellChecker](https://github.com/fromkk/SpellChecker)というCLIツールを作ってみました。
インストール方法は

```sh
git clone git@github.com:fromkk/SpellChecker.git
cd ./SpellChecker
make install
```

でインストール可能です。

## 使い方

CLIツールとしても利用可能なので、

```sh
/usr/local/bin/SpellChecker -yml WhiteList.yml -- /path/to/ViewController.swift /path/to/Model.swift
```

の様な感じで利用可能です。
`-yml` の後にワーニングを無視するためのYAMLファイルのパスを指定することができます。
また、 `--` の後ろにスペルチェックしたいファイルのパスの一覧を渡します。

### YAML

対応しているフォーマットは

```yaml
whiteList:
  - kazuya
  - ueoka
  - fromkk
```

の様な感じです。

### Run Script

Xcodeのプロジェクトに新しくRun Scriptを追加して下記の様なコードを追加します。

```sh
if ! [ -f /usr/local/bin/SpellChecker ]; then
    echo "SpellChecker not installed"
    exit 0
fi

git_path=/usr/local/bin/git
files=$($git_path diff --diff-filter=d --name-only -- "*.swift" "*.h" "*.m")
if (test -z $files) || (test ${#files[@]} -eq 0); then
  echo "no files changed."
  exit 0
fi

options=""
for file in $files
do
  options="$options $SRCROOT/$file"
done

/usr/local/bin/SpellChecker -yml $SRCROOT/whitelist.yml -- $options

```

これでコードを適当に変更してビルドすると

<img width="584" alt="screenshot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2846/2b418359-aacb-ab5a-1b3a-2f09843b2e2d.png">

こんな感じでwarningが表示されるのでどこでタイポしているかが一目瞭然になります。

良かったらスター :star: ください :thumbsup: 
**[SpellChecker](https://github.com/fromkk/SpellChecker)**

---

## 開発にあたって考えた事など

### typoを検知する仕組みについて

いくつか検討・実装をしてみて一番簡単でコストの掛からない方法を模索していました。
ざっと以下の様な感じです。

1. ツールから[cspell](https://github.com/streetsidesoftware/cspell)をそのまま呼ぶ事を検討したが **却下**
  - `cspell` が重たいのが気になった
  - 出力結果の変換が面倒
  - 外部ツールへの依存はあまりしたく無かった
2. [cspell](https://github.com/streetsidesoftware/cspell)を参考にして単語リストを作成して、リストに無い場合はタイポと見なす方法を検討したが **却下**
  - 単語リストが重たい
  - 重たいリストを読み込んでパースする処理も比例して重たい
  - Swift Package Managerではリソースを持つ事が出来なかった
3. Xcode上で使われる事を想定するとLinuxの事を考える必要が無いなと思い、macOSが持ってる辞書を利用出来ないかを検討したが **却下**
  - 精度が悪い(想像以上に辞書に登録されている単語が少なかった)
  - Private APIを利用しないと辞書の選択が出来ない(しかもObjective-Cからしか利用出来ない)
4. スペルチェックで調べていると[UITextChecker](https://developer.apple.com/documentation/uikit/uitextchecker)というものを発見し、iOSにあるならmacOSにもあるだろと調べていたら[NSSpellChecker](https://developer.apple.com/documentation/appkit/nsspellchecker)を発見し良さそうだったので **採用** :tada: 
  - 逆に精度が高すぎて `hoge` や `fuga` などがタイポにならないのが少し気になる
  - 運用する中で検討していきたい

#### 補足(謝辞)

ちなみに、念の為、他にも同様のツールが無いか簡単に調べた上で作ったんですが、上記の `NSSpellChecker` の使い方を調べている中で @ezura さんの [ezura/spell-checker-for-swift](https://github.com/ezura/spell-checker-for-swift) を発見しました。
完全に用途も被っており途中で作るのを諦めるか悩んだのですが、ezuraさんの方が[SwiftSyntax](https://github.com/apple/swift-syntax)を利用している事を発見し、Swiftファイルに限定された用途なのだと理解しました。
僕の方はあえて[SwiftSyntax](https://github.com/apple/swift-syntax)を利用せず、半角英字を見つけたらスペルチェックをする様にしているので特にファイル形式を問わない様に作っています。
どちらが良い・悪いというものでもなく、用途に合わせて良いなと思った方を使って頂ければと思います :pray: 
尚、 `NSSpellChecker` の使い方はとても参考にさせて頂きました。ありがとうございました :bow: 

# まとめ

Advent Calendarドリブンで色々調べたり開発をしたりしてたのですが、結果的に車輪の再開発をしてしまった部分もあるかもしれませんが、個人的には良いものが出来たかなと思いました。
今後自分で使っていく中でメンテナンスなどはしていくと思いますが、バグや要望などがあればお気軽に[SpellChecker](https://github.com/fromkk/SpellChecker)まで頂ければと思います。
ついでに改めてですが、良かったらスター :star: ください :thumbsup: 
**[SpellChecker](https://github.com/fromkk/SpellChecker)**

振り返ってみるとあまりiOS関係無かったですね。明日は @shtnkgm さんです。