君は完璧で究極のエディター ~NeovimでSwiftを書く~

おはこんばんにちは。ウホーイ(@the_uhooi)です。

本記事では、完璧で究極のエディターである「Neovim」でiOSアプリ開発に挑戦していることを紹介します。

iOSアプリは「Xcode」というIDEを使って開発するのが一般的です。Xcodeを使わずにNeovimでどこまでできるのか、ぜひ最後まで読んでみてください。

余談

最初は真面目に草案を執筆していたのですが、Findyの担当者に見せたら「暴走のウホーレンくらいふざけていいです」と言われたので、思う存分ふざけることにしました。

念のためエビデンスを添付します。

▲担当者から送られてきたDM

「暴走のウホーレン」とは、私が「iOSDC Japan 2024」というカンファレンスで登壇するトークのタイトルです。

day2 8/24(土) 17:00 Track Aで5分間話すので、ぜひみなさん聴きに来てください。

チケットの購入もまだ間に合います。

fortee.jp

fortee.jp

トークの宣伝もしていいと担当者に言われているので、エビデンスを(ry

▲担当者から(ry

ちなみに本記事のタイトルはiOSDC Japan 2023で非採択となったプロポーザルから取っています。

せっかく考えたので、こちらで使わせてもらいました。

NeovimでSwiftを書くきっかけ

ここから本題です。

まずは私がNeovimでSwiftを書くようになったきっかけを紹介します。

私が一番好きな言語はSwiftです。そして一番好きなエディタはNeovimです。しかし普段はXcodeでSwiftを書いています。Xcodeも好きだし今でもメインで使っています。でもどうせなら一番好きな言語を一番好きなエディタで書きたいと考えるようになりました。これは自然の摂理です。

Neovimのインストール

ここから先は実際に手元でNeovimを動かせたほうが面白いので、インストールします。

基本的にはターミナルで brew install neovim を実行するのみです。

nvim を実行して以下の画面が表示されたら成功です。

▲Neovimの起動画面

※iOSアプリ開発ではmacOSが必須なので、本記事はmacOSの利用を前提としています。

NeovimでSwiftを書くための設定

次にNeovimでSwiftを書くための設定です。

ちょうど先日AppleがSwift向けの設定方法を公開したので、こちらに記載されていることはほぼ省略します。

VimやNeovimは設定が大変(それが面白いのですが)なので、気軽に試す場合はLazyVimがオススメです。

自分で設定する人向けに、設定をキーワードベースで紹介します。

  • プラグインマネージャー: lazy.nvim
  • LSP設定: nvim-lspconfig
  • 言語サーバー: SourceKit-LSP(Appleが提供している言語サーバー)
  • 補完: nvim-cmp

私の設定も置いておきます。日々更新しているので、よかったらたまに覗いて参考にしてください。

github.com

ここまで設定できると、以下ができるようになります。

  • シンタックスハイライト
  • 補完(iOS SDKを除く)

▲NeovimでSwiftファイルを開いているところ

私はゴリゴリにカスタマイズしているので表示がリッチですが、みなさんの環境でもコードにシンタックスハイライトが付くようになったはずです。

NeovimでiOSアプリ開発するための設定

NeovimでSwiftを書けるようになりましたが、これだけではiOSアプリ開発はできません。

iOS SDK(UIKitなど)を補完できるようにしたり、シミュレータを起動してデバッグできるようにしたりしないとXcodeの代わりにはなり得ません。

これらについて触れられている日本語の記事は見たことないため、詳細に説明します。

iOS SDKを補完できるようにする

SDKのパスを取得し、それをSourceKit-LSP(言語サーバー)へ伝えるよう設定すれば補完できるようになります。

ターミナルで以下のコマンドを実行します。

$ xcrun --sdk iphonesimulator --show-sdk-path
/Applications/Xcode-15.4.0.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk

このパスをSourceKit-LSPへ伝えるよう設定します。

lspconfig.sourcekit.setup {
  -- …
  cmd = {
    'sourcekit-lsp',
    '-Xswiftc',
    '-sdk',
    '-Xswiftc',
    '/Applications/Xcode-15.4.0.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator17.5.sdk',
    '-Xswiftc',
    '-target',
    '-Xswiftc',
    'x86_64-apple-ios17.5-simulator',
  },
}

これでUIKitなどが補完できるようになりました。

▲UIKitのUIViewControllerを補完しているところ

こちらの設定は以下の記事を参考にさせていただきました。

qiita.com

ブレークポイントを貼ってデバッグできるようにする

Neovimでここまでやるのは難しいと思っていましたが、プラグインを開発してくださった方がいて、そのおかげで私でもできるようになりました。

詳細な設定方法はプラグイン開発者のブログをご参照ください。

wojciechkulik.pl

仕組みを簡単に説明します。

シンタックスハイライトや補完は「LSP(Language Server Protocol)」というMicrosoftが主にVSCodeのために提供しているプロトコルをNeovimでも使うことで実現しています。

それと同じようにMicrosoftが「DAP(Debug Adapter Protocol)」というプロトコルを提供しており、これを使うことでデバッグを実現します。

例によって設定をキーワードベースで紹介します。

  • DAPクライアント: nvim-dap + nvim-dap-ui
  • デバッガ: CodeLLDB(LLDB拡張)
  • iOSアプリ開発支援: xcodebuild.nvim

予め設定しているNeovimがあるので、どのようにデバッグできるか見てみましょう。

ブレークポイントを貼ります。86と87行目に貼りました。

▲ブレークポイントを貼ったところ

これでデバッグを実行します。

▲ビルドしているところ。右上にビルド中の表示がある

ビルドに成功するとシミュレータにアプリが表示され、Neovim上でDAPクライアントが起動します。

▲デバッグが開始されたところ。左にブレークポイントを貼った箇所、右下に停止やステップオーバーなどのボタンがある

先ほどブレークポイントを貼った箇所は、画面左下にある「新規」ボタンのタップ時に実行されるので、早速タップしてみましょう。

無事にブレークポイントに引っ掛かりました。

▲ブレークポイントに引っ掛かったところ。行の背景色が青になるよう設定している

uiState.shouldShowInputScreen の値をホバーで見てみます。87行目はまだ実行されてないので false ということがわかります。

▲87行目にある変数の中身を見ているところ

ステップオーバーを2回実行して再度値を確認すると、 true に更新されていることがわかります。

▲87行目にある変数の中身を見ているところ

このように、Xcodeを使わなくてもブレークポイントを貼ってデバッグできるようになりました。

右下にある赤い四角のアイコンをタップし、デバッグを終了します。

NeovimとXcodeの比較

NeovimでiOSアプリ開発が一通りできるようになったので、Xcodeと比べてみます。

Neovimでしかできないこと

Neovimは何もできないし、何でもできるともいえます。

デフォルトだと最低限のことしかできません。しかしLuaを使って機能を何でも拡張できるので、ターミナルでできることは理論上すべて実現できるはずです。

Xcodeでできない一例を紹介します。

型情報をインレイヒントで表示する

LSPには「Inlay hint(インレイヒント)」という機能があり、型情報などをインラインに表示できます。

Neovimもプラグインを使うことでインレイヒントを表示できます。

以下の11行目と12行目は型を省略しているのですが、右辺から型推論してそれをインレイヒントとして表示しています。

▲StringとBoolの型推論を表示しているところ

他にもenumのAssociated valueやforループしている値の型などを表示できます。

このように、Xcodeでは実装されていない機能をカスタマイズして実現できるのがNeovimの魅力のひとつです。

起動が速い

大量のプラグインを起動時に読み込ませている場合を除き、爆速で起動します。

起動が遅い場合も原因を追求してチューニングできます。

Xcodeでしかできないこと

ぶっちゃけ数え切れないほどたくさんあります

まずターミナルでなくリッチなmacOSアプリであり、Appleが開発しているのでUI/UXも優れています。

補完が強力

おそらくLSPのプロトコルを越えて補完機能を提供しており、非常に強力です。

定義したばかりの変数も補完に表示されます。これは本ビルドではない小さいビルドが常に細かく走っていると思われます。

▲Xcodeで補完を表示しているところ

ログがリッチ

Xcode 15からですが、ログが非常にリッチです。レベルごとに色分けされ、出力元のコードまで一瞬でジャンプできます。

▲Xcodeでログを表示しているところ

ここまで書いて、頑張ればNeovimでもできそうだと思いました。 私にサッとプラグインを作る力があれば作っていたところでした。

ちなみにiOSアプリ上でもログを表示していますが、以下のライブラリを使えばたったの1行で実装できます。

スターお待ちしています。

github.com

おわりに

Neovimはカスタマイズ性に優れ、自分好みのUIにできるところが気に入っています。Luaで気持ちよくカスタマイズできるのも楽しいです。Neovimの設定を書くためにNeovimを使っているといっても過言ではありません。

Neovim×iOSアプリ開発はまだ行っている人が少なく、マジで日本に私しかいないんじゃないかレベルでいないです。そういう私もまだゴリゴリNeovimでSwiftを書いていないのが正直なところです。世界を見渡してもかなり少ないです。

つまり未開拓の領域です。そう聞くとワクワクしませんか?

これを機に一緒に沼へハマりましょう!