Spacemacsでgoplsを使おうとしたらハマった

概要

エディタとしてSpacemacsを使っている。

各種言語での開発を快適にするためにはもちろん色々と環境を整えるのであるが、goplsを導入するにあたってちょっと手こずったので覚書を残しておく。

本題の前に

Spacemacsとは

www.spacemacs.org

Emacsのdistributionの1つ。その特徴を示すものとして、リポジトリのDescriptionに以下のように書かれている。

A community-driven Emacs distribution - The best editor is neither Emacs nor Vim, it's Emacs and Vim!

つまり、EmacsVimを掛け合わせたようなエディタである。

ベースとなっているのはEmacsなので設定ファイルはEmacs Lispで書くが、キーバインドVimのそれが使え、Vimでいうモードの概念もある*1

インストールは単純で、リポジトリ~/.emacs.dに落としてくれば済む。 masterブランチよりもdevelopブランチにあるものの方が機能が豊富なので個人的にはそちらを使っている。

さて、Spacemacsでの各種言語向けのサポートはlayerという単位でまとめられており、例えばGo言語で開発する場合にはGo layerをインストールする*2。そして、そのバックエンドとしてgo-modeだけでなくLSPを使うこともできるようだったので、今回goplsを導入してみることにした*3

goplsとは

github.com

Go言語の公式Language Server。

全く知らなかったのだがLSP (Language Server Protocol) というプロトコルがあって、各種言語でのコード補完、定義元へのジャンプ、リファレンス参照などの機能を提供するのに使われる。 エディタはクライアントとして動作し、サーバーが提供するこれらの情報を受け取る。 LSPを使うことで各言語が各エディタ向けにプラグインを提供する必要はなくなり、単一のLanguage Serverの開発に注力できる...ということらしい。

以下 Langserver.org から引用。

LSP creates the opportunity to reduce the m-times-n complexity problem of providing a high level of support for any programming language in any editor, IDE, or client endpoint to a simpler m-plus-n problem.

生じた問題

さて、SpacemacsもEmacsと同様、--daemonオプションを使えばバックグラウンドで起動させておける。 OSとしてArch Linuxを使っているので、これをsystemdのユーザーサービスとして登録することで自動起動させていた。

だが、emacsclientによってSpacemacsデーモンにアクセスすると、goplsが存在しない旨のエラーが出た。 もちろんgoplsはインストール済みであり、コンソールから試した限りではパスは通っていたので、環境変数の設定に不備があることはすぐにわかった。 また、元々設定ファイルの中でexec-path-from-shellを使っており、その設定を削除した直後だったので、それが一因なのも間違いないと思われた。

しかし、FAQを見る限りではexec-path-from-shellを使わずとも環境変数は読み込めるようだったうえ、以下の記事に沿って環境変数のリロードを試しても、シェルの環境変数とSpacemacsが指す環境変数は一致しないままであった。

scrapbox.io

原因と対処

打つ手なしかと思っていたが、systemd/ユーザー - ArchWiki を眺めていたら意外な原因が判明した。 曰く、

systemd のユーザーインスタンスは .bashrc などに設定された環境変数を全く継承しません。

とのこと。 Wikiには設定方法まで載っていたので、PATHをカスタマイズしているzshenvにsystemctl --user import-pathを書き加えて問題は解消した*4

また、PATHを適切に設定したあとにもgoplsがno CheckPackageHandles for fileというエラーを発していたが、これもGOPATHが継承できていないことが原因だった*5ので同様に解決した。

終わりに

結局、問題だったのはSpacemacsでもgoplsでもなく、systemdのユニット設定だった。 Arch Wikiには足を向けて寝られない。

*1:Emacsにはメジャーモード、マイナーモードといった概念が元々存在するため、Vimでいうモードの概念はステートと呼んで区別される。

*2:リンク先のドキュメントはdevelopブランチの実装に向けたものだと思われる。

*3:ここを見た限り、本記事を公開した時点ではまだmasterブランチの実装ではlsp layerが追加できず、したがってLSPは使えない模様。

*4:もっとも、この設定は既に起動しているユーザーユニットには影響しないらしい。マシンの起動時にはsystemdのサービス起動の後にzshenvが読み込まれるようなので、初回起動の直後には環境変数が継承されず、Spacemacsデーモンを再起動しなくてはならない問題は依然として残っている。

*5:lsp-logというバッファに詳細なエラーログが出ていた