カレントバッファに関するanything.elのソースを設定する - 「bm.el」、「imenu」、「eevのアンカー」をanything.elで扱う

anything.elはユーザーひとりひとりのアイデアに柔軟に応えられる。
俺は「他のバッファへの切り替え」と「カレントバッファ内の移動」のソースを使い分けている。なぜなら、これらをひとまとめにすると余計な処理が入って重くなるし、余計な候補が入って選択しづらくなる。
そもそも二者は脳内における思考回路が異なる。たとえば、「他のファイルを開く」や「manを見る」は別な情報を見ると解釈できるし、「bm.elのブックマークへ飛ぶ」や「imenuでエントリに飛ぶ」などはバッファ内移動と解釈できる。

anything-set-source-filterで分けるのもいいけど、カレントバッファに関する候補はなるべく多く表示したい。だからletで設定を一時変更して別コマンドに分けておいた。かなり快適になった。imenuやbmのデフォルトのインターフェースなんか捨てだ。

anything-config.elで設定されてるanything-c-source-imenuは手抜きで使いものにならないから拡張しておいた。imenuは巨大なファイルだと重いが、キャッシュを使うことで高速化を図った。

bm.elは便利だから有無を言わさず入れとくべし。何をするかは言葉で説明するよりも実際に使ってみるほうがよくわかる。

eevは俺の5年来のパートナー。大昔書いた説明が残っているが、つかみどころのない説明しかできん。日本人のヘビーユーザはおそらく俺含め数人くらいであろう。

(defvar anything-function 'anything-migemo)
(defvar anything-for-current-buffer-sources nil)
(defun anything-for-current-buffer ()
  (interactive)
  (let ((anything-sources anything-for-current-buffer-sources)
        (anything-candidate-number-limit 2000))
    (call-interactively anything-function)))

;; bm.el source by Matsuyama
(require 'bm)
(defvar anything-c-source-bm
  '((name . "Visible Bookmarks")
    (init . (lambda ()
              (let ((bookmarks (bm-lists)))
                (setq anything-bm-marks
                      (delq nil
                            (mapcar (lambda (bm)
                                      (let ((start (overlay-start bm))
                                            (end (overlay-end bm)))
                                        (if (< (- end start) 2)
                                            nil
                                          (format "%7d: %s"
                                                  (line-number-at-pos start)
                                                  (buffer-substring start (1- end))))))
                                    (append (car bookmarks) (cdr bookmarks))))))))
    (candidates . (lambda ()
                    anything-bm-marks))
    (action . (("Goto line" . (lambda (candidate)
                                (goto-line (string-to-number candidate))))))))

;; eev anchor source
(defvar anything-c-source-eev-anchor
  '((name . "Anchors")
    (candidates . (lambda ()
                    (save-excursion
                      (set-buffer anything-current-buffer)
                      (goto-char (point-min))
                      (let (anchors)
                        (while (re-search-forward (format ee-anchor-format "\\(.+\\)") nil t)
                          (push (match-string 1) anchors))
                        (nreverse anchors)))))

    (volatile)
    (action . ee-to)))

;; improved imenu source
(defvar anything-c-imenu-delimiter " -> ")
(defvar anything-c-cached-imenu-alist nil)
(defvar anything-c-cached-imenu-candidates nil)
(defvar anything-c-cached-imenu-tick nil)
(make-variable-buffer-local 'anything-c-cached-imenu-alist)
(make-variable-buffer-local 'anything-c-cached-imenu-candidates)
(make-variable-buffer-local 'anything-c-cached-imenu-tick)
(setq anything-c-source-imenu
  '((name . "Imenu")
    (init . (lambda ()
              (setq anything-c-imenu-current-buffer
                    (current-buffer))))
    (candidates
     . (lambda ()
         (with-current-buffer anything-c-imenu-current-buffer
           (let ((tick (buffer-modified-tick)))
             (if (eq anything-c-cached-imenu-tick tick)
                 anything-c-cached-imenu-candidates
               (setq anything-c-cached-imenu-tick tick
                     anything-c-cached-imenu-candidates
                     (condition-case nil
                         (mapcan
                          (lambda (entry)
                            (if (listp (cdr entry))
                                (mapcar (lambda (sub)
                                          (concat (car entry) anything-c-imenu-delimiter (car sub)))
                                        (cdr entry))
                              (list (car entry))))
                          (setq anything-c-cached-imenu-alist (imenu--make-index-alist)))
                       (error nil))))))))
    (volatile)
    (action
     . (lambda (entry)
         (let* ((pair (split-string entry anything-c-imenu-delimiter))
                (first (car pair))
                (second (cadr pair)))
           (imenu
            (if second
                (assoc second (cdr (assoc first anything-c-cached-imenu-alist)))
              (assoc entry anything-c-cached-imenu-alist))))))))

(setq anything-for-current-buffer-sources
          (list anything-c-source-bm
                anything-c-source-eev-anchor
                anything-c-source-imenu))