refe.el を使う。

refe.el とは Emacs から ReFe を使うためのインターフェイス

最新版は …… たぶん公式に配布してるとこはない。*1

手元にあった最新版と思しき refe.el を動かしてみると、候補の補完ができない。

本来なら複数のクラスに存在するメソッドを引くと、クラスの候補が出てきて補完できるようになるはず。

blade から refe.el 関連のメールを漁る。

手元にあったのとは、ちょっと違う refe.el を手に入れたが、やっぱり補完はできない。

looking-at の正規表現をいぢって、なんとか動くようになった。

(defvar refe-program-name
  (if (featurep 'meadow)
      "ruby"
    "refe"))
(defvar refe-program-args
  (if (featurep 'meadow)
      '("-S" "refe")
    nil))
(defvar refe-buffer-name "*Refe*")
(defvar refe-completion-table nil)

(defun refe-call-process (buf &rest args)
  (let ((coding-system-for-read 'euc-japan))
    (apply 'call-process refe-program-name nil buf nil
           (append refe-program-args args))))

(defun refe-make-completion-table ()
  (setq refe-completion-table (make-vector 547 0))
  (with-temp-buffer
    (refe-call-process t)
    (goto-char (point-min))
    (while (looking-at "[A-Z][A-Za-z_0-9:]*")
      (intern (match-string 0) refe-completion-table)
      (skip-chars-forward "^ \n")
      (skip-chars-forward " \n")))

  (with-temp-buffer
    (refe-call-process t "")
    (goto-char (point-min))
    (while (looking-at "\\(\\$[^ \n]*\\|[A-Z][A-Za-z_0-9:]*[#.][^ \n]*\\)")
      (intern (match-string 0) refe-completion-table)
      (skip-chars-forward "^ \n")
      (skip-chars-forward " \n")))
  nil)

(refe-make-completion-table)

(defun refe-get-word-at-point ()
  (save-excursion
    (while (looking-at "\\sw\\|\\s_")
      (forward-char 1))
    (if (or (re-search-backward "\\sw\\|\\s_"
				(save-excursion (beginning-of-line) (point))
				t)
	    (re-search-forward "\\(\\sw\\|\\s_\\)+"
			       (save-excursion (end-of-line) (point))
			       t))
	(progn (goto-char (match-end 0))
	       (buffer-substring (point)
				 (progn (forward-sexp -1)
					(while (looking-at "\\s'")
					  (forward-char 1))
					(point))))
      nil)))

(defun refe ()
  (interactive)
  (if (null refe-completion-table)
      (refe-make-completion-table))
  (let* ((default (refe-get-word-at-point))
	 (completion-ignore-case t)
	 (word (completing-read (if default
				    (format "Class or Method (default %s): " default)
				  "Class or Method: ")
				refe-completion-table nil nil nil nil default))
	 (buf (or (get-buffer refe-buffer-name)
		  (generate-new-buffer refe-buffer-name)))
	 (pop-up-windows t)
	 (pop-up-frames nil))

    (set-buffer buf)
    (setq buffer-read-only nil)
    (erase-buffer)

    (refe-call-process buf word)

    (goto-char (point-min))
    (if (re-search-forward "^---" nil t)
	nil
      (let ((klass-table (make-vector 17 0))
	    (completion-ignore-case t)
	    klass)
	(goto-char (point-min))
	(while (looking-at "\\([A-Z][A-Za-z_0-9:]*\\)[#.][^ \n]*")
	  (intern (match-string 1) klass-table)
	  (skip-chars-forward "^ \n")
	  (skip-chars-forward " \n"))
	(if (= (point) (point-min))
	    nil ; (message "no such class or method: %s" word)
	  (setq klass (completing-read "Class: "
				       klass-table nil nil nil nil nil))
	  (erase-buffer)
	  (refe-call-process buf "--all" klass word))))

    (set-buffer-modified-p nil)
    (setq buffer-read-only t)
    (goto-char (point-min))
    (display-buffer buf)))

(provide 'refe)

元のファイルがあやふやなので、パッチじゃなくて全部を貼ってみた。

個人的には refe-make-completion-table はいらないなぁ。遅いし。

Re: refe.el によると、

説明なしのライセンスなしで、本気でメンテしたい方にお譲りします。

らしいけど ……

*1:今は anything を使うのが主流なの?