]> code.delx.au - gnu-emacs/blobdiff - lisp/filecache.el
(mode-line-major-mode-keymap): Undo last change.
[gnu-emacs] / lisp / filecache.el
index 08ae14c739553cddce693833c0e70531725d4bf8..c0e9e9e5f5d2b6877b763588b5befba3cee21630 100644 (file)
@@ -1,11 +1,11 @@
-;;; filecache.el --- Find files using a pre-loaded cache
+;;; filecache.el --- find files using a pre-loaded cache
 ;;
-;; Author:  Peter Breton
+;; Author:  Peter Breton <pbreton@cs.umb.edu>
 ;; Created: Sun Nov 10 1996
-;; Keywords: 
-;; Time-stamp: <97/02/07 17:26:54 peter>
+;; Keywords: convenience
 ;;
-;; Copyright (C) 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 2000, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -21,8 +21,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 ;;
 ;; ADDING FILES TO THE CACHE:
 ;;
 ;; Use the following functions to add items to the file cache:
-;; 
+;;
 ;;   * `file-cache-add-file': Adds a single file to the cache
 ;;
 ;;   * `file-cache-add-file-list': Adds a list of files to the cache
 ;;
 ;; The following functions use the regular expressions in
 ;; `file-cache-delete-regexps' to eliminate unwanted files:
-;;   
+;;
 ;;   * `file-cache-add-directory': Adds the files in a directory to the
 ;;     cache. You can also specify a regular expression to match the files
 ;;     which should be added.
 ;;   * `file-cache-add-directory-using-locate': Uses the `locate' command to
 ;;     add files matching a pattern to the cache.
 ;;
+;;   * `file-cache-add-directory-recursively': Uses the find-lisp package to
+;;     add all files matching a pattern to the cache.
+;;
 ;; Use the function `file-cache-clear-cache' to remove all items from the
 ;; cache. There are a number of `file-cache-delete' functions provided
 ;; as well, but in general it is probably better to not worry too much
 ;; about extra files in the cache.
 ;;
 ;; The most convenient way to initialize the cache is with an
-;; `eval-after-load' function, as noted in the INSTALLATION section.
+;; `eval-after-load' function, as noted in the ADDING FILES
+;; AUTOMATICALLY section.
 ;;
 ;; FINDING FILES USING THE CACHE:
 ;;
@@ -87,7 +91,7 @@
 ;;
 ;; 4) When you have found a unique completion, the minibuffer contents
 ;; will change to the full name of that file.
-;; 
+;;
 ;; If there are a number of directories which contain the completion,
 ;; invoking `file-cache-minibuffer-complete' repeatedly will cycle through
 ;; them.
 ;;
 ;; It is much easier to simply try it than trying to explain it :)
 ;;
