トップ 最新 追記 RSS feed

継続にっき

2004|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|03|05|06|08|09|10|12|
2007|01|02|03|05|07|12|
2008|10|
2009|01|05|12|
2010|04|05|11|
2011|01|09|12|
2012|02|03|05|09|12|
2013|02|03|
2014|05|09|
2015|12|

2010-11-06 (Sat)

))) scala-mode.elのインデントの挙動を改善する

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まとめ(1)

ついでに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
         │   └── ...
         └── ...

.emacs

他スクリプトのロードを行うだけなので非常にシンプル。 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")

.emacs.d/*.el

isearch

isearch後のカーソル位置を常にキーワードの前方にします。

(add-hook 'isearch-mode-end-hook
          (lambda ()
            (if (and (eq last-input-char ?\C-m) isearch-forward)
                (goto-char isearch-other-end))))
session

特定のファイル名を持つファイルはポイントを保存しないようにします。 (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)

スクリーンショットの様な感じになります。

anything
anything-mode-specific

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向けに末尾のような設定をしておくと、

  1. 適当にコード参照。
  2. 関数定義にジャンプしたい or リファレンスを参照したいキーワードが見つかる。
  3. キーワードの上でC-u C-x C-b。
  4. 前置引数付きで実行するとカーソル位置の単語で絞り込まれた状態でリストが開くので、そのままアクション。

といった操作ができるようになります。

(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)))
anything-c-source-comint-history

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)))

その他

  • ido
  • ruby-modeのオートインデント
  • VMwareホストとのkill-ringの同期
  • 窓使いの憂鬱(YAMY)を使ったエスケープシーケンスの送信

あたりの話題がまだあるけれど、長くなってきたのでいったんここまで。


2004|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|03|05|06|08|09|10|12|
2007|01|02|03|05|07|12|
2008|10|
2009|01|05|12|
2010|04|05|11|
2011|01|09|12|
2012|02|03|05|09|12|
2013|02|03|
2014|05|09|
2015|12|
トップ 最新 追記 RSS feed