emacsでmatlab

今後の人生においてmatlabを使うのは多分あと数カ月だけだと思いますが、
逆にいうと数カ月はmatlabを使わなければならないのでemacsから便利に使えるように頑張ってみました。

環境はubuntu 9.04 64bit + matlab 2009aです。

1. 導入
http://redgecko.jp/d/?date=20070328
基本的にここのサイトの通りやれば大体いい感じに使えるようになります。
具体的には、mlintによるエラーチェックやインデントとかmatlabシェルの呼び出しとかです。

ただし、若干情報が古いので現在の僕の設定を晒しておきます。

(autoload 'matlab-mode "matlab" "Enter MATLAB mode." t)
(autoload 'matlab-shell "matlab" "Interactive MATLAB mode." t)
(setq auto-mode-alist (cons '("\\.m\\'" . matlab-mode) auto-mode-alist))

;; auto-complete-modeの自動起動
(add-to-list 'ac-modes 'matlab-mode)

(setq matlab-shell-command "/usr/local/bin/matlab"  
      matlab-shell-command-swithes '("-nodesktop -v=glnxa64")  
      matlab-indent-level 2  
      matlab-indent-function-body nil  
      matlab-highlight-cross-function-variables t  
      matlab-return-add-semicolon t  
      matlab-show-mlint-warnings t  
      mlint-programs '("/usr/local/matlab2009a/bin/glnxa64/mlint")  
      matlab-mode-install-path (list (expand-file-name "~/matlab/"))  
      )  
(autoload 'mlint-minor-mode "mlint" nil t)  
(add-hook 'matlab-mode-hook (lambda () (mlint-minor-mode 1)))  
(add-hook 'matlab-shell-mode-hook 'ansi-color-for-comint-mode-on)  
(add-hook 'matlab-shell-mode-hook  
	  (lambda () (setenv "LANG" "C")))  
(eval-after-load "shell"  
  '(define-key shell-mode-map [down] 'comint-next-matching-input-from-input))  
(eval-after-load "shell"  
  '(define-key shell-mode-map [up] 'comint-previous-matching-input-from-input)) 


これでとりあえずはemacsからmatlabが使えると思います。

2. hideshow.elでコードの折りたたみ
先日pythonで導入したhideshow.elが便利だったのでmatlabでも使えるようにします。

(load-library "hideshow")
(add-hook 'matlab-mode-hook 'hideshowvis-enable)

(add-to-list 'hs-special-modes-alist 
	      '(matlab-mode 
		"if\\|switch\\|case\\|otherwise\\|while\\|for\\|try\\|catch" "end" 
		nil (lambda (arg) (matlab-forward-sexp)) nil))

これでうまいこと折りたたんでくれると思います。

3. yasnippetで入力支援
http://www.mediafire.com/?2on0q0vfucd24ll
適当ですがsnippetのパターンを作ったので解凍してsnippetsフォルダにぶちこんでください

4. auto-completeで入力支援
for文とか関数定義とかのパターンはyasnippetからできますが、matlab.elに入力補完用の関数があります。

そこそこいい感じに補完してくれるのですが、僕はauto-complete.elに慣れきってしまっているのでできればこっちから補完したいのです。

matlab.elの補完関数はM-TAB連打で候補を次々変えていくというパターンで、候補リストは直接は渡してくれないっぽいのでその関数を適当に手直ししてその候補リストを渡してくれる関数を新たに作って、そのリストとyasnippetのリストを使ってauto-completeを使おうという作戦です。

(defface ac-matlab-candidate-face
  '((t (:background "PaleGreen" :foreground "black")))
  "Face for matlab candidate."
  :group 'auto-complete)

(defface ac-matlab-selection-face
  '((t (:background "DarkGreen" :foreground "white")))
  "Face for matlab selected candidate."
  :group 'auto-complete)


(defun matlab-complete-symbol-list (&optional arg)

  (interactive "P")
  ;(matlab-navigation-syntax
    (let* ((prefix (if (and (not (eq last-command 'matlab-complete-symbol))
			    (member (preceding-char) '(?  ?\t ?\n ?, ?\( ?\[ ?\')))
		       ""
		     (buffer-substring-no-properties
		      (save-excursion (forward-word -1) (point))
		      (point))))
	   (sem (matlab-lattr-semantics prefix)))
      (if (not (eq last-command 'matlab-complete-symbol))
	  (setq matlab-last-prefix prefix
		matlab-last-semantic sem
		matlab-completion-search-state
		(cond ((eq sem 'solo)
		       '(matlab-solo-completions
			 matlab-find-user-functions
			 matlab-find-recent-variable))
		      ((eq sem 'boolean)
		       '(matlab-find-recent-variable
			 matlab-boolean-completions
			 matlab-find-user-functions
			 matlab-value-completions))
		      ((eq sem 'value)
		       '(matlab-find-recent-variable
			 matlab-find-user-functions
			 matlab-value-completions
			 matlab-boolean-completions))
		      ((eq sem 'property)
		       '(matlab-property-completions
			 matlab-find-user-functions
			 matlab-find-recent-variable
			 matlab-value-completions))
		      (t '(matlab-find-recent-variable
			   matlab-find-user-functions
			   matlab-value-completions
			   matlab-boolean-completions)))))

      (let ((allsyms (apply 'append
			    (mapcar (lambda (f) (funcall f prefix))
				    matlab-completion-search-state))))
	(matlab-uniquafy-list allsyms))))


(defvar ac-source-matlab
  '((candidates
     . (lambda ()
	 (matlab-complete-symbol-list)))
    (candidate-face . ac-matlab-candidate-face)
    (selection-face . ac-matlab-selection-face)
))

(add-hook 'matlab-mode-hook
	  (lambda ()
	    (add-to-list 'ac-sources 'ac-source-matlab)
	    (add-to-list 'ac-sources 'ac-source-yasnippet)))

5. anythingでヘルプを引く

まだやってないっす…


ということで、100%ではありませんが、わりかしいい感じに使えるようになったと思います。
matlab使わなきゃなんないけどEmacsから離れたくないっていう人の力に少しでもなれれば幸いです。
一応SSも載せときます。

基本的にEmacsLispはあんまりわからないのでコピペとトライアンドエラーの果てに、とりあえず動けばよしといった感じなので無駄なことや変なことをしてると思います。

もっといいやり方があったら教えてください。