linkd.elインストール

anything.elのソースに linkd.el が使われているのを見て、便利そうだったので導入してみた。

以下の2つの問題点あり。

何故かアイコンが表示されない

何か設定が足りないと思うので、後で調査する。

テキスト中の中途半端な lisp式が記述してあるとエラーになる

bm.el の .bm-repository など、テキスト中に中途半端な lisp式が記述してあるとエラーになる。
中途半端な lisp式の記述可能性のあるファイル(text-modeとか)モードフックに 'linkd-mode を加えるのを断念。
c++の例外catchみたいに、エラーが出てもヌルー出来ないものだろうか。。。

追記:

エラーの条件が絞り込めた。
中途半端なlisp式ではなく、おかしなlinkd式(?)があったときにエラーになる。

;;    corresponding @*, not just to the next link (@* or @>).

↑linkd.elより
とか

(@* \"Foo bar baz\")

↑bm.elの保存ファイルより

発生場所は、font-lockの際の (linkd-render-link) 。
linkd.elを色づけする際にエラーになっているので、自分環境でしかこのエラーは起こっていない模様。
さて、どう対応するか。。

解決

font-lock時の (eval sexp) で落ちていたので、linkd-match を下記のように変更 (※この修正は正しくありません。下記の2008/10/2の追記を参照して下さい)

(defun linkd-match (limit)
  "Try to read link sexp between point and LIMIT.
Return non-nil if a link is found.  Set match-data appropriately."
  (let ((sexp nil))
    (when (search-forward (concat "(" "@") limit t) (backward-char 2))
    (let ((begin-point (point)))
;org      (condition-case nil (setq sexp (read (current-buffer))) ((error nil)))
      (condition-case nil (let ( (tmp-sexp (read (current-buffer))))
                                 (eval tmp-sexp)
                                 (setq sexp tmp-sexp))
        ((error nil)))
      (when (string-match "@.*" (symbol-name (car-safe sexp)))
        (let ((begin-marker (make-marker))
              (end-marker (make-marker)))
          (set-marker begin-marker begin-point)
          (set-marker end-marker (point))
          (set-match-data (list begin-marker end-marker)))
        t))))
追記: 2008/09/29

エラーの発生機序が段々分かってきた。
まず、linkd.el 自体でエラーになる現象だが、add-hook をしない状態で、手動で M-x linkd-mode を行うと起こらない。
調べてみると、手動で linkd-mode に切り替えたときは linkd-match がコールされていない。
mode-hook で色づけされるときと、手動で linkd-modeに切り替えたときの色づけの機序が違うらしい。
多分、いい感じでfont-lockがコメントとしてはじいているような気がする。
それを裏付けるように、text-mode では、手動で linkd-mode にした場合もエラーになる。

段々面倒になってきたので、前回の修正でイイヤと思い始めてきた。。

追記: 2008/10/2

結局力業で、下記のような修正をすることで最終的な解決とした。
前回の修正だと、下記のような正しくないS式があった場合、それ以降のlinkd S式が色づけされないという問題があった。

(@

というか、他の人たちはエラー出てないんだろうか。。
ウチのVineでは、emacs -q で試してみてもエラーになっていたのに。。。

※2009/2/24追記
この不具合だか、emacsのバージョンに依存している事が発覚。
emacs-22.0だとNG
emacs-22.3だと問題なく動作していた。
トホホ。。

(defun linkd-match (limit)
  "Try to read link sexp between point and LIMIT.
Return non-nil if a link is found.  Set match-data appropriately."
  (catch 'found
    (while t
      (if (search-forward (concat "(" "@") limit t)
          (progn
            (backward-char 2)
            (let ((sexp nil) (begin-point (point)))
              (if (and (condition-case nil (setq sexp (read (current-buffer))) (error (if (end-of-buffer)
                                                                                          (throw 'found nil)
                                                                                        (goto-char (+ 1 begin-point)))))
                       (condition-case nil (eval sexp) (error nil)))
                  (progn
                    (when (string-match "@.*" (symbol-name (car-safe sexp)))
                      (let ((begin-marker (make-marker))
                            (end-marker (make-marker)))
                        (set-marker begin-marker begin-point)
                        (set-marker end-marker (point))
                        (set-match-data (list begin-marker end-marker)))
                      (throw 'found t))
                    ))))
        (throw 'found nil)))
    ))
linkd.elの設定例
(require 'linkd)

(define-key linkd-map (kbd "C-c , >") 'linkd-insert-tag)
(define-key linkd-map (kbd "C-c , *") 'linkd-insert-star)


(setq linkd-use-icons t)
(setq linkd-icons-directory (concat my-lisp-directory "/linkd-icons"))

(add-hook 'emacs-lisp-mode-hook 'linkd-mode)
(add-hook 'lisp-mode-hook 'linkd-mode)
(add-hook 'sh-mode-hook 'linkd-mode)
(add-hook 'c-mode-common-hook 'linkd-mode)