Pages

2013年10月11日金曜日

EmacsでのScala用の設定を公開してみる

Emacs上でのScala関係の設定がたまってきたので公開してみる。
いい設定があったらおしえてください。他にもこの辺りが参考になるかもしれません。

eMacsでscaLaを書く準備
EmacsでつくるScala開発環境 後編(ENSIME)

設定

scala-mode2利用している。

(require 'scala-mode2)
(add-to-list 'auto-mode-alist
'("\\.\\(scala\\|sbt\\)\\'" . scala-mode))

個人的な設定,,,日本語キーボードだけどmayu(窓使いの憂鬱)で英語配列にしているのでコロンがシフトを押さないといけないため入れかえる。Rubyとかのほとんどセミコロンを使わない言語で利用してもいいかも

;; Reverse ; and :
(let ((map scala-mode-map))
(define-key map (kbd ";") (lambda () (interactive) (insert ":")))
(define-key map (kbd ":") (lambda () (interactive) (insert ";"))))

Buffer上のコードを実行するのに関数をつくった。
apt-get install scalaでscalaコマンドの-eオプションを使えるのが条件
あとpopwinも必要。さりげにRubyとPerlにも対応している。

(require 'popwin)
(defun my/execute-from-current-file (&optional statement)
"Execute current buffer's program."
(interactive)
(lexical-let*
((original-buffer (current-buffer))
(code (shell-quote-argument (or statement (buffer-string))))
(program (case major-mode
(ruby-mode "ruby -e ")
(cperl-mode "perl -e ")
(scala-mode "scala -e ")))
(command (concat program code))
(buffer (get-buffer-create "*execute program*")))
(save-current-buffer
(popwin:popup-buffer
buffer :stick t :width (/ (frame-width) 2) :position :right)
(erase-buffer))
(start-process
"emacs-program" buffer "/bin/sh" "-c" command)
(switch-to-buffer-other-window original-buffer)))

(define-key scala-mode-map (kbd "C-c C-c") 'my/execute-from-current-file)

自動的にクラス名とか型名の最初の一文字を大文字にする。

;; Capitalize type word automatically
(defun my/scala-capitalize-auto ()
(when (equal major-mode 'scala-mode)
(lexical-let*
((current-face (nth 1 (text-properties-at (1- (point)))))
(type-face-p
(lambda () (equal font-lock-type-face current-face)))
(anonymous-func-type-p
(lambda ()
(and
(string-match "^ ?+def " (thing-at-point 'line))
(equal "=" (char-to-string (char-before (- (point) 3))))
(equal ">" (char-to-string (char-before (- (point) 2)))))))
(bracket-p
(lambda ()
(and (string-match "\\[" (char-to-string (char-before (1- (point)))))
(string-match "]" (char-to-string (char-after (point))))))))
(when (and (not (bobp))
(not (equal font-lock-string-face current-face))
(or (funcall type-face-p)
(and (not (equal font-lock-constant-face current-face))
(or (funcall anonymous-func-type-p)
(funcall bracket-p)))))
(let ((case-fold-search nil))
(unless (string-match "[A-Z]" (word-at-point))
(capitalize-word -1)))))))

(defadvice self-insert-command
(around ad-capitalize-type-word-in-scala activate)
ad-do-it
(my/scala-capitalize-auto))

multi-term上でのsbtの以下の挙動を修正する。

  • C-hで文字がきえない
  • C-aで行の頭に戻れない

パッケージにしたので、el-getとかで適当にダウンロードしてください。

cd somewhere
git clone https://github.com/yuutayamada/sbtp.git

sbtp-prompt-string変数はsbtコマンドを実行したあとの"> "とかの文字を
設定してください。(デフォルトで"> "なので 変更してなければ必要ありません)
2013/10/05 追記:
起動が遅いのでsbtのconsoleから利用するようにしました。
コマンドを実行するとEmacsのstart-processでsbt consoleを起動します。
起動後sbtp-console-sendでミニバッファから入力またはリージョン選択して
いればそのリージョンを実行します。
sbt-console-send-lineコマンドはその行を評価します。print文を使わなくても
res1: ~~ とかなんとかでて評価されるます。
sbtp-lang変数はデフォルトではLANG変数が設定されます。
もし日本語の表示がおかしい場合は設定するとなおるかもしれません。
C-uを押してから各sbt-consoleコマンドを実行すると、 :reset をしてからコ
マンドを実行します。
(ensimeでもC-c C-v sでensime-sbt-switchというコマンドがありますが、これ
はensime必須なので)

(require 'sbtp)
(setq sbtp-prompt-string "> "
sbtp-lang "ja_JP.UTF-8")
(define-key term-raw-map (kbd "C-a") 'sbtp-begging-of-line)
(define-key scala-mode-map (kbd "C-c C-p") 'sbtp-console-send)
(define-key scala-mode-map (kbd "C-c C-l") 'sbtp-console-send-line)

ensime 関係:

.ensime があったら自動でコネクトする

(require ensime)
(setq ensime-auto-connect 'always)
(add-hook 'scala-mode-hook '(lambda ()
(when (my/file-exists-p ".ensime")
(ensime-scala-mode-hook))))

(defun my/file-exists-p (file)
"Search file recursively until home directory"
(let* ((filename (concat "./" file))
(home "~/")
(home-p (lambda (dir1 filename)
(equal
(expand-file-name dir1)
(expand-file-name
(file-name-directory filename))))))
(while (not (or (file-exists-p filename)
(funcall home-p home filename)))
(setq filename (concat "../" filename)))
(when (file-exists-p filename)
(expand-file-name filename))))

Error箇所にジャンプする。popup packageが必要です

(eval-when-compile (require 'cl))
(require 'ensime)
(require 'popup)

(defvar my/ensime-current-error-number 0
"A number already searched error")

(defun my/ensime-goto-next-error ()
(interactive)
(when (equal major-mode 'scala-mode)
(lexical-let*
((errors (ensime-all-notes))
(convert-error-format
(lambda (err)
(loop for i from 0 to (length err) by 2
for key = (nth i err)
for value = (nth (1+ i) err)
if (< i (1- (length err)))
collect (cons key value))))
(converted-err-list
(loop for error in errors
for formatted-error = (funcall convert-error-format error)
if (equal buffer-file-name (assoc-default :file formatted-error))
collect formatted-error))
(move
(lambda (err-list)
(let* ((err (nth my/ensime-current-error-number err-list))
(err-point (1+ (assoc-default :beg err))))
(goto-char err-point)
(popup-tip (assoc-default :msg err)
:point err-point))))
(save-err-point
(lambda ()
(setq-local my/ensime-current-error-number
(if (equal my/ensime-current-error-number
(1- (length converted-err-list)))
0
(1+ my/ensime-current-error-number))))))
(when converted-err-list
(funcall move converted-err-list)
(funcall save-err-point)))))

終わり

Scalaのコード書くのにIntelliJとかIDEのほうがよさそうだけど、Emacsしか
使うきがないので仲間を増やすために設定を公開してみました。
何かナウい設定があったらおしえてください。


0 件のコメント:

コメントを投稿