読者です 読者をやめる 読者になる 読者になる

あそびたい

こころにうつりゆくよしなしごとを

Emacs+sbt+ensimeでScalaの環境を整えた話

今期の実験でScalaを使おうと思い、まず手始めに環境を整えたので、はまったポイントをまとめようかと。
環境は、

です。

コンパイラを入れよう

Scalaのビルドツールとしてメジャーなものの1つであるsbtをインストールします。
幸いbrewに登録されているので、

brew install sbt
sbt

でインストールできます。が、めちゃめちゃ時間がかかります。
最初にライブラリとか落としてくるからっぽいです。

Emacsの環境を整えよう

Scalaのモードはデフォルトでは入っていない(?)ようなので、入れます。
M-x list-packages で scala-mode を入れましょう。

ググるscala-mode2とか出てきますが、つい最近scala-modeに変わったっぽいです。ややこしい。

IDEを入れよう

ScalaIDEとしてensimeなるものがあり、これがsbtとEmacsに対応しているとのことだったので導入しましょう。

まずはsbt側から

~/.sbt/0.13/plugins/plugins.sbtを作成し、そこに

if (sys.props("java.version").startsWith("1.6"))
  addSbtPlugin("org.ensime" % "sbt-ensime" % "1.0.0")
else
  addSbtPlugin("org.ensime" % "sbt-ensime" % "1.9.1")

を書き足します。以上です。

次にEmacs側を

毎度おなじみM-x list-packages でensimeを入れます。

これだけで一応連携自体はできるのですが、どうせやったらIDEらしく
.を入力したらauto-completeが起動したりとか
カーソルを合わせたところの型がみれたりとか
できたらいいなあと思ったので探してみたら、やってらっしゃる方
がいらっしゃったので、コードをコピペしたものの、バージョンの壁に阻まれ、若干妥協することになりました……

最終的なinit.elは以下の通りになりました。

;; ;; Scala-mode *****************************************************************
(require 'scala-mode)

;;; Use auto-complete for ensime
(setq ensime-completion-style 'auto-complete)

(defun scala/enable-eldoc ()
  "Show error message or type name at point by Eldoc."
  (setq-local eldoc-documentation-function
              #'(lambda ()
                  (when (ensime-connected-p)
                    (let ((err (ensime-print-errors-at-point))) err))))
  (eldoc-mode +1))

(defun scala/completing-dot-company ()
  (cond (company-backend
         (company-complete-selection)
         (scala/completing-dot))
        (t
         (insert ".")
         (company-complete))))

(defun scala/completing-dot-ac ()
  (insert ".")
  (ac-trigger-key-command t))


;; look type at point by C-t
(bind-key "C-t" `ensime-type-at-point scala-mode-map)

;; Interactive commands

(defun scala/completing-dot ()
  "Insert a period and show company completions."
  (interactive "*")
  (eval-and-compile (require 'ensime))
  (eval-and-compile (require 's))
  (when (s-matches? (rx (+ (not space)))
                    (buffer-substring (line-beginning-position) (point)))
    (delete-horizontal-space t))
  (cond ((not (and (ensime-connected-p) ensime-completion-style))
         (insert "."))
        ((eq ensime-completion-style 'company)
         (scala/completing-dot-company))
        ((eq ensime-completion-style 'auto-complete)
         (scala/completing-dot-ac))))

;; Initialization
(setq ensime-startup-snapshot-notification nil)

(add-hook 'ensime-mode-hook #'scala/enable-eldoc)
(add-hook 'scala-mode-hook 'ensime-scala-mode-hook)
(add-hook 'scala-mode-hook 'flycheck-mode)

動かしてみよう!

test.scalaを作って意気揚々とM-x ensime としたところ……

byte-code: check that sbt is on your PATH and see the Troubleshooting Guide for further steps http://ensime.org/editors/emacs/troubleshooting/ [(wrong-type-argument stringp nil)]

なんかつらそうなエラーが出てきました……

とりあえず必死になって英語のドキュメントを読んだところ、.ensimeとかいうファイルがないとダメだそうで、それ自体はsbtを使って作れるそうなので作ってみます

sbt ensimeConfig

で、再度M-x ensimeとすると……

ENSIME ready. Let the hacking commence!

成功です!
なんかいい感じに下線引いてくれたり型を出してくれたりするようになりました。

まとめ

多分こんな流れだったとは思うのですが、なにぶん環境が完成してから書き始めたため、他に詰まったところがなかっただろうか……という感じです。
あと、デバッガはうまく連携できなかったので、できた方がいらっしゃったら教えて下さい。

ではではっ