<2014-12-25 Thu> Emacs Advent Calendar 2014にてhelm-swoopについて書きました!

helmanything.el を使っていると、
つい M-g M-n (M-x next-error)や
M-g M-p (M-x previous-error)が
恋しくなったりしませんか?

helmやanythingの美点は、なんといっても
絞り込み検索 ができることです。

しかし、絞り込んだ結果を順次渡り歩くコマンドは
残念ながら用意されていません。

そのためにときには旧来の M-x occur などを
使うハメになってしまいます。

これでは勿体ないですね。

そこで、next-error/previous-errorを
helm/anything対応させてみました。

M-x helm-occurhelm-swoop.el を使った後に
新しい next-error 相当のコマンドを実行したら、
helm/anythingの次の項目に移動してくれるようにします。

もちろん、M-x occurや M-x grep を実行したら、
それらの結果に対して通常の挙動をします。

この設定では標準のM-g M-n/M-g M-pを置き換えています。

helmとanything.elを併用している方は
M-x package-install helm-anything
で拙作 helm-anything.el をインストールしてください。

設定 141127102557.helm-next-error.1.el(以下のコードと同一)

;;;; replacement of `next-error' and `previous-error'

(require 'helm-anything nil t)
(require 'helm)

;;; resumable helm/anything buffers
(defvar helm-resume-goto-buffer-regexp
  (rx (or (regexp "Helm Swoop") "helm imenu" (regexp "helm.+grep") "helm-ag"
          "occur"
          "*anything grep" "anything current buffer")))
(defvar helm-resume-goto-function nil)
(defun helm-initialize--resume-goto (resume &rest _)
  (when (and (not (eq resume 'noresume))
             (ignore-errors
               (string-match helm-resume-goto-buffer-regexp helm-last-buffer)))
    (setq helm-resume-goto-function
          (list 'helm-resume helm-last-buffer))))
(advice-add 'helm-initialize :after 'helm-initialize--resume-goto)
(defun anything-initialize--resume-goto (resume &rest _)
  (when (and (not (eq resume 'noresume))
             (ignore-errors
               (string-match helm-resume-goto-buffer-regexp anything-last-buffer)))
    (setq helm-resume-goto-function
          (list 'anything-resume anything-last-buffer))))
(advice-add 'anything-initialize :after 'anything-initialize--resume-goto)

;;; next-error/previous-error
(defun compilation-start--resume-goto (&rest _)
  (setq helm-resume-goto-function 'next-error))
(advice-add 'compilation-start :after 'compilation-start--resume-goto)
(advice-add 'occur-mode :after 'compilation-start--resume-goto)
(advice-add 'occur-mode-goto-occurrence :after 'compilation-start--resume-goto)
(advice-add 'compile-goto-error :after 'compilation-start--resume-goto)


(defun helm-resume-and- (key)
  (unless (eq helm-resume-goto-function 'next-error)
    (if (fboundp 'helm-anything-resume)
        (setq helm-anything-resume-function helm-resume-goto-function)
      (setq helm-last-buffer (cadr helm-resume-goto-function)))
    (execute-kbd-macro
     (kbd (format "%s %s RET"
                  (key-description (car (where-is-internal
                                         (if (fboundp 'helm-anything-resume)
                                             'helm-anything-resume
                                           'helm-resume))))
                  key)))
    (message "Resuming %s" (cadr helm-resume-goto-function))
    t))
(defun helm-resume-and-previous ()
  "Relacement of `previous-error'"
  (interactive)
  (or (helm-resume-and- "C-p")
      (call-interactively 'previous-error)))
(defun helm-resume-and-next ()
  "Relacement of `next-error'"
  (interactive)
  (or (helm-resume-and- "C-n")
      (call-interactively 'next-error)))

;;; Replace: next-error / previous-error
(require 'helm-config)
(ignore-errors (helm-anything-set-keys))
(global-set-key (kbd "M-g M-n") 'helm-resume-and-next)
(global-set-key (kbd "M-g M-p") 'helm-resume-and-previous)

実行方法

$ wget http://rubikitch.com/f/141127102557.helm-next-error.1.el
$ emacs -Q -f package-initialize -l 141127102557.helm-next-error.1.el

20141127104143.png
Fig1: M-x helm-occur RET that

20141127104155.png
Fig2: M-g M-n

本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。