anythingでoccur-by-moccur

emacs使っている人は、ほとんどの人が使っていると思いますがバッファやファイルを対象とした検索が超絶便利なcolor-moccurというelispがあります。
これをanythingで使えばimenuと組み合わせたりしてバッファ内の検索->移動が非常に素早くできると思ったので書いてみました。
とりあえず動くようになったので貼り付けておきます。


参考リンクでの紹介文とほぼ同じですが

  • migemo正規表現を利用した検索ができる。
  • 検索パターンの先頭が ! で関数、 ; でコメント、 " で文字列を対象に絞り込める。
  • スペース区切りで複数語の検索が簡単にできる。

点が非常に便利です。


以下にコードを貼り付けて置きます。
まだ、バッファ内の検索しかできません。
使い方は二通りです。

  • anything-sources に anything-c-source-moccur を追加する。
  • コマンド anything-moccur 実行する。

自分は (global-set-key (kbd "M-o") 'anything-moccur)
でM-o に割り当てて使っています。
もっさりするかなと思いましたが自分の環境(X61,core2duo1.8G,memory2G)では、jQuery,Prototype等3000-4000行くらいのソースでもストレス感じないです。
10万行のsdicファイルでmigemoを使った日本語検索もやってみましたが問題なくてビックリしました。

;;color-moccurのお勧め設定。
(setq moccur-split-word t) ;スペース区切りでAND検索
(setq moccur-use-migemo t) ;migemoを使う

(require 'anything)
(require 'color-moccur)
;; 結果のバッファから候補を得るためにadvice
;; 日記に貼り付けるため元のコードのインデントをすこし変えました。すいません。
(defadvice moccur-search (around no-window-change)
  (let ((regexp (ad-get-arg 0))
        (arg (ad-get-arg 1))
        (buffers (ad-get-arg 2)))
    (when (or (not regexp)
              (string= regexp ""))
    (error "No search word specified!"))
    ;; initialize
  (let ((lst (list regexp arg buffers)))
    (if (equal lst (car moccur-searched-list))
        ()
      (setq moccur-searched-list (cons (list regexp arg buffers) moccur-searched-list))))
  (setq moccur-special-word nil)
  (moccur-set-regexp)
  (moccur-set-regexp-for-color)
  ;; variable reset
  (setq dmoccur-project-name nil)
  (setq moccur-matches 0)
  (setq moccur-match-buffers nil)
  (setq moccur-regexp-input regexp)
  (if (string= (car regexp-history) moccur-regexp-input)
      ()
    (setq regexp-history (cons moccur-regexp-input regexp-history)))
  (save-excursion
    (setq moccur-mocur-buffer (generate-new-buffer "*Moccur*"))
    (set-buffer moccur-mocur-buffer)
    (insert "Lines matching " moccur-regexp-input "\n")
    (setq moccur-buffers buffers)
    ;; search all buffers
    (while buffers
      (if (and (car buffers)
               (buffer-live-p (car buffers))
               ;; if b:regexp exists,
               (if (and moccur-file-name-regexp
                        moccur-split-word)
                   (string-match moccur-file-name-regexp (buffer-name (car buffers)))
                 t))
          (if (and (not arg)
                   (not (buffer-file-name (car buffers))))
              (setq buffers (cdr buffers))
            (if (moccur-search-buffer (car moccur-regexp-list) (car buffers))
                (setq moccur-match-buffers (cons (car buffers) moccur-match-buffers)))
            (setq buffers (cdr buffers)))
        ;; illegal buffer
        (setq buffers (cdr buffers)))))))

(defun anything-c-source-moccur-get-candidates ()
  ;; active advice
  (ad-enable-advice 'moccur-search 'around 'no-window-change)
  (ad-activate 'moccur-search)
  (save-window-excursion
    (moccur-setup)
    (moccur-search anything-pattern t (list anything-current-buffer)))
  ;; disable advance
  (ad-disable-advice 'moccur-search 'around 'no-window-change)
  (ad-activate 'moccur-search)
  (with-current-buffer moccur-mocur-buffer
    (let* ((buf (buffer-substring (point-min) (point-max)))
           (lines (delete "" (subseq (split-string buf "\n") 3))))
      lines)))

;; source内にlambdaだと動かなかった(詳細不明)
(defun anything-c-source-moccur-match (c) t)

(defvar anything-c-source-moccur
  '((name . "Occur by Moccur")
    (candidates . (lambda ()
                    (anything-c-source-moccur-get-candidates)))
    (action . (("Goto line" . (lambda (candidate)
                                (goto-line (string-to-number candidate))))))
    (match . (anything-c-source-moccur-match))
    (requires-pattern . 3)
    (delayed) ;追記
    (volatile)))

;;; Command
(defun anything-moccur ()
  (interactive)
  (let ((anything-sources (list anything-c-source-moccur)))
    (anything)))

追記

  • ソース内に (delayed) を追記しました。

参考リンク