2012年11月16日金曜日

Scala Tips / Emacs

ScalaプログラミングはなんといってもEmacs+Ensimeですね!

先週サブノート目的でMacBook Air 11inchを入手したのですが、Emacs+Ensimeで満ち足りてしまって、まだEclipseは入れていない状況です。

Emacsのどこがよいかというと、まずテキストエディタとしての基本機能、シェルモードやディレクトリモードといったシェル機能が充実している点が挙げられますが、なんといってもelispで比較的簡単にカスタマイズができるのがよいですね。

カッコの捌き方

Scalaプログラミングをする時の生産性に影響があるのが「{」「}」の捌き方です。たとえば:

といれると、自動的に括弧を開いてくれてカーソルを所定の位置に持って行ってくれると便利です。

  1. abc {  
  2.   ←カーソル  
  3. }  

もちろん、これぐらいの自動化はどのエディタにもついていると思いますが、問題なのは「abc { }」と打った時に自動的・強制的に上の形になってしまうと、逆に「abc { x => x + 1 }」と書きたかった時に手戻りが発生してしまいます。

このような問題があるため、キーの入力で自動的に上記のような整形をする機能(Emacsのscala-modeではscala-mode-feature-electric)は案外使いづらく、ボクもたいてい切ってしまいます。

  1. abc {  
  2.   ←カーソル  
  3. }  

にしたい時と

  1. abc { x => x + 1 }  

にしたい時のどちらにも対応できる入力方法が欲しいところです。

カスタマイズ

この問題に対処するために、以下のelispの関数を作ってみました。

  1. (defun my-scala-newline(arg)  
  2.   (interactive "p")  
  3.   (cond ((scala-in-multi-line-comment-p)  
  4.   (scala-newline))  
  5.  ((char-equal ?\} (following-char))  
  6.   (let (killed)  
  7.            (newline-and-indent)  
  8.            (newline-and-indent)  
  9.            (forward-char)  
  10.     (setq killed (not (my-end-of-line-p)))  
  11.     (if killed (kill-line))  
  12.            (previous-line)  
  13.            (indent-for-tab-command)  
  14.     (if killed (yank))))  
  15.  (t  
  16.   (newline-and-indent))))  

.emacsまたはinit.elへの設定は以下になります。

  1. (require 'scala-mode-feature-electric)  
  2.   
  3. (setq scala-mode-feature:electric-expand-delimiters-list '(?\{))  
  4.   
  5. (add-hook 'scala-mode-hook  
  6.           (function (lambda ()  
  7.         (scala-mode-feature-electric-mode)  
  8.           (define-key scala-mode-map "\r" 'my-scala-newline)  

まずscala-mode-feature:electric-expand-delimiters-listで「{」のみを有効にするように設定しています。こうすることによって:

と打つと自動的に以下のようになります。

  1. abc { }←カーソル  

ここからの動きがポイントですが、先程のmy-scala-newline関数がReturnに設定されていると、この場所でReturnを押すことで、以下の形に整形されカーソルも所定の位置に移動します。

  1. abc {  
  2.   ←カーソル  
  3. }  

カーソルの位置が他の場所の場合、通常の改行キーの動作をするので、不必要な整形が行われません。「abc { x => x + 1 }」と書きたい時はそのまま入力をしていけばよいわけですね。

括弧を追加する場合の捌き方

my-scala-newline関数は、よく出てくるコーディングパターンをサポートするためにもう一工夫しています。

以下のように一行に書いていた文を:

  1. abc xyz  

括弧を入れて複数行に分割したい時がよくあります。

  1. abc {  
  2.   xyz  
  3. }  

まず、最初の状態で「abc 」の場所で「{」を打つと以下のようになります。カーソルは「}」の上になります。

  1. abc { }xyz  

ここでReturnを押下すると、「}」の後ろのxyzが自動的に括弧内に移動し、カーソルも所定の位置に移動します。

  1. abc {  
  2.   xyz←カーソル  
  3. }  

簡単なカスタマイズですが、なかなか効果抜群です。

0 件のコメント:

コメントを投稿