]> code.delx.au - gnu-emacs/blobdiff - lisp/find-file.el
*** empty log message ***
[gnu-emacs] / lisp / find-file.el
index d59f10d22bd68638111ae94cb5acf68a850e58d4..b4db74da7561f9846324c6eaa7f7e4684f451773 100644 (file)
@@ -4,7 +4,7 @@
 ;; Maintainer: FSF
 ;; Keywords: c, matching, tools
 
-;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 2002 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
 ;;
 ;; THERE ARE FIVE AVAILABLE HOOKS, called in this order if non-nil:
 ;;
-;; - ff-pre-find-hooks     - called before the search for the other file starts
-;; - ff-not-found-hooks    - called when the other file could not be found
-;; - ff-pre-load-hooks     - called just before the other file is 'loaded'
-;; - ff-file-created-hooks - called when the other file is created
-;; - ff-post-load-hooks    - called just after the other file is 'loaded'
+;; - ff-pre-find-hook     - called before the search for the other file starts
+;; - ff-not-found-hook    - called when the other file could not be found
+;; - ff-pre-load-hook     - called just before the other file is 'loaded'
+;; - ff-file-created-hook - called when the other file is created
+;; - ff-post-load-hook    - called just after the other file is 'loaded'
 ;;
-;; The *load-hooks allow you to place point where you want it in the other
+;; The *load-hook allow you to place point where you want it in the other
 ;; file.
 
 ;; CREDITS:
   :link '(emacs-commentary-link "find-file")
   :group 'find-file)
 
