作者: rubikitch
日時: 2003/2/12(10:23)
るびきちです。

つい最近おもしろいEmacsLispをみつけた。その名も「eev」。

http://angg.twu.net/index.html#eev

eevは大きくわけてふたつの機能がある。

* ハイパーリンク
* region内のスクリプトをセーブ

注目したいのは「ハイパーリンク」。Emacsをひとつの「Lispシステム」とみ
なしてLisp式でハイパーリンクをしてしまっている。とにかくその単純明解か
つ汎用性の高い発想に驚きだ。

その発想の原点となるのが
  C-x C-e
で

                どのバッファであろうが

Lisp式を評価できるということだ。
emacs-lisp-modeであろうが、text-modeであろうが、perl-modeであろうが、
  ruby-modeであろうがなんでもいい。Emacs上にいる以上いつでもどこでも
Lisp式が評価できるということ。

それを逆手に取って

                だったらテキストにLisp式を埋め込んでしまえ!

って発想がでた。それがeevの発想。

たとえば、
  # (find-file "~/.emacs")
の)の後のカーソルをあわせてC-xC-eすると、バッファが~/.emacsへと変わる。
そんなのは当たり前のことなのだが、ちょっと視点を変えてみたい。

そして、次のコードを.emacsに加えておく。(これはeev配布物には加わってな
い。おれが勝手につくった)
(defun ee-next-sexp ()
  (interactive)
  (re-search-forward ")$"))
(defun ee-prev-sexp ()
  (interactive)
  (re-search-backward ")$"))
(global-set-key "\M-p" 'ee-prev-sexp)
(global-set-key "\M-n" 'ee-next-sexp)

そうすると、テキスト内に埋め込まれたLisp式をM-p/M-nでとぶことができる。
で、Lisp式の後にカーソルをあわせて C-x C-e すると実行される。

別にfind-fileに限らない。関数の解説がみたければ describe-function だし
変数ならば describe-variable だ。関数定義にとびたければ find-function。
そういう式を実行すると、所定の場所へジャンプする。これっていってみれば

                ハイパーリンク

に他ならない!!!

eevをインストールするとそういうハイパーリンクをもっと便利に使えるよう
にする関数がたくさん登録される。よく使うものとしては
  (find-fline filename position)
という関数がある。それはfind-fileの拡張版でpositionに行番号などを入れ
るとその場所へジャンプしてくれるようになる。
  (find-fline "~/.emacs" 5)
で~/.emacsの5行目へジャンプするように。

さらに、M-eに end-of-line-then-eval-last-sexp という行頭へ飛んでからそ
の式を評価するコマンドが割り当てられる。M-p/M-nと組み合わせてHTML顔負
けのハイパーリンクができるのがある意味恐しい。どんなファイルを編集して
てもそのハイパーリンクがつかえてしまうのだから!!
スクリプトに使ってもいいし、ChangeLogメモと組み合わせてもいい。

eevを使って以来、拙作clwikiはもう使わなくなった(^^; リンクはeevがある
し、ブロックについてはyardmという「ChangeLog風RDメモ(開発中)」を使って
いるから。RDはほぼフリーフォーマットな上、rd-mode.elが見出しには色をつ
けてくれるから嬉しい。それに階層構造もつくれるし。ChangeLogメモだと先
頭のタブがうざい、clwikiのブロックはclgrepで検索されないなどなど。

さらにbookmark.elとの連携で任意のファイルの位置をLisp式に吐き出すコー
ドを書いてみた。

(defun ee-bookmark (fn pos front rear)
  (if fn (find-file fn)
    (push-mark))
  (goto-char pos)
  (if (search-forward front (point-max) t)
      (goto-char (match-beginning 0)))
  (if (and rear (search-backward rear (point-min) t))
      (goto-char (match-end 0))))
(defalias 'pos 'ee-bookmark)
(setq ee-bookmark-tmp nil)
(defun ee-yank (arg)
  (interactive "P")
  (when ee-bookmark-tmp
    (let ((print-escape-newlines t)
          (buf (car ee-bookmark-tmp))
          (fn (nth 1 ee-bookmark-tmp))
          (pos (nth 2 ee-bookmark-tmp))
          (front (nth 3 ee-bookmark-tmp))
          (rear (nth 4 ee-bookmark-tmp)))
      (setq ee-bookmark-tmp nil)
      (kill-new (if (eq buf (current-buffer))
                    (format "(pos nil %d %S %S)" pos front rear)
                  (format "(pos %S %d %S %S)" fn pos front rear)))))
  (call-interactively 'yank))
(global-set-key "\C-y" 'ee-yank)
(defun ee-make-bookmark (arg)
  (interactive "P")
  (require 'bookmark)
  (let* ((bookmark "ee")
         (bookmark-alist (list (list bookmark (bookmark-make-cell nil)))) 
         (filename (unless arg (bookmark-get-filename bookmark)))
         (front (bookmark-get-front-context-string bookmark))
         (rear (bookmark-get-rear-context-string bookmark))
         (position (bookmark-get-position bookmark))
         )
    (setq ee-bookmark-tmp (list (current-buffer) filename position front rear))
    (message "stored position at #<buffer %s> to kill-ring." (buffer-name (current-buffer)))))

ここの位置を記録したいと思ったら M-x ee-make-bookmark とする。(当然お
れはキーにわりあてている)それから、貼り付けたい場所で C-y すればその式
がyankされる。

面白いと思ったら是非とも使ってみては?

るびきち☆
http://www.ruby-lang.org/~rubikitch/ ←Ruby大衆化計画(笑)