-;;; INSTALLATION
-;;
-;; Insert the following into your .emacs:
-;;
-;; (autoload 'file-cache-minibuffer-complete "filecache" nil t)
+;;; ADDING FILES AUTOMATICALLY
 ;;
 ;; For maximum utility, you should probably define an `eval-after-load'
 ;; form which loads your favorite files:
 ;;
-;;      (eval-after-load 
+;;      (eval-after-load
 ;;       "filecache"
 ;;       '(progn
 ;;         (message "Loading file cache...")
 ;; If you clear and reload the cache frequently, it is probably easiest
 ;; to put your initializations in a function:
 ;;
-;;   (eval-after-load 
+;;   (eval-after-load
 ;;     "filecache"
 ;;      '(my-file-cache-initialize))
-;;        
+;;
 ;;   (defun my-file-cache-initialize ()
 ;;      (interactive)
 ;;     (message "Loading file cache...")
 ;; Lisp functions.
 ;;
 ;; RELATED WORK:
-;; 
+;;
 ;; This package is a distant relative of Noah Friedman's fff utilities.
 ;; Our goal is pretty similar, but the implementation strategies are
 ;; different.
 
 ;;; Code:
 
+(eval-when-compile
+  (require 'find-lisp))
+
+(defgroup file-cache nil
+  "Find files using a pre-loaded cache."
+  :group 'files
+  :group 'convenience
+  :prefix "file-cache-")
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Variables
+;; Customization Variables
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 ;; User-modifiable variables
-(defvar file-cache-filter-regexps 
-  (list "~$" "\\.o$" "\\.exe$" "\\.a$" "\\.elc$" ",v$" "\\.output$" 
-       "\\.$" "#$")
+(defcustom file-cache-filter-regexps
+  (list "~$" "\\.o$" "\\.exe$" "\\.a$" "\\.elc$" ",v$" "\\.output$"
+       "\\.$" "#$" "\\.class$")
   "*List of regular expressions used as filters by the file cache.
 File names which match these expressions will not be added to the cache.
-Note that the functions `file-cache-add-file' and `file-cache-add-file-list' 
-do not use this variable.")
-
-(defvar file-cache-find-command "find"
-  "*External program used by `file-cache-add-directory-using-find'.")
-
-(defvar file-cache-locate-command "locate"
-  "*External program used by `file-cache-add-directory-using-locate'.")
+Note that the functions `file-cache-add-file' and `file-cache-add-file-list'
+do not use this variable."
+  :type '(repeat regexp)
+  :group 'file-cache)
+
+(defcustom file-cache-find-command "find"
+  "*External program used by `file-cache-add-directory-using-find'."
+  :type 'string
+  :group 'file-cache)
+
+(defcustom file-cache-find-command-posix-flag 'not-defined
+  "*Set to t, if `file-cache-find-command' handles wildcards POSIX style.
+This variable is automatically set to nil or non-nil
+if it has the initial value `not-defined' whenever you first
+call the `file-cache-add-directory-using-find'.
+
+Under Windows operating system where Cygwin is available, this value
+should be t."
+  :type  '(choice (const :tag "Yes" t)
+                 (const :tag "No" nil)
+                 (const :tag "Unknown" not-defined))
+  :group 'file-cache)
+
+(defcustom file-cache-locate-command "locate"
+  "*External program used by `file-cache-add-directory-using-locate'."
+  :type 'string
+  :group 'file-cache)
 
 ;; Minibuffer messages
-(defvar file-cache-no-match-message " [File Cache: No match]"
-  "Message to display when there is no completion.")
+(defcustom file-cache-no-match-message " [File Cache: No match]"
+  "Message to display when there is no completion."
+  :type 'string
+  :group 'file-cache)
+
+(defcustom file-cache-sole-match-message " [File Cache: sole completion]"
+  "Message to display when there is only one completion."
+  :type 'string
+  :group 'file-cache)
+
+(defcustom file-cache-non-unique-message
+  " [File Cache: complete but not unique]"
+  "Message to display when there is a non-unique completion."
+  :type 'string
+  :group 'file-cache)
+
+(defcustom file-cache-completion-ignore-case
+   (if (memq system-type (list 'ms-dos 'windows-nt 'cygwin))
+      t
+     completion-ignore-case)
+  "If non-nil, file-cache completion should ignore case.
+Defaults to the value of `completion-ignore-case'."
+  :type 'sexp
+  :group 'file-cache
+  )
 
-(defvar file-cache-sole-match-message " [File Cache: sole completion]"
-  "Message to display when there is only one completion.")
+(defcustom file-cache-case-fold-search
+  (if (memq system-type (list 'ms-dos 'windows-nt 'cygwin))
+      t
+    case-fold-search)
+  "If non-nil, file-cache completion should ignore case.
+Defaults to the value of `case-fold-search'."
+  :type 'sexp
+  :group 'file-cache
+  )
 
-(defvar file-cache-non-unique-message " [File Cache: complete but not unique]"
-  "Message to display when there is a non-unique completion.")
+(defcustom file-cache-ignore-case
+  (memq system-type (list 'ms-dos 'windows-nt 'cygwin))
+  "Non-nil means ignore case when checking completions in the file cache.
+Defaults to nil on DOS and Windows, and t on other systems."
+  :type 'sexp
+  :group 'file-cache
+  )
 
 (defvar file-cache-multiple-directory-message nil)
 
 ;; Internal variables
 ;; This should be named *Completions* because that's what the function
 ;; switch-to-completions in simple.el expects
-(defvar file-cache-completions-buffer "*Completions*"
-  "Buffer to display completions when using the file cache.")
+(defcustom file-cache-completions-buffer "*Completions*"
+  "Buffer to display completions when using the file cache."
+  :type 'string
+  :group 'file-cache)
 
-(defvar file-cache-buffer "*File Cache*"  
-  "Buffer to hold the cache of file names.")
+(defcustom file-cache-buffer "*File Cache*"
+  "Buffer to hold the cache of file names."
+  :type 'string
+  :group 'file-cache)
 
-(defvar file-cache-buffer-default-regexp "^.+$"
-  "Regexp to match files in `file-cache-buffer'.")
+(defcustom file-cache-buffer-default-regexp "^.+$"
+  "Regexp to match files in `file-cache-buffer'."
+  :type 'regexp
+  :group 'file-cache)
 
 (defvar file-cache-last-completion nil)
 
@@ -199,30 +268,36 @@ do not use this variable.")
 
 (defun file-cache-add-directory (directory &optional regexp)
   "Add DIRECTORY to the file cache.
-If the optional REGEXP argument is non-nil, only files which match it will 
+If the optional REGEXP argument is non-nil, only files which match it will
 be added to the cache."
-  (interactive "DAdd files from directory: ") 
-  (let* ((dir       (expand-file-name directory))
-        (dir-files (directory-files dir t regexp))
-        )
-    ;; Filter out files we don't want to see
-    (mapcar
-     '(lambda (file)
-       (mapcar 
-        '(lambda (regexp)
-           (if (string-match regexp file)
-               (setq dir-files (delq file dir-files))))
-        file-cache-filter-regexps))
-     dir-files)
-    (file-cache-add-file-list dir-files)))
+  (interactive "DAdd files from directory: ")
+  ;; Not an error, because otherwise we can't use load-paths that
+  ;; contain non-existent directories.
+  (if (not (file-accessible-directory-p directory))
+      (message "Directory %s does not exist" directory)
+    (let* ((dir       (expand-file-name directory))
+          (dir-files (directory-files dir t regexp))
+          )
+      ;; Filter out files we don't want to see
+      (mapcar
+       '(lambda (file)
+          (if (file-directory-p file)
+              (setq dir-files (delq file dir-files))
+           (mapcar
+            '(lambda (regexp)
+               (if (string-match regexp file)
+                   (setq dir-files (delq file dir-files))))
+            file-cache-filter-regexps)))
+       dir-files)
+      (file-cache-add-file-list dir-files))))
 
 (defun file-cache-add-directory-list (directory-list &optional regexp)
   "Add DIRECTORY-LIST (a list of directory names) to the file cache.
-If the optional REGEXP argument is non-nil, only files which match it 
-will be added to the cache. Note that the REGEXP is applied to the files 
+If the optional REGEXP argument is non-nil, only files which match it
+will be added to the cache. Note that the REGEXP is applied to the files
 in each directory, not to the directory list itself."
   (interactive "XAdd files from directory list: ")
-  (mapcar 
+  (mapcar
    '(lambda (dir) (file-cache-add-directory dir regexp))
    directory-list))
 
@@ -235,37 +310,48 @@ in each directory, not to the directory list itself."
 (defun file-cache-add-file (file)
   "Add FILE to the file cache."
   (interactive "fAdd File: ")
-  (let* ((file-name (file-name-nondirectory file))
-        (dir-name  (file-name-directory    file))
-        (the-entry (assoc file-name file-cache-alist))
-       )
-    ;; Does the entry exist already?
-    (if the-entry
-       (if (or (and (stringp (cdr the-entry))
-                    (string= dir-name (cdr the-entry)))
-               (and (listp (cdr the-entry))
-                    (member dir-name (cdr the-entry))))
-           nil
-         (setcdr the-entry (append (list dir-name) (cdr the-entry)))
-         )
-      ;; If not, add it to the cache
-      (setq file-cache-alist
-           (cons (cons file-name (list dir-name)) 
-                 file-cache-alist)))
-    ))
+  (if (not (file-exists-p file))
+      (message "Filecache: file %s does not exist" file)
+    (let* ((file-name (file-name-nondirectory file))
+          (dir-name  (file-name-directory    file))
+          (the-entry (assoc-string
+                      file-name file-cache-alist
+                      file-cache-ignore-case))
+          )
+      ;; Does the entry exist already?
+      (if the-entry
+         (if (or (and (stringp (cdr the-entry))
+                      (string= dir-name (cdr the-entry)))
+                 (and (listp (cdr the-entry))
+                      (member dir-name (cdr the-entry))))
+             nil
+           (setcdr the-entry (append (list dir-name) (cdr the-entry)))
+           )
+       ;; If not, add it to the cache
+       (setq file-cache-alist
+             (cons (cons file-name (list dir-name))
+                   file-cache-alist)))
+      )))
 
 (defun file-cache-add-directory-using-find (directory)
   "Use the `find' command to add files to the file cache.
 Find is run in DIRECTORY."
   (interactive "DAdd files under directory: ")
   (let ((dir (expand-file-name directory)))
+    (when (memq system-type '(windows-nt cygwin))
+      (if (eq file-cache-find-command-posix-flag 'not-defined)
+         (setq file-cache-find-command-posix-flag
+               (executable-command-find-posix-p file-cache-find-command))))
     (set-buffer (get-buffer-create file-cache-buffer))
     (erase-buffer)
-    (call-process file-cache-find-command nil 
+    (call-process file-cache-find-command nil
                  (get-buffer file-cache-buffer) nil
-                 dir "-name" 
-                 (if (memq system-type 
-                           (list 'windows-nt 'ms-dos)) "'*'" "*")
+                 dir "-name"
+                 (if (memq system-type '(windows-nt cygwin))
+                     (if file-cache-find-command-posix-flag
+                         "\\*"
+                       "'*'")
+                   "*")
                  "-print")
     (file-cache-add-from-file-cache-buffer)))
 
@@ -275,17 +361,41 @@ STRING is passed as an argument to the locate command."
   (interactive "sAdd files using locate string: ")
   (set-buffer (get-buffer-create file-cache-buffer))
   (erase-buffer)
-  (call-process file-cache-locate-command nil 
+  (call-process file-cache-locate-command nil
                (get-buffer file-cache-buffer) nil
                string)
   (file-cache-add-from-file-cache-buffer))
 
+(defun file-cache-add-directory-recursively  (dir &optional regexp)
+  "Adds DIR and any subdirectories to the file-cache.
+This function does not use any external programs
+If the optional REGEXP argument is non-nil, only files which match it
+will be added to the cache. Note that the REGEXP is applied to the files
+in each directory, not to the directory list itself."
+  (interactive "DAdd directory: ")
+  (require 'find-lisp)
+  (mapcar
+   (function
+    (lambda(file)
+      (or (file-directory-p file)
+         (let (filtered)
+           (mapcar
+            (function
+             (lambda(regexp)
+               (and (string-match regexp file)
+                    (setq filtered t))
+               ))
+            file-cache-filter-regexps)
+           filtered)
+         (file-cache-add-file file))))
+   (find-lisp-find-files dir (if regexp regexp "^"))))
+
 (defun file-cache-add-from-file-cache-buffer (&optional regexp)
   "Add any entries found in the file cache buffer.
 Each entry matches the regular expression `file-cache-buffer-default-regexp'
 or the optional REGEXP argument."
   (set-buffer file-cache-buffer)
-  (mapcar 
+  (mapcar
    (function (lambda (elt)
               (goto-char (point-min))
               (delete-matching-lines elt)))
@@ -293,10 +403,10 @@ or the optional REGEXP argument."
   (goto-char (point-min))
   (let ((full-filename))
     (while (re-search-forward
-           (or regexp file-cache-buffer-default-regexp) 
+           (or regexp file-cache-buffer-default-regexp)
            (point-max) t)
       (setq full-filename (buffer-substring-no-properties
-                     (match-beginning 0) (match-end 0))) 
+                     (match-beginning 0) (match-end 0)))
       (file-cache-add-file full-filename))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -313,8 +423,9 @@ or the optional REGEXP argument."
   "Delete FILE from the file cache."
   (interactive
    (list (completing-read "Delete file from cache: " file-cache-alist)))
-  (setq file-cache-alist 
-       (delq (assoc file file-cache-alist) file-cache-alist)))
+  (setq file-cache-alist
+       (delq (assoc-string file file-cache-alist file-cache-ignore-case)
+             file-cache-alist)))
 
 (defun file-cache-delete-file-list (file-list)
   "Delete FILE-LIST (a list of files) from the file cache."
@@ -325,26 +436,27 @@ or the optional REGEXP argument."
   "Delete files matching REGEXP from the file cache."
   (interactive "sRegexp: ")
   (let ((delete-list))
-    (mapcar '(lambda (elt) 
+    (mapcar '(lambda (elt)
               (and (string-match regexp (car elt))
                    (setq delete-list (cons (car elt) delete-list))))
            file-cache-alist)
     (file-cache-delete-file-list delete-list)
-    (message "Deleted %d files from file cache" (length delete-list))))
+    (message "Filecache: deleted %d files from file cache"
+             (length delete-list))))
 
 (defun file-cache-delete-directory (directory)
   "Delete DIRECTORY from the file cache."
   (interactive "DDelete directory from file cache: ")
   (let ((dir (expand-file-name directory))
        (result 0))
-    (mapcar 
-     '(lambda (entry) 
+    (mapcar
+     '(lambda (entry)
        (if (file-cache-do-delete-directory dir entry)
            (setq result (1+ result))))
      file-cache-alist)
     (if (zerop result)
-       (error "No entries containing %s found in cache" directory)
-      (message "Deleted %d entries" result))))
+       (error "Filecache: no entries containing %s found in cache" directory)
+      (message "Filecache: deleted %d entries" result))))
 
 (defun file-cache-do-delete-directory (dir entry)
   (let ((directory-list (cdr entry))
@@ -352,7 +464,7 @@ or the optional REGEXP argument."
        )
     (and (member directory directory-list)
         (if (equal 1 (length directory-list))
-            (setq file-cache-alist 
+            (setq file-cache-alist
                   (delq entry file-cache-alist))
           (setcdr entry (delete directory directory-list)))
         )
@@ -369,30 +481,32 @@ or the optional REGEXP argument."
 
 ;; Returns the name of a directory for a file in the cache
 (defun file-cache-directory-name  (file)
-  (let* ((directory-list (cdr (assoc file file-cache-alist)))
+  (let* ((directory-list (cdr (assoc-string
+                              file file-cache-alist
+                              file-cache-ignore-case)))
         (len            (length directory-list))
         (directory)
         (num)
         )
     (if (not (listp directory-list))
-       (error "Unknown type in file-cache-alist for key %s" file))
-    (cond 
+       (error "Filecache: unknown type in file-cache-alist for key %s" file))
+    (cond
      ;; Single element
      ((eq 1 len)
       (setq directory (elt directory-list 0)))
      ;; No elements
      ((eq 0 len)
-      (error "No directory found for key %s" file))
+      (error "Filecache: no directory found for key %s" file))
      ;; Multiple elements
      (t
-      (let* ((minibuffer-dir (file-name-directory (buffer-string)))
+      (let* ((minibuffer-dir (file-name-directory (minibuffer-contents)))
             (dir-list       (member minibuffer-dir directory-list))
             )
        (setq directory
              ;; If the directory is in the list, return the next element
              ;; Otherwise, return the first element
-             (if dir-list 
-                 (or (elt directory-list 
+             (if dir-list
+                 (or (elt directory-list
                           (setq num (1+ (- len (length dir-list)))))
                      (elt directory-list (setq num 0)))
                (elt directory-list (setq num 0))))
@@ -408,7 +522,7 @@ or the optional REGEXP argument."
 (defun file-cache-file-name  (file)
   (let ((directory (file-cache-directory-name file)))
     (concat directory file)))
+
 ;; Return a canonical directory for comparison purposes.
 ;; Such a directory ends with a forward slash.
 (defun file-cache-canonical-directory (dir)
@@ -423,10 +537,10 @@ or the optional REGEXP argument."
 
 ;; The prefix argument works around a bug in the minibuffer completion.
 ;; The completion function doesn't distinguish between the states:
-;; 
+;;
 ;;   "Multiple completions of name" (eg, Makefile, Makefile.in)
 ;;   "Name available in multiple directories" (/tmp/Makefile, ~me/Makefile)
-;;   
+;;
 ;; The default is to do the former; a prefix arg forces the latter.
 
 ;;;###autoload
@@ -434,30 +548,30 @@ or the optional REGEXP argument."
   "Complete a filename in the minibuffer using a preloaded cache.
 Filecache does two kinds of substitution: it completes on names in
 the cache, and, once it has found a unique name, it cycles through
-the directories that the name is available in.  With a prefix argument, 
-the name is considered already unique; only the second substitution 
+the directories that the name is available in.  With a prefix argument,
+the name is considered already unique; only the second substitution
 \(directories) is done."
-  (interactive "P") 
-  (let* 
+  (interactive "P")
+  (let*
       (
-       (completion-ignore-case nil)
-       (case-fold-search       nil)
-       (string                 (file-name-nondirectory (buffer-string)))
+       (completion-ignore-case file-cache-completion-ignore-case)
+       (case-fold-search       file-cache-case-fold-search)
+       (string                 (file-name-nondirectory (minibuffer-contents)))
        (completion-string      (try-completion string file-cache-alist))
        (completion-list)
        (len)
        (file-cache-string)
        )
-    (cond 
+    (cond
      ;; If it's the only match, replace the original contents
      ((or arg (eq completion-string t))
       (setq file-cache-string (file-cache-file-name string))
-      (if (string= file-cache-string (buffer-string))
+      (if (string= file-cache-string (minibuffer-contents))
          (file-cache-temp-minibuffer-message file-cache-sole-match-message)
-       (erase-buffer)
-       (insert-string file-cache-string)
+       (delete-minibuffer-contents)
+       (insert file-cache-string)
        (if file-cache-multiple-directory-message
-           (file-cache-temp-minibuffer-message 
+           (file-cache-temp-minibuffer-message
             file-cache-multiple-directory-message))
       ))
 
@@ -466,12 +580,13 @@ the name is considered already unique; only the second substitution
       ;; If we've already inserted a unique string, see if the user
       ;; wants to use that one
       (if (and (string= string completion-string)
-              (assoc string file-cache-alist))
+              (assoc-string string file-cache-alist
+                            file-cache-ignore-case))
          (if (and (eq last-command this-command)
                   (string= file-cache-last-completion completion-string))
-             (progn 
-               (erase-buffer)
-               (insert-string (file-cache-file-name completion-string))  
+             (progn
+               (delete-minibuffer-contents)
+               (insert (file-cache-file-name completion-string))
                (setq file-cache-last-completion nil)
                )
            (file-cache-temp-minibuffer-message file-cache-non-unique-message)
@@ -483,29 +598,29 @@ the name is considered already unique; only the second substitution
        (if (> len 1)
            (progn
              (goto-char (point-max))
-             (insert-string 
+             (insert
               (substring completion-string (length string)))
              ;; Add our own setup function to the Completions Buffer
              (let ((completion-setup-hook
-                  (reverse 
+                  (reverse
                    (append (list 'file-cache-completion-setup-function)
                            completion-setup-hook)))
                    )
                (with-output-to-temp-buffer file-cache-completions-buffer
-                 (display-completion-list completion-list))
+                 (display-completion-list completion-list string))
                )
              )
          (setq file-cache-string (file-cache-file-name completion-string))
-         (if (string= file-cache-string (buffer-string))
-             (file-cache-temp-minibuffer-message 
+         (if (string= file-cache-string (minibuffer-contents))
+             (file-cache-temp-minibuffer-message
               file-cache-sole-match-message)
-           (erase-buffer)
-           (insert-string file-cache-string)
+           (delete-minibuffer-contents)
+           (insert file-cache-string)
            (if file-cache-multiple-directory-message
-               (file-cache-temp-minibuffer-message 
+               (file-cache-temp-minibuffer-message
                 file-cache-multiple-directory-message)))
          )))
-          
+
      ;; No match
      ((eq completion-string nil)
       (file-cache-temp-minibuffer-message file-cache-no-match-message))
@@ -535,11 +650,11 @@ the name is considered already unique; only the second substitution
 
   (if file-cache-completions-keymap
       nil
-    (setq file-cache-completions-keymap 
+    (setq file-cache-completions-keymap
          (copy-keymap completion-list-mode-map))
-    (define-key file-cache-completions-keymap [mouse-2] 
-      'file-cache-mouse-choose-completion) 
-    (define-key file-cache-completions-keymap "\C-m"    
+    (define-key file-cache-completions-keymap [mouse-2]
+      'file-cache-mouse-choose-completion)
+    (define-key file-cache-completions-keymap "\C-m"
       'file-cache-choose-completion))
 
     (use-local-map file-cache-completions-keymap)
@@ -565,17 +680,95 @@ the name is considered already unique; only the second substitution
     )
   )
 
+(defun file-cache-complete  ()
+  "Complete the word at point, using the filecache."
+  (interactive)
+  (let (start pattern completion all)
+    (save-excursion
+      (skip-syntax-backward "^\"")
+      (setq start (point)))
+    (setq pattern    (buffer-substring-no-properties start (point)))
+    (setq completion (try-completion  pattern file-cache-alist))
+    (setq all        (all-completions pattern file-cache-alist nil))
+    (cond ((eq completion t))
+         ((null completion)
+          (message "Can't find completion for \"%s\"" pattern)
+          (ding))
+         ((not (string= pattern completion))
+          (delete-region start (point))
+          (insert completion)
+          )
+         (t
+          (with-output-to-temp-buffer "*Completions*"
+            (display-completion-list all pattern))
+          ))
+    ))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Show parts of the cache
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun file-cache-files-matching-internal (regexp)
+  "Output a list of files whose names (not including directories)
+match REGEXP."
+  (let ((results))
+    (mapcar
+     (function
+      (lambda(cache-element)
+       (and (string-match regexp
+                          (elt cache-element 0))
+            (if results
+                (nconc results (list (elt cache-element 0)))
+              (setq results (list (elt cache-element 0)))))))
+     file-cache-alist)
+    results))
+
+(defun file-cache-files-matching (regexp)
+  "Output a list of files whose names (not including directories)
+match REGEXP."
+  (interactive "sFind files matching regexp: ")
+  (let ((results
+        (file-cache-files-matching-internal regexp))
+       buf)
+    (set-buffer
+     (setq buf (get-buffer-create
+               "*File Cache Files Matching*")))
+    (erase-buffer)
+    (insert
+     (mapconcat
+      'identity
+      results
+      "\n"))
+    (goto-char (point-min))
+    (display-buffer buf)))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Debugging functions
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defun file-cache-debug-read-from-minibuffer (file)
   "Debugging function."
-  (interactive 
+  (interactive
    (list (completing-read "File Cache: " file-cache-alist)))
-  (message "%s" (assoc file file-cache-alist))
+  (message "%s" (assoc-string file file-cache-alist
+                             file-cache-ignore-case))
   )
 
+(defun file-cache-display  ()
+  "Display the file cache."
+  (interactive)
+  (let ((buf "*File Cache Contents*"))
+    (with-current-buffer
+       (get-buffer-create buf)
+      (erase-buffer)
+      (mapcar
+       (function
+      (lambda(item)
+       (insert (nth 1 item) (nth 0 item) "\n")))
+    file-cache-alist)
+      (pop-to-buffer buf)
+    )))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Keybindings
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -586,4 +779,5 @@ the name is considered already unique; only the second substitution
 
 (provide 'filecache)
 
+;;; arch-tag: 433d3ca4-4af2-47ce-b2cf-1f727460f538
 ;;; filecache.el ends here