-(defcustom ff-pre-find-hooks nil
+(defcustom ff-pre-find-hook nil
   "*List of functions to be called before the search for the file starts."
   :type 'hook
   :group 'ff)
 
-(defcustom ff-pre-load-hooks nil
+(defcustom ff-pre-load-hook nil
   "*List of functions to be called before the other file is loaded."
   :type 'hook
   :group 'ff)
 
-(defcustom ff-post-load-hooks nil
+(defcustom ff-post-load-hook nil
   "*List of functions to be called after the other file is loaded."
   :type 'hook
   :group 'ff)
 
-(defcustom ff-not-found-hooks nil
+(defcustom ff-not-found-hook nil
   "*List of functions to be called if the other file could not be found."
   :type 'hook
   :group 'ff)
 
-(defcustom ff-file-created-hooks nil
+(defcustom ff-file-created-hook nil
   "*List of functions to be called if the other file needs to be created."
   :type 'hook
   :group 'ff)
@@ -202,6 +202,7 @@ Specifies how to recognise special constructs such as include files
 etc. and an associated method for extracting the filename from that
 construct.")
 
+(defvaralias 'ff-related-file-alist 'ff-other-file-alist)
 (defcustom ff-other-file-alist 'cc-other-file-alist
   "*Alist of extensions to find given the current file's extension.
 
@@ -284,11 +285,11 @@ is created with the first matching extension (`.cc' yields `.hh')."
 ;; No user definable variables beyond this point!
 ;; ==============================================
 
-(make-variable-buffer-local 'ff-pre-find-hooks)
-(make-variable-buffer-local 'ff-pre-load-hooks)
-(make-variable-buffer-local 'ff-post-load-hooks)
-(make-variable-buffer-local 'ff-not-found-hooks)
-(make-variable-buffer-local 'ff-file-created-hooks)
+(make-variable-buffer-local 'ff-pre-find-hook)
+(make-variable-buffer-local 'ff-pre-load-hook)
+(make-variable-buffer-local 'ff-post-load-hook)
+(make-variable-buffer-local 'ff-not-found-hook)
+(make-variable-buffer-local 'ff-file-created-hook)
 (make-variable-buffer-local 'ff-case-fold-search)
 (make-variable-buffer-local 'ff-always-in-other-window)
 (make-variable-buffer-local 'ff-ignore-include)
@@ -311,6 +312,9 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window."
     (ff-find-the-other-file in-other-window)
     (setq ff-ignore-include ignore)))
 
+;;;###autoload
+(defalias 'ff-find-related-file 'ff-find-other-file)
+
 ;;;###autoload
 (defun ff-find-other-file (&optional in-other-window ignore-include)
   "Find the header or source file corresponding to this file.
@@ -350,19 +354,19 @@ Variables of interest include:
    List of directories searched through with each extension specified in
    `ff-other-file-alist' that matches this file's extension.
 
- - `ff-pre-find-hooks'
+ - `ff-pre-find-hook'
    List of functions to be called before the search for the file starts.
 
- - `ff-pre-load-hooks'
+ - `ff-pre-load-hook'
    List of functions to be called before the other file is loaded.
 
- - `ff-post-load-hooks'
+ - `ff-post-load-hook'
    List of functions to be called after the other file is loaded.
 
- - `ff-not-found-hooks'
+ - `ff-not-found-hook'
    List of functions to be called if the other file could not be found.
 
- - `ff-file-created-hooks'
+ - `ff-file-created-hook'
    List of functions to be called if the other file has been created."
   (interactive "P")
   (let ((ignore ff-ignore-include))
@@ -394,8 +398,7 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window."
         dirs            ;; local value of ff-search-directories
         no-match)       ;; whether we know about this kind of file
 
-    (if ff-pre-find-hooks
-        (run-hooks 'ff-pre-find-hooks))
+    (run-hooks 'ff-pre-find-hook 'ff-pre-find-hooks)
 
     (message "Working...")
 
@@ -422,8 +425,7 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window."
                          (buffer-file-name)
                        "/none.none"))
 
-      (string-match ".*/\\(.+\\)$" pathname)
-      (setq fname (substring pathname (match-beginning 1) (match-end 1))
+      (setq fname (file-name-nondirectory pathname)
             no-match nil
             match (car alist))
 
@@ -487,8 +489,7 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window."
 
        ((not found)                ;; could not find the other file
 
-        (if ff-not-found-hooks     ;; run the hooks
-            (run-hooks 'ff-not-found-hooks))
+       (run-hooks 'ff-not-found-hook 'ff-not-found-hooks)
 
         (cond
          (ff-always-try-to-create  ;; try to create the file
@@ -515,6 +516,103 @@ If optional IN-OTHER-WINDOW is non-nil, find the file in another window."
 
     found))                        ;; return buffer-name or filename
 
+(defun ff-other-file-name ()
+  "Return name of the header or source file corresponding to the current file.
+Being on a `#include' line pulls in that file, but see the help on
+the `ff-ignore-include' variable."
+
+  (let (match           ;; matching regexp for this file
+        suffixes        ;; set of replacing regexps for the matching regexp
+        action          ;; function to generate the names of the other files
+        fname           ;; basename of this file
+        pos             ;; where we start matching filenames
+        stub            ;; name of the file without extension
+        alist           ;; working copy of the list of file extensions
+        pathname        ;; the pathname of the file or the #include line
+        default-name    ;; file we should create if none found
+        format          ;; what we have to match
+        found           ;; name of the file or buffer found - nil if none
+        dirs            ;; local value of ff-search-directories
+        no-match)       ;; whether we know about this kind of file
+
+    (message "Working...")
+
+    (setq dirs
+          (if (symbolp ff-search-directories)
+              (ff-list-replace-env-vars (symbol-value ff-search-directories))
+            (ff-list-replace-env-vars ff-search-directories)))
+
+    (save-excursion
+      (beginning-of-line 1)
+      (setq fname (ff-treat-as-special)))
+
+    (cond
+     ((and (not ff-ignore-include) fname)
+      (setq default-name fname)
+      (setq found (ff-get-file-name dirs fname nil)))
+
+     ;; let's just get the corresponding file
+     (t
+      (setq alist (if (symbolp ff-other-file-alist)
+                      (symbol-value ff-other-file-alist)
+                    ff-other-file-alist)
+            pathname (if (buffer-file-name)
+                         (buffer-file-name)
+                       "/none.none"))
+
+      (setq fname (file-name-nondirectory pathname)
+            no-match nil
+            match (car alist))
+
+      ;; find the table entry corresponding to this file
+      (setq pos (ff-string-match (car match) fname))
+      (while (and match (if (and pos (>= pos 0)) nil (not pos)))
+        (setq alist (cdr alist))
+        (setq match (car alist))
+        (setq pos (ff-string-match (car match) fname)))
+
+      ;; no point going on if we haven't found anything
+      (if (not match)
+          (setq no-match t)
+
+        ;; otherwise, suffixes contains what we need
+        (setq suffixes (car (cdr match))
+              action (car (cdr match))
+              found nil)
+
+        ;; if we have a function to generate new names,
+        ;; invoke it with the name of the current file
+        (if (and (atom action) (fboundp action))
+            (progn
+              (setq suffixes (funcall action (buffer-file-name))
+                    match (cons (car match) (list suffixes))
+                    stub nil
+                    default-name (car suffixes)))
+
+          ;; otherwise build our filename stub
+          (cond
+
+           ;; get around the problem that 0 and nil both mean false!
+           ((= pos 0)
+            (setq format "")
+            (setq stub "")
+            )
+
+           (t
+            (setq format (concat "\\(.+\\)" (car match)))
+            (string-match format fname)
+            (setq stub (substring fname (match-beginning 1) (match-end 1)))
+            ))
+
+          ;; if we find nothing, we should try to get a file like this one
+          (setq default-name
+                (concat stub (car (car (cdr match))))))
+
+        ;; do the real work - find the file
+        (setq found
+              (ff-get-file-name dirs stub suffixes)))))
+    found))                        ;; return buffer-name or filename
+
 (defun ff-get-file (search-dirs filename &optional suffix-list other-window)
   "Find a file in the SEARCH-DIRS with the given FILENAME (or filename stub).
 If (optional) SUFFIX-LIST is nil, search for fname, otherwise search
@@ -727,20 +825,17 @@ and on the global variable `ff-always-in-other-window'.
 F1 and F2 are typically `find-file' / `find-file-other-window'
 or `switch-to-buffer' / `switch-to-buffer-other-window' function pairs.
 
-If optional NEW-FILE is t, then a special hook (`ff-file-created-hooks') is
-called before `ff-post-load-hooks'."
-  (if ff-pre-load-hooks
-      (run-hooks 'ff-pre-load-hooks))
+If optional NEW-FILE is t, then a special hook (`ff-file-created-hook') is
+called before `ff-post-load-hook'."
+  (run-hooks 'ff-pre-load-hook 'ff-pre-load-hooks)
   (if (or
        (and in-other-window (not ff-always-in-other-window))
        (and (not in-other-window) ff-always-in-other-window))
       (funcall f2 file)
     (funcall f1 file))
   (if new-file
-      (if ff-file-created-hooks
-          (run-hooks 'ff-file-created-hooks)))
-  (if ff-post-load-hooks
-      (run-hooks 'ff-post-load-hooks)))
+      (run-hooks 'ff-file-created-hook 'ff-file-created-hooks))
+  (run-hooks 'ff-post-load-hook 'ff-post-load-hooks))
 
 (defun ff-find-file (file &optional in-other-window new-file)
   "Like `find-file', but may show the file in another window."
@@ -849,9 +944,9 @@ and the name of the file passed in."
 
 (defvar ff-function-name nil "Name of the function we are in.")
 
-(eval-when-compile (require 'ada-mode))
+;(eval-when-compile (require 'ada-mode))
 
-;; bind with (setq ff-pre-load-hooks 'ff-which-function-are-we-in)
+;; bind with (setq ff-pre-load-hook 'ff-which-function-are-we-in)
 ;;
 (defun ff-which-function-are-we-in ()
   "Return the name of the function whose definition/declaration point is in.
@@ -869,7 +964,7 @@ Also remember that name in `ff-function-name'."
                                                    (match-end 0)))
         ))))
 
-;; bind with (setq ff-post-load-hooks 'ff-set-point-accordingly)
+;; bind with (setq ff-post-load-hook 'ff-set-point-accordingly)
 ;;
 (defun ff-set-point-accordingly ()
   "Find the function specified in `ff-function-name'.