emacsの設定

友人がemacsを使い始めたというので自分のemacsの設定を公開してみるテスト。emacs-22 用の設定なので、emacs-21ではそのままでは動かないところがあるだろう。特にUTF-8対応のためのmule-ucsがemacs-21では必要だ。

基本的な使い方

-nw

基本的にscreenを上げたterminal上でしかemacsは使わない。screenのattach/detach機能を使うことで、遠隔からsshで入り、それまでの作業を継続できる。だから、いつもemacs -nw (no window)。

縦分割

最近24inchのワイド液晶を使っている。使いかたは、左三分の一に縦最大化したターミナルを一つ、残り三分の二を埋めるサイズのターミナルを一つ。大きな方のターミナルでScreenをあげて、emacs -nwしている。emacsは、"Ctrl-x 3"で二分割して使っている。実際上はターミナルが三つあるような感じ。かなり画面を広く使えていい感じ。壁紙?デスクトップ?なにそれおいしいの?

あ、もちろんメール(sylpheed)、ブラウザ用のワークスペースが別にあって、ターミナルだけで生活しているわけではないです。

移動

三行下のあの単語にカーソルを合わせたい、ということが良くある。単純にはCtrl-n を三回押して三行下に行き、Ctrl-fで移動していく。あるいはM-fで単語を飛ばすか。もちろんこれでもいいのだけれども、Ctrl-sでその単語を検索し、Enterを押せばさっくり移動できる。上に書いたようにかなり画面が広いので検索で移動した方が楽なのです。

キーバインド

Meta キー

Metaキーは、わりと多くの人がESCキーやAltキーを使っているみたいだけれども、"Ctrl-["を使っている。これだとESCに手を伸ばす必要がないので良い、と最初に読んだEmacsの本(なんだか忘れた)に書いてあったのでそのまま使い続けている。

"Ctrl-["は、キーコード的にESCと一緒なのでviでも使えたりする。

Backspace

"Ctrl-h"に割り当て。

