requireしているファイルの場所に飛ぶelisp

  • (require '<何か>)というところにカーソルを合わせてC-c C-fでファイルを開ける
  • C-c C-aでcurrent-buffer内のすべてのrequireしているファイルからanythingで選択して開ける
  • 実体がないものとかは無理です。*1
(require 'anything)
(defun elisp-reading-search-file (file &optional allp) 
  (if (not allp)
      (dolist (path load-path)
	(let ((full-path (concat path "/" file)))
	  (when (file-exists-p full-path)
	    (return full-path))))
    (let ((result '()))
      (dolist (path load-path)
	(let ((full-path (concat path "/" file)))
	  (when (file-exists-p full-path)
	    (push full-path result))))
      result))
  )

(defvar elisp-reading-required-regexp "(\\(require\\|autoload\\) '\\([^ )]+\\)")

(defun elisp-reading-get-filename (required) 
  (let ((file (concat required ".el")))
    (substring-no-properties file)))


(defun elisp-reading-touch-required (&optional action) (interactive)
  (let ((action (or action #'find-file)))
    (save-excursion
      (beginning-of-line)
      (when (re-search-forward elisp-reading-required-regexp (point-at-eol) t 1)
	(let ((file (elisp-reading-get-filename (match-string 2))))
	  (when file
	    (let ((file-full-path (elisp-reading-search-file file)))
	      (when file-full-path
		(funcall action file-full-path)))))))))


(defun elisp-reading-get-all-required () (interactive)
  (let ((lst '()))
    (save-excursion
      (goto-char (point-min))
      (while (re-search-forward elisp-reading-required-regexp nil t)
	(let* ((file (elisp-reading-get-filename (match-string 2)))
	       (file-full-paths (elisp-reading-search-file file t)))
	  (dolist (f file-full-paths)(push f lst))))
      lst)))

(defun anything-elisp-required  () (interactive)
  (let ((anything-sources
	 `(((name . "elisp required")
	    (type . file)
	    (candidates . ,(elisp-reading-get-all-required))))))
    (anything)))

(add-hook 'emacs-lisp-mode-hook
	  (lambda ()
	    (define-key emacs-lisp-mode-map "\C-c\C-f" 'elisp-reading-touch-required)
	    (define-key emacs-lisp-mode-map "\C-c\C-a" 'anything-elisp-required)
	    ))

*1:.elcだけのものとか