よく開くファイルを登録しとく

いっつも開くファイルなんてたかだか 5〜6 個だけど、探すのがめんどくさい。
とくに今はカスタマイズ中なので、.xyzzy は頻繁に開くし、自前のライブラリとかもしょっちゅう開く。
じゃあ、登録しとけばってことで、こんなのを作ってみた。

;;;
;;; @@@ find-file-frequently
;;;
(defvar *find-file-frequently-list* '((merge-pathnames ".xyzzy" (user-homedir-pathname))
                                      (append-trail-slash (path-delim-to-slash (get-special-folder-location :desktop)))
                                      (default-directory)))

(defvar *find-file-frequently-count* 0)

(add-hook '*enter-minibuffer-hook*
          #'(lambda (buf his)
              (setq *find-file-frequently-count* 0)))
          
(defun find-file-frequently-sort-function (x y)
  (cond ((and (not (file-directory-p x)) (file-directory-p y)) t)
        ((and (file-directory-p x) (not (file-directory-p y))) nil)
        (t (string-length-lessp x y))))

(defun find-file-frequently ()
  (interactive)
  (let ((old (buffer-substring (point-min) (point-max)))
        (lst (mapcar #'truename-mod (mapcar #'eval *find-file-frequently-list*))))
    (let ((s (nth (mod *find-file-frequently-count* (length lst))
                  (sort lst #'find-file-frequently-sort-function))))
      (if (or (string= s old)
              (find s (mapcar #'get-buffer-file-name (buffer-list)) :test 'string=))
          (progn
            (incf *find-file-frequently-count*)
            (find-file-frequently))
        (progn
          (delete-region (point-min) (point-max))
          (insert s)
          (incf *find-file-frequently-count*))))))

(define-key ed::minibuffer-local-completion-map #\C-\f #'(lambda () (interactive)
                                                           (if (= (point) (point-max))
                                                               (find-file-frequently)
                                                             (forward-char 1))))

; (setq *find-file-frequently-list* (append *find-file-frequently-list*
;                                           '("~/lisp/discrete.l" "~/lisp/lib.l" "~/lisp/")))

使い方

C-x C-f でミニバッファに入ったら、C-f する。
すると登録している候補が出てくる。C-f するごとに順に次の候補が出てくる。
C-f は末尾のときだけ機能するような変態キーバインドにしてみた。

キーバインドは ed::minibuffer-local-completion-map をいじる。
候補のリストは *find-file-frequently-list* をカスタマイズする(最下行を参考)。
候補の順が気に入らなければ、find-file-frequently-sort-function を差し替えるとよろしい。

そうそう、こんなの↓が要る。

;;; @@@ string<, string-lessp
(defun string-length< (x y)
  (cond ((< (length x) (length y)) t)
        ((> (length x) (length y)) nil)
        ((string< x y) t)
        (t nil)))

(defun string-length-lessp (x y)
  (cond ((< (length x) (length y)) t)
        ((> (length x) (length y)) nil)
        ((string-lessp x y) t)
        (t nil)))

;;; @@@ truename
;;; mod: fixed removing trailing slash
(defun truename-mod (path)
  (let ((endc (char path (1- (length path)))))
    (if (or (eq endc #\/)
            (eq endc #\\))
        (append-trail-slash (truename path))
      (truename path))))