発端
発端という程のことは何もないんですが、Emacs のプラグインが肥大化するに伴なって、食い合せが悪くて変な挙動をしたり、バージョンを上げたらパッケージが動かなくなったり……といったことにいい加減辟易してきました。 最近はよくわらないタイミングでビジーになったり死んでしまうことも多くなってきたので、いっそモダンなエディタに乗り換えよう、という機運でした。
そんな中で VSCode (Visual Studio Code) を選んだのは、何か最近話題になっていたからというのと、Atom があんまり手に合わない印象があったから、あと TL で VSCode 使ってる人が多かったからという感じで、まあ特に理由はないです。
要件
とはいえ、Emacs ではかなりカスタマイズを進めていたので、VSCode に移行するに当っては以下の要件が満たされて欲しい、という思いがあります。
マトモな Haskell 統合環境
Emacs ではここ数年はずっと intero を使っていた。 intero の補完・警告システムはかなり良かったので、完全互換ではないにせよ、十分伍するものが欲しい。
そもそも今回乗り換えようと思ったのは、intero が最近あまりメンテされていない感じで、REPL で IO の結果を表示しようとすると Hang するとか、型の重いプログラムを書いていると、REPL で補完を働かせようとしてビジーになるとか、そういうことが続いたからでもあった。
コードスニペットデータの移行
- 僕はコードスニペットを多用してコーディングをしているので、これまでのスニペットが移行出来ないと死ぬ。
- スニペットエンジンは Yasnippet
を使っていて、たとえば
module
宣言の補完とかは 内部で ELisp を使ってpiyo/Hoge/Fuga/Bar.hs
ならmodule Hoge.Fuga.Bar where...
、 小文字のファイル名moke.hs
とかならmodule Main where
となるようにしていたので、こういうことが出来ると嬉しい。
Rust と Scala の統合環境
- 最近使ってみているので、快適なのが欲しい。
YaTeX の代替になるやつ
2018/11/12 追記:幾つか組み合わせつつ、自前で拡張を書いて解決した。
永らく LaTeX の執筆環境では YaTeX-mode を利用してきた。
特に、YaTeX にはイメージ補完というのがあって、アスキーで表現された数学記号のイメージに相当する記号を手軽に入力出来る。 例えば ;||- で (\Vdash
)、;ox で (\otimes
)、あるいは :a で (\alpha
)、:ph- で (\varphi
) といった具合に。僕はもうこれがなければ数式が打てないレベルまで来ているので、この機能の代替が欲しい。 前 Atom に乗り換えようとした際にも、Atom 向けのイメージ補完機構を作ってみていたのだが、途中で飽きて放り投げてある。VSCode の方がAPIが整理されていて、遥かに書き易かった。
Tramp による SSH 越しに sudo やったりするやつ
現状
上記の要件に対して、どの程度まで移行出来ているか、以下で順次書いていくことにする。
Haskell 環境
この構築に一番手間取った。検索してヒットするのはだいたい以下の三つだろう:
- Haskell Language Server
haskell-ide-engine
ベース。 裏でintero
,ghc-mod
,brittany
,hoogle
,HaRe
などを呼び出すことになっている。
- Haskero
- Haskelly
- どちらも
intero
ベース。
- どちらも
最終的には haskell-ide-engine
に収斂していくべきだと思っているので、Haskell Language Server
をまず入れてみたのがだ、結論から言うと全然動かなかった。 一応
hie-wrapper
をめぼしい GHC
バージョンごとにビルドしてインストールはしてあったのだが、モジュールの補完は利かないし、マウスオーバーで表示されるはずのドキュメントがいつまで経っても出てこないし、warning
や error
の報告も全然表示されないしで、検索するとヒットするような対応はだいたい試してみたつもりだが、ロクに動かなかった。
次いで Haskelly。これは調べた感じ Warning や error の表示がないみたいなので割愛。
最後に Haskero。これもなかなかマウスオーバーでドキュメント表示が上手くいかなかった。 これはローカルの DB だけあればいいだろうと思っていたら、どうも global な DB も必要だったらしい。 なので、以下を実行すればマウスオーバーは出来るようになる:
$ hoogle generate
$ cd path/to/project
$ stack haddock --keep-going
$ stack hoogle generate
多分最後の三行はローカルの DB 要らねと思ったら実行する必要はない。 実にはこの工程を試したあとに Haskell Language Server のマウスオーバーも試していて、その上でタイムアウトしている。
これで Haskero のマウスオーバーは出来るようになったが、警告やエラーが一向に表示されない。 調べてみると、次の issue が見付かった。
ここで書かれている対処法を参考に、インストールの Haskero
を書き換える形で一時的に解決している。 なんでも :l
した後に
:r
をするのが不味いらしい。
具体的には、$HOME/.vscode/extensions/vans.haskero-1.3.1/server/intero/commands/reload.js
の ReloadRequest
クラスの
send
メソッドを以下のように書き換える:
send(interoProxy) {
const filePath = uriUtils_1.UriUtils.toFilePath(this.uri);
const escapedFilePath = interoUtils_1.InteroUtils.escapeFilePath(filePath);
const load = `:l ${escapedFilePath}`;
// const reloadRequest = ':r';
return interoProxy.sendRawRequest(load)
/*
.then(response => {
return interoProxy.sendRawRequest(reloadRequest);
})
*/
.then((response) => {
return Promise.resolve(new ReloadResponse(response.rawout, response.rawerr));
;
}) }
すると、開いた直後は掻き消えることがあるが、一応問題なく動ようになった。
Haskero には REPL はなさそうだったので、GHCi
Helper を入れた。 REPL としての intero
は、-fdefer-type-errors
が掛かっていたり、無駄に補完しようとしてビジーになったり、正直腐り切っていたので、stack ghci
を使う GHCi Helper は性に合っていそうである。
あと、コードフォーマッタは Haskero は brittany
を推奨しているようだが、僕は stylish-haskell
を使っているので、stylish-haskell
用機能拡張を入れた。 HLint も使いたいので、hlint
機能拡張も入れた。haskell-linter
とかいうのもあるが、apply-refact
を使った自動反映に対応しているっぽかったので、hlint
の方を選んだ。
他にも Haskero の warning や error を同様に適用してくれる奴として、
Haskutil
も入れた。
以上で、完全ではないがあるていどこれまでの Haskell
統合環境に近いものが構築出来た。
さらに、オマケとして、Haskell 編集中だけ Haskell 用リガチャフォントの
Hasklig
を使うようにするため、以下の設定を settings.json
に追加した:
{ ...,
"[haskell]": {
"editor.fontFamily": "Hasklig,Menlo, Monaco, 'Courier New', monospace"
}
}
コードスニペットの移行
検索すると幾つか変換器がヒットするが、どう対応しているのかわからなかったので、Rust を使って変換器を書いた。
Rust のパーザコンビネータである combine
crate
の良い練習になった。 Yasnippet では選択肢から選ぶという場合はそれ専用の
ELisp 関数を呼び出しやる必要があったのだが、VSCode
では専用の構文が用意されており、 ${1|foo,bar,buz|}
とすればよく大変楽だった。
取り敢えず、可能な限り選択肢からの変換やプレースホルダの変換の面倒を見つつ、内部で任意コードを呼びだしているっぽいスニペットが来たら、標準出力で警告をするようにしている。 使い方としては、
$ mkdir -p path/to/output
$ crates ~/.emacs/share/snippets path/to/output
とすれば、言語ごとに haskell.json
のような形でまとめられたスニペット定義が出来上がるので、上の警告を参考に書き換えつつ、macOS
なら $HOME/Library/Application Support/Code/User/snippets
にでも置けばよい。 ところで、如何に天下の Microsoft
だからといって、サポートファイルの識別名を Code
にするのはいかがなものか。 というか、なんで $HOME/.vscode
にしないのか全く理解出来ない。
一方で、任意のコードが実行出来るわけではないので、上の要件に上げたモジュール名補完は今のところ有効打が見付かっていない。
一応、正規表現で一回だけ置換したり大文字小文字を弄ったり、空かどうかで分岐したり、といった機構が
VSCode にもあるにはある。
だが、調べた感じ複数回置換は出来なさそうだし、そもそも正規表のキャプチャグループとスニペットのタブストップへの参照がどちらも
$1, $2, ...
という形でごっちゃになっている上に、変数の正規表現置換と空文字列の条件分岐を組み合わせようとすると一瞬で変な挙動をするので、今のところ実現出来ていない、という感じである。
何か良い手を思い付いた方は御一報下さい。いっそのこと機能拡張を作って、動的にスニペットを生成して補完候補として呼び出させるのも一つの手かもしれないが……。
Rust と Scala
- Rust
-
Rusty Code と Rust (
rls
) を入れたら万事 OK。 - Scala
-
Scala Language Server、Scala (
sbt
) あたりを入れたら動いて見える。
YaTeX の代替
残念ながらまだ見付かってないです。良い奴教えてください。最低要件は上で書いたイメージ補完が使えることです。
だいぶ楽になった。詳細は新記事を参照。
Emacs の TRAMP 相当
Emacs には tramp-mode というのがあって、SSH
越しにリモートファイルを編集したり、更にリモートで sudo
越しに保護されたファイル(サーバの config
とか)を編集したりということができた。 VSCode
では何を使えばいいんだろう。
当面の間はSSH
FS for VSCodeを使うことにした1。 TRAMP は /.ssh/config
を自動で読み出してくれるが、SSH FS
では自分で設定を書く必要があるようだ。 この
issueによれば、現行の 1.10.0 でも "sftpCommand": "sudo /usr/lib/openssh/sftp-server"
とか指定すれば、リモートで sudo
打てる筈なのだが、どうも上手く接続出来ないのでどうしたものか。
あと、ワークスペースとしてマウントする奴なので、ちょっと一つのファイルだけ開きたい時はオーバーキルのような気もする。
所でどうでもいいけど、SSH FS って言うと FUSE の SSH マウント出来るやつと紛らわしいな。↩︎