Scalaを書く環境をxyzzy(scala-mode.l)からEmacs(scala-mode.el)に移してみたんだけど、インデントの挙動がどうも気になる。
// 期待するもの(scala-mode.l) a.b { c => d.e { f => g } h } // 実際のもの(scala-mode.el) a.b { c => d.e { f => g } h }
というわけで、scala-mode.lから修正用コード(とscala-newline-and-indentも)を逆輸入してみた。
(defadvice scala-block-indentation (around improve-indentation-after-brace activate) (if (eq (char-before) ?\{) (setq ad-return-value (+ (current-indentation) scala-mode-indent:step)) ad-do-it)) (defun scala-newline-and-indent () (interactive) (delete-horizontal-space) (let ((last-command nil)) (newline-and-indent)) (when (scala-in-multi-line-comment-p) (insert "* "))) (add-hook 'scala-mode-hook (lambda () (define-key scala-mode-map (kbd "RET") 'scala-newline-and-indent)))
これ以外にも
val a = (b) c
とか、
for (a <- b) yield a
とか、うまく行かないケースがいろいろ残っているので出来れば何とかしたいところ。
ついでにEmacsのカスタマイズネタをいくつか公開してみます。
.emacsには.emacs.d以下のスクリプトをロードするコードだけを書いておき実際の設定は.emacs.d/*.elに書く感じです。 外部ライブラリは基本的に.emacs.d/site-lisp直下に置き、anythingのように複数ファイルに分かれているものはさらにディレクトリを分けています。
~/ ├── .emacs └── .emacs.d ├── 00init.el ├── 05bindings.el ├── 10anything.el ├── 20windows.el ├── 30dired.el ├── 30gdb.el ├── 30git.el ├── 30shell.el ├── 50c.el ├── 50lisp.el ├── 50ruby.el ├── 50scala.el ├── 50scheme.el └── site-lisp ├── anything │ └── ... └── ...
他スクリプトのロードを行うだけなので非常にシンプル。 normal-top-level-add-subdirs-to-load-pathを使うと、いちいちディレクトリ単位でload-pathに追加する必要がなくなるので便利です。
(let ((default-directory "~/.emacs.d")) (normal-top-level-add-subdirs-to-load-path)) (debian-run-directories "~/.emacs.d")
isearch後のカーソル位置を常にキーワードの前方にします。
(add-hook 'isearch-mode-end-hook (lambda () (if (and (eq last-input-char ?\C-m) isearch-forward) (goto-char isearch-other-end))))
特定のファイル名を持つファイルはポイントを保存しないようにします。 (gitのコミットログを書くためにバッファを開いたときに前回コミット時のポイントが復元されてしまうのが嫌なので)
(require 'session) (setq history-length t) (setq session-set-file-name-exclude-regexp "/\\.overview\\|.session\\|News/\\|COMMIT_EDITMSG") (setq session-file-alist-exclude-regexp session-set-file-name-exclude-regexp) (defadvice session-store-buffer-places (around apply-session-file-alist-exclude-regexp activate) (let ((file-name (session-buffer-file-name))) (when (and file-name (not (string-match session-file-alist-exclude-regexp file-name))) ad-do-it))) (add-hook 'after-init-hook 'session-initialize)
Emacs 23になってlinum、whitespaceがデファクトスタンダードになりつつあるようなのでその流れにのっています。
行番号は右寄せして表示。
;; linum (when (require 'linum nil t) (global-linum-mode) (unless window-system ;; http://www.emacswiki.org/emacs/LineNumbers (setq linum-format (lambda (line) (propertize (format (let ((w (length (number-to-string (count-lines (point-min) (point-max)))))) (concat "%" (number-to-string w) "d ")) line) 'face 'linum)))))
タブ、改行、全角スペース、EOFを表示。 改行を表示させるようにすると、kill-lineの「末尾にスペースがあっても無視して削除」というデフォルトの挙動が気になるので、 アドバイスを使って自然な動きに変えています。
;; whitespace (when (require 'whitespace nil t) ;; see whitespace.el for more details (setq whitespace-style '(tabs tab-mark newline newline-mark spaces space-mark)) (setq whitespace-display-mappings '((space-mark ?\u3000 [?\u25a1]) (newline-mark ?\n [?\u21B5 ?\n] [?$ ?\n]) ;; WARNING: the mapping below has a problem. ;; When a TAB occupies exactly one column, it will display the ;; character ?\xBB at that column followed by a TAB which goes to ;; the next TAB column. ;; If this is a problem for you, please, comment the line below. (tab-mark ?\t [?\xBB ?\t] [?\\ ?\t]))) (setq whitespace-space-regexp "\\(\u3000+\\)") (defvar whitespace-default-face 'whitespace-default-face) (make-face 'whitespace-default-face) (set-face-foreground 'whitespace-default-face "#5f5f00") (setq whitespace-tab 'whitespace-default-face) (setq whitespace-newline 'whitespace-default-face) (setq whitespace-space 'whitespace-default-face) (global-whitespace-mode 1)) (defadvice kill-line (around dont-treat-whitespace-as-nothing activate) (let ((show-trailing-whitespace (or show-trailing-whitespace whitespace-active-style))) ad-do-it)) ;; my-mark-eob ;; http://www.emacswiki.org/cgi-bin/wiki?HighlightEndOfBuffer (defun my-mark-eob () (let ((existing-overlays (overlays-in (point-max) (point-max))) (eob-mark (make-overlay (point-max) (point-max) nil t t)) (eob-text "[EOB]")) ;; Delete any previous EOB markers. Necessary so that they don't ;; accumulate on calls to revert-buffer. (dolist (next-overlay existing-overlays) (if (overlay-get next-overlay 'eob-overlay) (delete-overlay next-overlay))) ;; Add a new EOB marker. (put-text-property 0 (length eob-text) 'face '(foreground-color . "slate gray") eob-text) (overlay-put eob-mark 'eob-overlay t) (overlay-put eob-mark 'after-string eob-text))) (add-hook 'find-file-hook 'my-mark-eob)
スクリーンショットの様な感じになります。
obsolete扱いになったanything(anything-default)の代替としてanything-mode-specificというものを定義して使っています。
(defvar anything-c-source-mode-specific-default '(anything-c-source-buffers+ anything-c-source-recentf anything-c-source-files-in-current-dir+ anything-c-source-kill-ring )) (defvar anything-mode-specific-alist '()) (defun anything-mode-specific () (interactive) (let ((pair (assoc major-mode anything-mode-specific-alist))) (anything-at-point (if pair (append anything-c-source-mode-specific-default (cdr pair)) anything-c-source-mode-specific-default)))) (global-set-key (kbd "C-x C-b") 'anything-mode-specific)
anything-defaultは固定のsourcesしか設定できませんでしたが、anything-mode-specificでは使用頻度の高いsourcesをデフォルトとしつつ モードに応じて適切なsourceを追加で設定することが出来ます。
モードごとのsourceというのはimenuによる関数定義へのジャンプやリファレンスの参照などを想定していて、 たとえばscheme-mode向けに末尾のような設定をしておくと、
といった操作ができるようになります。
(defvar anything-c-source-info-gauche-refj '((info-index . "gauche-refj.info"))) (add-to-list 'anything-mode-specific-alist '(scheme-mode . (anything-c-source-imenu anything-c-source-info-gauche-refj)))
gud-mode(gdb), inferior-ruby-mode, scala-mode-infなどなど、 各種対話型モードにてよく使われているcomintモードによる履歴入力をanythingから行うためのものです。
(defvar anything-c-source-comint-history '((name . "Comint History") (header-name . (lambda (name) (format "%s" name))) (candidates . (lambda () (let ((ring (buffer-local-value 'comint-input-ring anything-current-buffer))) (if (ring-p ring) (ring-elements ring) '())))) (migemo) (action . insert))) (defun anything-comint-history () "Preconfigured `anything' for `comint-history'." (interactive) (anything-other-buffer 'anything-c-source-comint-history "*anything*"))
前述のanything-mode-specificと組み合わせた利用例は以下の通り。
(add-to-list 'anything-mode-specific-alist '(gud-mode . (anything-c-source-comint-history))) (add-hook 'gud-mode-hook (lambda () (setq comint-input-ring-file-name "~/.gdb_history") (setq comint-input-ring-size 10000) (setq comint-input-ignoredups t) (comint-read-input-ring t)))
あたりの話題がまだあるけれど、長くなってきたのでいったんここまで。