(global-set-key "\C-h" 'delete-backward-char)

.emacs

多くのconfigを一つの.emacsに書いていくと膨れ上がってしまう。そのため、.emacs自体は基本的な設定だけに留め、多くは .emacs.d というディレクトリを掘ってそこに集めている。これで.emacs自身はすごくスリムになる。また、.emacs.d をsvnで管理しているため、新しいマシンでもすぐにemacsが使えるようになる。

また、 .emacs.d/lib にはいろいろなところから持ってきたemacs lispを放り込んである。これは、emacs lispはblogに張り付けてあることなどもあり、ports/aptで簡単にインストールできないものも多いため。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; path

(setq load-path (append (list (expand-file-name "/usr/local/share/emacs/site-lisp/") ) load-path)) ;; ディストリビューションによって変えてください。

(setq load-path (append (list (expand-file-name "~/.emacs.d/") ) load-path))
(setq load-path (append (list (expand-file-name "~/.emacs.d/lib/") ) load-path))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;   Common Setting

(global-set-key "\C-h" 'delete-backward-char)

;;; Force text mode & auto fill mode.
(setq default-mejor-mode 'text-mode)
(setq text-mode-hook 'turn-on-auto-fill)
;;; display line number
(setq line-number-mode t)
;;; shell mode の入出力用漢字コード
(set-keyboard-coding-system 'euc-japan)
;;; モードラインの設定 - 行番号と日付・曜日・時間を表示
(line-number-mode t)
(column-number-mode t)
;;; 探索した文字列を強調
(setq search-highlight t)

;;; Menuバーを消す
(menu-bar-mode 0)
(tool-bar-mode 0)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Anthy Setting

(load-library "anthy")

(register-input-method "japanese-anthy" "Japanese"
                        'anthy-leim-activate "[anthy]"
                "Anthy Kana Kanji Conversion system")
(setq default-input-method "japanese-anthy")
(setq select-input-method "japanese-anthy")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Color Settings
(load "~/.emacs.d/color.el")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; mail setting
;; mew wanderlust
(load "~/.emacs.d/mail.el")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Dictionary
;;     lookup
(load "~/.emacs.d/dic.el")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; modes
;;     ruby-mode python-mode php-mode java-mode haskell-mode
(load "~/.emacs.d/mode.el")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; WWW
;;     w3m
(load "~/.emacs.d/www.el")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; tools
(load "~/.emacs.d/tools.el")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; howm
(load "~/.emacs.d/howm-setting.el")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Howm starts automatically

(howm-menu)

使用ソフトウエア その1

ports/aptで簡単にインストールできるような有名なソフトウェアで、使っているものをリストアップしてみる。こうやってみるとあんまりないのね。

  • mew (メール)
  • wanderlust (メール。なんとなくmewと両方とも使っている)
  • howm (スケジュール管理/メモ管理)
  • lookup (辞書)
  • emacs-w3m (Web)
  • anthy-el (日本語変換)
  • migemo/cmigemo (日本語で検索)

それぞれの設定についてはここでは触れない。これらに関してはそんなに変なことはしていない、つもり。

使用ソフトウェア その2

さて、ここからが本番。

これらのコードはもはやどこから取ってきたか分からないものもある(分かるものは明記してある)。もしもおれのコードだから公開を止めて欲しいという人がいらっしゃるようでしたら、お手数ですがご連絡ください。

dmacro

増井さん謹製の自動繰り返しマクロ生成ツール。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Dynamic Macro  http://pitecan.com/DynamicMacro/

(defconst *dmacro-key* "\C-t" "繰返し指定キー")
(global-set-key *dmacro-key* 'dmacro-exec)
(autoload 'dmacro-exec "dmacro" nil t)
ミニバッファ内でC-wで単語削除
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ミニバッファ内でC-wで単語削除
(define-key minibuffer-local-completion-map "\C-w" 'backward-kill-word)
タイムスタンプを挿入する

日付と時刻入力したい時がたまにあるのでこういう関数を用意してある。日付の形式はhowmに準拠してある。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; insert timestamp

(defun insert-timestamp nil "insert timestamp"
 (interactive (insert (format  "[%s] %s " (format-time-string
 "%Y-%m-%d") (format-time-string "%H:%M:%m")))))
iswitchb (標準添付)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; インクリメンタルにバッファきりかえられる
;; C-x bでバッファ選択中に文字を入力すると絞りこめる
;; C-s, C-r でバッファの選択を切替える
;; 検索候補がないならC-x C-fでfind-fileへ移行できる

;(iswitchb-default-keybindings) ; for emacs21
(iswitchb-mode 1) ; for emacs22

(add-hook 'iswitchb-define-mode-map-hook
          'iswitchb-my-keys)

(defun iswitchb-my-keys ()
  "Add my keybindings for iswitchb."
  (define-key iswitchb-mode-map "\C-n" 'iswitchb-next-match)
  (define-key iswitchb-mode-map "\C-p" 'iswitchb-prev-match)
  (define-key iswitchb-mode-map "\C-f" 'iswitchb-next-match)
  (define-key iswitchb-mode-map " " 'iswitchb-next-match)
  (define-key iswitchb-mode-map "\C-b" 'iswitchb-prev-match)
  )

(defadvice iswitchb-exhibit
  (after
   iswitchb-exhibit-with-display-buffer
   activate)
  "選択している buffer を window に表示してみる。"
  (when (and
         (eq iswitchb-method iswitchb-default-method)
         iswitchb-matches)
    (select-window
     (get-buffer-window (cadr (buffer-list))))
    (let ((iswitchb-method 'samewindow))
      (iswitchb-visit-buffer
       (get-buffer (car iswitchb-matches))))
    (select-window (minibuffer-window))))

(defun iswitchb-possible-new-buffer (buf)
  "Possibly create and visit a new buffer called BUF."
  (interactive)
  (message (format
            "No buffer matching `%s', "
            buf))
  (sit-for 1)
  (call-interactively 'find-file buf))

(defun iswitchb-buffer (arg)
  "Switch to another buffer.

The buffer name is selected interactively by typing a substring.  The
buffer is displayed according to `iswitchb-default-method' -- the
default is to show it in the same window, unless it is already visible
in another frame.
For details of keybindings, do `\\[describe-function] iswitchb'."
  (interactive "P")
  (if arg
      (call-interactively 'switch-to-buffer)
    (setq iswitchb-method iswitchb-default-method)
    (iswitchb)))
save buffer list

開いているバッファのリストを自動的に保存しておく。起動時にload-buffer-listが評価されてバッファが復帰するので、emacsを立ち上げ直したときにほぼ同じ環境で作業を継続できる。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; save buffer list
;;  http://www.agusa.i.is.nagoya-u.ac.jp/person/sue/download/el/bufferlist/save-buffer-list.el

(load-file "~/.emacs.d/lib/save-buffer-list.el")
(run-with-idle-timer 60 t 'save-current-buffer-list)
(load-buffer-list)
括弧移動
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; %を入力すると対応する括弧に飛ぶ。括弧がなければ単に%が挿入される

(global-set-key "%" 'match-paren)

(defun match-paren (arg)
  "Go to the matching paren if on a paren; otherwise insert %."
  (interactive "p")
  (cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
        ((looking-at "\\s\)") (forward-char 1) (backward-list 1))
        (t (self-insert-command (or arg 1)))))

自作 script

save everything

emacsで書いた文章を、日付ごとのディレクトリに自動的に保存する。日付で保存するので、同じファイルを違う日に編集したら、その分だけ増えることになる。しかし、所詮テキストファイルだし、大した容量ではない。それよりも作業の変遷を記録しておく方が重要だと思う。

なぜsvnとかにしないかって?まあ、そこらへんはごにょごにょ。。。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; save everything
;;

(setq save-everything-dir "~/lines/save-everything/")

(add-hook 'after-save-hook
          (lambda ()
            (save-excursion
              (let ((oldbuf (current-buffer))) ;; oldbufをcurrent-bufferの値にバインド
              (setq filename (expand-file-name (format "%s/%s/%s" save-everything-dir (format-time-string "%Y/%m/%d")

          (file-name-nondirectory buffer-file-name))))
              (setq dir (file-name-directory filename))
              (unless
                  (file-exists-p dir)
                (make-directory dir t)
                )
              (if
                  (file-exists-p filename)
                  (delete-file filename)
                )
              (set-buffer (get-buffer-create filename)) ;; バッファ切替え
              (insert-buffer oldbuf)
              (setq start (point-min))
              (setq end (point-max))
              (write-region start end filename nil 'hoge nil)
              (kill-buffer (current-buffer))
              ))))
est-mode

このあたり(http://d.hatena.ne.jp/faw/20071012)参照。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; est-mode

(load "~/.emacs.d/lib/est-mode.el")
logger-el

M-x logger-openとすると、自動的に現在の日付入りのログファイルを開き、設定してある文字列が先頭に挿入される。Agendaとか書いておくと忘れなくて便利。リストから人名を補完する機能もつけたけどその機能は結局使ってないなぁ。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Logger.el
;
;   usage: M-x logger-open
;
; Functions
;  - 自動的に log-YY_MM_DD-hogehgoe.log
;    というファイルを作り、開く
;    ファイルを作るときに"hogehoge"部分を入力する。
;    - ファイルを開いた時、
;      logger-text-prefix
;      logger-text-suffix
;      で宣言してある文字列が自動的に挿入される。
;  - 人名補完
;     - 補完した時に、Timestampもつく
;       ex.)
;         o M-tabって打つと、
;         osamu[8:55] >
;         って補完される。
;        .logger.el
;        の中の(setq logger-group-member-alist)
;        で補完リストを作成し、登録。
;
; TODO
;  - 人名補完
;     - 複数補完候補があるときに、mini-bufferにその候補を出す
;     - 日本語人名の補完がうまく動かない
;  - groupをlogger-text-prefixで使用可能にする。
;

;; Default Settings
(setq logger-text-prefix "参加者: \n")
(setq logger-text-suffix "Agenda\n\n  - \n  -\n  - \n")
(setq logger-directory "./")
(setq logger-fill-key "\C-t")

(setq str "")

(defun logger-open ()
  "*create log-file and open it."
  (interactive)

  (load "~/.emacs.d/.logger.el" 'noerror 'nomessage)

;; groupを入力させ、fileを作り、bufferをopenする。
  (logger-open-file)
)

(defun logger-open-file ()
  "*create log-file"
  (setq logger-group (read-string "What group do you want to log? "))
  (find-file (format "%s/log-%s-%s.txt" logger-directory (format-time-string "%Y_%m_%d") logger-group))
  (insert (format  "* %s %s \n" (format-time-string "%Y/%m/%d") logger-group))
  (insert logger-text-prefix)
  (insert "-------------------------------------------------\n")
  (insert logger-text-suffix)

  (text-mode)  ;; text-modeに
;; key-mapの変更
  (global-set-key logger-fill-key 'logger-fill-member-name)
)

(defun logger-fill-member-name ()
  "Auto-fill member name and insert timestamp"
  (interactive)
  (setq logger-fill-beginning-point (point))
    (skip-chars-backward "^ \t\n")
    ;;  先頭からポイントまでの文字列を取得
    (setq logger-fill-strings (buffer-substring
                               logger-fill-beginning-point (point)))
    ;;  (message logger-fill-strings)

    (setq logger-fill-result
          (try-completion logger-fill-strings logger-group-member-alist))
    (cond
     ((eq logger-fill-result t)    ;; 補完可
      (skip-chars-forward "A-Za-z")
      (insert (format "\[%s\] > " (format-time-string "%02H:%02M"))))
     ((eq logger-fill-result nil)  ;; 補完不可
            (skip-chars-forward "A-Za-z"))
     ((string-equal logger-fill-strings logger-fill-result)
      (skip-chars-forward "A-Za-z")
      ;;候補一覧を表示
      (setq str "complete ")
      (logger-print-complete-list (all-completions logger-fill-strings
                                                   logger-group-member-alist))
      )
     (t
      (delete-region logger-fill-beginning-point (point))
      (insert logger-fill-result)
      (logger-fill-member-name) ;; insert " > "
        )
     )
  )

(defun logger-print-complete-list (lis)
  ""
  (cond
   (( atom lis)
    (message str)
    )
   (t
    (setq str (concat str " : " (car lis) ))
    (logger-print-complete-list (cdr lis))
    )
   ))

他にもanything.elやyasnipetも使ってるけど使いこなしていないので、今回はこんなあたりで。