comparison lisp/ffap.el @ 88155:d7ddb3e565de

sync with trunk
author Henrik Enberg <henrik.enberg@telia.com>
date Mon, 16 Jan 2006 00:03:54 +0000
parents 3738a81ff66f
children
comparison
equal deleted inserted replaced
88154:8ce476d3ba36 88155:d7ddb3e565de
1 ;;; ffap.el --- find file (or url) at point 1 ;;; ffap.el --- find file (or url) at point
2 ;; 2
3 ;; Copyright (C) 1995, 96, 97, 2000 Free Software Foundation, Inc. 3 ;; Copyright (C) 1995, 1996, 1997, 2000, 2002, 2003, 2004,
4 ;; 4 ;; 2005 Free Software Foundation, Inc.
5
5 ;; Author: Michelangelo Grigni <mic@mathcs.emory.edu> 6 ;; Author: Michelangelo Grigni <mic@mathcs.emory.edu>
7 ;; Maintainer: Rajesh Vaidheeswarran <rv@gnu.org>
6 ;; Created: 29 Mar 1993 8 ;; Created: 29 Mar 1993
7 ;; Keywords: files, hypermedia, matching, mouse, convenience 9 ;; Keywords: files, hypermedia, matching, mouse, convenience
8 ;; X-URL: ftp://ftp.mathcs.emory.edu/pub/mic/emacs/ 10 ;; X-URL: ftp://ftp.mathcs.emory.edu/pub/mic/emacs/
9 11
10 ;; This file is part of GNU Emacs. 12 ;; This file is part of GNU Emacs.
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details. 22 ;; GNU General Public License for more details.
21 23
22 ;; You should have received a copy of the GNU General Public License 24 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the 25 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, 26 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02111-1307, USA. 27 ;; Boston, MA 02110-1301, USA.
26 28
27 29
28 ;;; Commentary: 30 ;;; Commentary:
29 ;; 31 ;;
30 ;; Command find-file-at-point replaces find-file. With a prefix, it 32 ;; Command find-file-at-point replaces find-file. With a prefix, it
39 ;; 41 ;;
40 ;; (ffap-bindings) ; do default key bindings 42 ;; (ffap-bindings) ; do default key bindings
41 ;; 43 ;;
42 ;; ffap-bindings makes the following global key bindings: 44 ;; ffap-bindings makes the following global key bindings:
43 ;; 45 ;;
44 ;; C-x C-f find-file-at-point (abbreviated as ffap) 46 ;; C-x C-f find-file-at-point (abbreviated as ffap)
45 ;; C-x d dired-at-point 47 ;; C-x C-r ffap-read-only
46 ;; C-x 4 f ffap-other-window 48 ;; C-x C-v ffap-alternate-file
47 ;; C-x 5 f ffap-other-frame 49 ;;
50 ;; C-x d dired-at-point
51 ;; C-x C-d ffap-list-directory
52 ;;
53 ;; C-x 4 f ffap-other-window
54 ;; C-x 4 r ffap-read-only-other-window
55 ;; C-x 4 d ffap-dired-other-window
56 ;;
57 ;; C-x 5 f ffap-other-frame
58 ;; C-x 5 r ffap-read-only-other-frame
59 ;; C-x 5 d ffap-dired-other-frame
60 ;;
48 ;; S-mouse-3 ffap-at-mouse 61 ;; S-mouse-3 ffap-at-mouse
49 ;; C-S-mouse-3 ffap-menu 62 ;; C-S-mouse-3 ffap-menu
50 ;; 63 ;;
51 ;; ffap-bindings also adds hooks to make the following local bindings 64 ;; ffap-bindings also adds hooks to make the following local bindings
52 ;; in vm, gnus, and rmail: 65 ;; in vm, gnus, and rmail:
63 ;; option variables. In particular, if ffap is slow, try these: 76 ;; option variables. In particular, if ffap is slow, try these:
64 ;; 77 ;;
65 ;; (setq ffap-alist nil) ; faster, dumber prompting 78 ;; (setq ffap-alist nil) ; faster, dumber prompting
66 ;; (setq ffap-machine-p-known 'accept) ; no pinging 79 ;; (setq ffap-machine-p-known 'accept) ; no pinging
67 ;; (setq ffap-url-regexp nil) ; disable URL features in ffap 80 ;; (setq ffap-url-regexp nil) ; disable URL features in ffap
81 ;; (setq ffap-shell-prompt-regexp nil) ; disable shell prompt stripping
68 ;; 82 ;;
69 ;; ffap uses `browse-url' (if found, else `w3-fetch') to fetch URL's. 83 ;; ffap uses `browse-url' (if found, else `w3-fetch') to fetch URL's.
70 ;; For a hairier `ffap-url-fetcher', try ffap-url.el (same ftp site). 84 ;; For a hairier `ffap-url-fetcher', try ffap-url.el (same ftp site).
71 ;; Also, you can add `ffap-menu-rescan' to various hooks to fontify 85 ;; Also, you can add `ffap-menu-rescan' to various hooks to fontify
72 ;; the file and URL references within a buffer. 86 ;; the file and URL references within a buffer.
78 ;; which also has some old examples and commentary from ffap 1.5. 92 ;; which also has some old examples and commentary from ffap 1.5.
79 93
80 94
81 ;;; Todo list: 95 ;;; Todo list:
82 ;; * use kpsewhich 96 ;; * use kpsewhich
83 ;; * let "/path/file#key" jump to key (tag or regexp) in /path/file 97 ;; * let "/dir/file#key" jump to key (tag or regexp) in /dir/file
84 ;; * find file of symbol if TAGS is loaded (like above) 98 ;; * find file of symbol if TAGS is loaded (like above)
85 ;; * break long menus into multiple panes (like imenu?) 99 ;; * break long menus into multiple panes (like imenu?)
86 ;; * notice node in "(dired)Virtual Dired" (quotes, parentheses, whitespace) 100 ;; * notice node in "(dired)Virtual Dired" (quotes, parentheses, whitespace)
87 ;; * notice "machine.dom blah blah blah path/file" (how?) 101 ;; * notice "machine.dom blah blah blah dir/file" (how?)
88 ;; * as w3 becomes standard, rewrite to rely more on its functions 102 ;; * as w3 becomes standard, rewrite to rely more on its functions
89 ;; * regexp options for ffap-string-at-point, like font-lock (MCOOK) 103 ;; * regexp options for ffap-string-at-point, like font-lock (MCOOK)
90 ;; * v19: could replace `ffap-locate-file' with a quieter `locate-library' 104 ;; * v19: could replace `ffap-locate-file' with a quieter `locate-library'
91 ;; * handle "$(VAR)" in Makefiles 105 ;; * handle "$(VAR)" in Makefiles
92 ;; * use the font-lock machinery 106 ;; * use the font-lock machinery
118 Otherwise return nil (or the optional DEFAULT value)." 132 Otherwise return nil (or the optional DEFAULT value)."
119 ;; Bug: (ffap-soft-value "nil" 5) --> 5 133 ;; Bug: (ffap-soft-value "nil" 5) --> 5
120 (let ((sym (intern-soft name))) 134 (let ((sym (intern-soft name)))
121 (if (and sym (boundp sym)) (symbol-value sym) default))) 135 (if (and sym (boundp sym)) (symbol-value sym) default)))
122 136
137 (defcustom ffap-shell-prompt-regexp
138 ;; This used to test for some shell prompts that don't have a space
139 ;; after them. The common root shell prompt (#) is not listed since it
140 ;; also doubles up as a valid URL character.
141 "[$%><]*"
142 "Paths matching this regexp are stripped off the shell prompt
143 If nil, ffap doesn't do shell prompt stripping."
144 :type '(choice (const :tag "Disable" nil)
145 (const :tag "Standard" "[$%><]*")
146 regexp)
147 :group 'ffap)
148
123 (defcustom ffap-ftp-regexp 149 (defcustom ffap-ftp-regexp
124 ;; This used to test for ange-ftp or efs being present, but it should be 150 ;; This used to test for ange-ftp or efs being present, but it should be
125 ;; harmless (and simpler) to give it this value unconditionally. 151 ;; harmless (and simpler) to give it this value unconditionally.
126 "\\`/[^/:]+:" 152 "\\`/[^/:]+:"
127 "*Paths matching this regexp are treated as remote ftp paths by ffap. 153 "*File names matching this regexp are treated as remote ffap.
128 If nil, ffap neither recognizes nor generates such paths." 154 If nil, ffap neither recognizes nor generates such names."
129 :type '(choice (const :tag "Disable" nil) 155 :type '(choice (const :tag "Disable" nil)
130 (const :tag "Standard" "\\`/[^/:]+:") 156 (const :tag "Standard" "\\`/[^/:]+:")
131 regexp) 157 regexp)
132 :group 'ffap) 158 :group 'ffap)
133 159
134 (defcustom ffap-url-unwrap-local t 160 (defcustom ffap-url-unwrap-local t
135 "*If non-nil, convert `file:' url to local path before prompting." 161 "*If non-nil, convert `file:' URL to local file name before prompting."
136 :type 'boolean 162 :type 'boolean
137 :group 'ffap) 163 :group 'ffap)
138 164
139 (defcustom ffap-url-unwrap-remote t 165 (defcustom ffap-url-unwrap-remote t
140 "*If non-nil, convert `ftp:' url to remote path before prompting. 166 "*If non-nil, convert `ftp:' URL to remote file name before prompting.
141 This is ignored if `ffap-ftp-regexp' is nil." 167 This is ignored if `ffap-ftp-regexp' is nil."
142 :type 'boolean 168 :type 'boolean
143 :group 'ffap) 169 :group 'ffap)
144 170
145 (defcustom ffap-ftp-default-user "anonymous" 171 (defcustom ffap-ftp-default-user "anonymous"
146 "*User name in ftp paths generated by `ffap-host-to-path'. 172 "*User name in ftp file names generated by `ffap-host-to-path'.
147 Note this name may be omitted if it equals the default 173 Note this name may be omitted if it equals the default
148 \(either `efs-default-user' or `ange-ftp-default-user'\)." 174 \(either `efs-default-user' or `ange-ftp-default-user'\)."
149 :type 'string 175 :type 'string
150 :group 'ffap) 176 :group 'ffap)
151 177
152 (defcustom ffap-rfs-regexp 178 (defcustom ffap-rfs-regexp
153 ;; Remote file access built into file system? HP rfa or Andrew afs: 179 ;; Remote file access built into file system? HP rfa or Andrew afs:
154 "\\`/\\(afs\\|net\\)/." 180 "\\`/\\(afs\\|net\\)/."
155 ;; afs only: (and (file-exists-p "/afs") "\\`/afs/.") 181 ;; afs only: (and (file-exists-p "/afs") "\\`/afs/.")
156 "*Matching paths are treated as remote. nil to disable." 182 "*Matching file names are treated as remote. Use nil to disable."
157 :type 'regexp 183 :type 'regexp
158 :group 'ffap) 184 :group 'ffap)
159 185
160 (defvar ffap-url-regexp 186 (defvar ffap-url-regexp
161 ;; Could just use `url-nonrelative-link' of w3, if loaded. 187 ;; Could just use `url-nonrelative-link' of w3, if loaded.
186 ;; those features interesting but not clear winners (a matter of 212 ;; those features interesting but not clear winners (a matter of
187 ;; personal taste) I try to leave options to enable them. Read 213 ;; personal taste) I try to leave options to enable them. Read
188 ;; through this section for features that you like, put an appropriate 214 ;; through this section for features that you like, put an appropriate
189 ;; enabler in your .emacs file. 215 ;; enabler in your .emacs file.
190 216
191 (defcustom ffap-dired-wildcards nil 217 (defcustom ffap-dired-wildcards "[*?][^/]*\\'"
192 ;; Suggestion from RHOGEE, 07 Jul 1994. Disabled, dired is still
193 ;; available by "C-x C-d <pattern>", and valid filenames may
194 ;; sometimes contain wildcard characters.
195 "*A regexp matching filename wildcard characters, or nil. 218 "*A regexp matching filename wildcard characters, or nil.
219
196 If `find-file-at-point' gets a filename matching this pattern, 220 If `find-file-at-point' gets a filename matching this pattern,
197 it passes it on to `dired' instead of `find-file'." 221 and `ffap-pass-wildcards-to-dired' is nil, it passes it on to
222 `find-file' with non-nil WILDCARDS argument, which expands
223 wildcards and visits multiple files. To visit a file whose name
224 contains wildcard characters you can suppress wildcard expansion
225 by setting `find-file-wildcards'. If `find-file-at-point' gets a
226 filename matching this pattern and `ffap-pass-wildcards-to-dired'
227 is non-nil, it passes it on to `dired'.
228
229 If `dired-at-point' gets a filename matching this pattern,
230 it passes it on to `dired'."
198 :type '(choice (const :tag "Disable" nil) 231 :type '(choice (const :tag "Disable" nil)
199 (const :tag "Enable" "[*?][^/]*\\'") 232 (const :tag "Enable" "[*?][^/]*\\'")
200 ;; regexp -- probably not useful 233 ;; regexp -- probably not useful
201 ) 234 )
235 :group 'ffap)
236
237 (defcustom ffap-pass-wildcards-to-dired nil
238 "*If non-nil, pass filenames matching `ffap-dired-wildcards' to dired."
239 :type 'boolean
202 :group 'ffap) 240 :group 'ffap)
203 241
204 (defcustom ffap-newfile-prompt nil 242 (defcustom ffap-newfile-prompt nil
205 ;; Suggestion from RHOGEE, 11 Jul 1994. Disabled, I think this is 243 ;; Suggestion from RHOGEE, 11 Jul 1994. Disabled, I think this is
206 ;; better handled by `find-file-not-found-hooks'. 244 ;; better handled by `find-file-not-found-hooks'.
219 (defcustom ffap-file-finder 'find-file 257 (defcustom ffap-file-finder 'find-file
220 "*The command called by `find-file-at-point' to find a file." 258 "*The command called by `find-file-at-point' to find a file."
221 :type 'function 259 :type 'function
222 :group 'ffap) 260 :group 'ffap)
223 (put 'ffap-file-finder 'risky-local-variable t) 261 (put 'ffap-file-finder 'risky-local-variable t)
262
263 (defcustom ffap-directory-finder 'dired
264 "*The command called by `dired-at-point' to find a directory."
265 :type 'function
266 :group 'ffap)
267 (put 'ffap-directory-finder 'risky-local-variable t)
224 268
225 (defcustom ffap-url-fetcher 269 (defcustom ffap-url-fetcher
226 (if (fboundp 'browse-url) 270 (if (fboundp 'browse-url)
227 'browse-url ; rely on browse-url-browser-function 271 'browse-url ; rely on browse-url-browser-function
228 'w3-fetch) 272 'w3-fetch)
432 (t (signal (car error) (cdr error)))))))))))) 476 (t (signal (car error) (cdr error))))))))))))
433 477
434 478
435 ;;; Possibly Remote Resources: 479 ;;; Possibly Remote Resources:
436 480
437 (defun ffap-replace-path-component (fullname name) 481 (defun ffap-replace-file-component (fullname name)
438 "In remote FULLNAME, replace path with NAME. May return nil." 482 "In remote FULLNAME, replace path with NAME. May return nil."
439 ;; Use ange-ftp or efs if loaded, but do not load them otherwise. 483 ;; Use ange-ftp or efs if loaded, but do not load them otherwise.
440 (let (found) 484 (let (found)
441 (mapcar 485 (mapcar
442 (function (lambda (sym) (and (fboundp sym) (setq found sym)))) 486 (function (lambda (sym) (and (fboundp sym) (setq found sym))))
444 efs-replace-path-component 488 efs-replace-path-component
445 ange-ftp-replace-path-component 489 ange-ftp-replace-path-component
446 ange-ftp-replace-name-component 490 ange-ftp-replace-name-component
447 )) 491 ))
448 (and found 492 (and found
449 (fset 'ffap-replace-path-component found) 493 (fset 'ffap-replace-file-component found)
450 (funcall found fullname name)))) 494 (funcall found fullname name))))
451 ;; (ffap-replace-path-component "/who@foo.com:/whatever" "/new") 495 ;; (ffap-replace-file-component "/who@foo.com:/whatever" "/new")
452 496
453 (defun ffap-file-suffix (file) 497 (defun ffap-file-suffix (file)
454 "Return trailing `.foo' suffix of FILE, or nil if none." 498 "Return trailing `.foo' suffix of FILE, or nil if none."
455 (let ((pos (string-match "\\.[^./]*\\'" file))) 499 (let ((pos (string-match "\\.[^./]*\\'" file)))
456 (and pos (substring file pos nil)))) 500 (and pos (substring file pos nil))))
483 ret)))) 527 ret))))
484 528
485 (defun ffap-file-remote-p (filename) 529 (defun ffap-file-remote-p (filename)
486 "If FILENAME looks remote, return it (maybe slightly improved)." 530 "If FILENAME looks remote, return it (maybe slightly improved)."
487 ;; (ffap-file-remote-p "/user@foo.bar.com:/pub") 531 ;; (ffap-file-remote-p "/user@foo.bar.com:/pub")
488 ;; (ffap-file-remote-p "/cssun.mathcs.emory.edu://path") 532 ;; (ffap-file-remote-p "/cssun.mathcs.emory.edu://dir")
489 ;; (ffap-file-remote-p "/ffap.el:80") 533 ;; (ffap-file-remote-p "/ffap.el:80")
490 (or (and ffap-ftp-regexp 534 (or (and ffap-ftp-regexp
491 (string-match ffap-ftp-regexp filename) 535 (string-match ffap-ftp-regexp filename)
492 ;; Convert "/host.com://path" to "/host:/path", to handle a dieing 536 ;; Convert "/host.com://dir" to "/host:/dir", to handle a dieing
493 ;; practice of advertising ftp paths as "host.dom://path". 537 ;; practice of advertising ftp files as "host.dom://filename".
494 (if (string-match "//" filename) 538 (if (string-match "//" filename)
495 ;; (replace-match "/" nil nil filename) 539 ;; (replace-match "/" nil nil filename)
496 (concat (substring filename 0 (1+ (match-beginning 0))) 540 (concat (substring filename 0 (1+ (match-beginning 0)))
497 (substring filename (match-end 0))) 541 (substring filename (match-end 0)))
498 filename)) 542 filename))
503 (defun ffap-machine-at-point nil 547 (defun ffap-machine-at-point nil
504 "Return machine name at point if it exists, or nil." 548 "Return machine name at point if it exists, or nil."
505 (let ((mach (ffap-string-at-point 'machine))) 549 (let ((mach (ffap-string-at-point 'machine)))
506 (and (ffap-machine-p mach) mach))) 550 (and (ffap-machine-p mach) mach)))
507 551
508 (defsubst ffap-host-to-path (host) 552 (defsubst ffap-host-to-filename (host)
509 "Convert HOST to something like \"/USER@HOST:\" or \"/HOST:\". 553 "Convert HOST to something like \"/USER@HOST:\" or \"/HOST:\".
510 Looks at `ffap-ftp-default-user', returns \"\" for \"localhost\"." 554 Looks at `ffap-ftp-default-user', returns \"\" for \"localhost\"."
511 (if (equal host "localhost") 555 (if (equal host "localhost")
512 "" 556 ""
513 (let ((user ffap-ftp-default-user)) 557 (let ((user ffap-ftp-default-user))
516 (equal user (ffap-soft-value "efs-default-user"))) 560 (equal user (ffap-soft-value "efs-default-user")))
517 (setq user nil)) 561 (setq user nil))
518 (concat "/" user (and user "@") host ":")))) 562 (concat "/" user (and user "@") host ":"))))
519 563
520 (defun ffap-fixup-machine (mach) 564 (defun ffap-fixup-machine (mach)
521 ;; Convert a hostname into an url, an ftp path, or nil. 565 ;; Convert a hostname into an url, an ftp file name, or nil.
522 (cond 566 (cond
523 ((not (and ffap-url-regexp (stringp mach))) nil) 567 ((not (and ffap-url-regexp (stringp mach))) nil)
524 ;; gopher.well.com 568 ;; gopher.well.com
525 ((string-match "\\`gopher[-.]" mach) ; or "info"? 569 ((string-match "\\`gopher[-.]" mach) ; or "info"?
526 (concat "gopher://" mach "/")) 570 (concat "gopher://" mach "/"))
527 ;; www.ncsa.uiuc.edu 571 ;; www.ncsa.uiuc.edu
528 ((and (string-match "\\`w\\(ww\\|eb\\)[-.]" mach)) 572 ((and (string-match "\\`w\\(ww\\|eb\\)[-.]" mach))
529 (concat "http://" mach "/")) 573 (concat "http://" mach "/"))
530 ;; More cases? Maybe "telnet:" for archie? 574 ;; More cases? Maybe "telnet:" for archie?
531 (ffap-ftp-regexp (ffap-host-to-path mach)) 575 (ffap-ftp-regexp (ffap-host-to-filename mach))
532 )) 576 ))
533 577
534 (defvar ffap-newsgroup-regexp "^[a-z]+\\.[-+a-z_0-9.]+$" 578 (defvar ffap-newsgroup-regexp "^[a-z]+\\.[-+a-z_0-9.]+$"
535 "Strings not matching this fail `ffap-newsgroup-p'.") 579 "Strings not matching this fail `ffap-newsgroup-p'.")
536 (defvar ffap-newsgroup-heads ; entirely inadequate 580 (defvar ffap-newsgroup-heads ; entirely inadequate
578 (substring url (1+ (match-end 1))))) 622 (substring url (1+ (match-end 1)))))
579 (defsubst ffap-url-unwrap-remote (url) 623 (defsubst ffap-url-unwrap-remote (url)
580 "Return URL as a remote file, or nil. Ignores `ffap-url-regexp'." 624 "Return URL as a remote file, or nil. Ignores `ffap-url-regexp'."
581 (and (string-match "\\`\\(ftp\\|file\\)://\\([^:/]+\\):?\\(/.*\\)" url) 625 (and (string-match "\\`\\(ftp\\|file\\)://\\([^:/]+\\):?\\(/.*\\)" url)
582 (concat 626 (concat
583 (ffap-host-to-path (substring url (match-beginning 2) (match-end 2))) 627 (ffap-host-to-filename (substring url (match-beginning 2) (match-end 2)))
584 (substring url (match-beginning 3) (match-end 3))))) 628 (substring url (match-beginning 3) (match-end 3)))))
585 ;; Test: (ffap-url-unwrap-remote "ftp://foo.com/bar.boz") 629 ;; Test: (ffap-url-unwrap-remote "ftp://foo.com/bar.boz")
586 630
587 (defun ffap-fixup-url (url) 631 (defun ffap-fixup-url (url)
588 "Clean up URL and return it, maybe as a file name." 632 "Clean up URL and return it, maybe as a file name."
594 ((fboundp 'url-normalize-url) ; may autoload url (part of w3) 638 ((fboundp 'url-normalize-url) ; may autoload url (part of w3)
595 (url-normalize-url url)) 639 (url-normalize-url url))
596 (url))) 640 (url)))
597 641
598 642
599 ;;; Path Handling: 643 ;;; File Name Handling:
600 ;; 644 ;;
601 ;; The upcoming ffap-alist actions need various utilities to prepare 645 ;; The upcoming ffap-alist actions need various utilities to prepare
602 ;; and search paths of directories. Too many features here. 646 ;; and search directories. Too many features here.
603 647
604 ;; (defun ffap-last (l) (while (cdr l) (setq l (cdr l))) l) 648 ;; (defun ffap-last (l) (while (cdr l) (setq l (cdr l))) l)
605 ;; (defun ffap-splice (func inlist) 649 ;; (defun ffap-splice (func inlist)
606 ;; "Equivalent to (apply 'nconc (mapcar FUNC INLIST)), but less consing." 650 ;; "Equivalent to (apply 'nconc (mapcar FUNC INLIST)), but less consing."
607 ;; (let* ((head (cons 17 nil)) (last head)) 651 ;; (let* ((head (cons 17 nil)) (last head))
685 (list dir)))) 729 (list dir))))
686 path))) 730 path)))
687 731
688 (defun ffap-locate-file (file &optional nosuffix path dir-ok) 732 (defun ffap-locate-file (file &optional nosuffix path dir-ok)
689 ;; The Emacs 20 version of locate-library could almost replace this, 733 ;; The Emacs 20 version of locate-library could almost replace this,
690 ;; except it does not let us overrride the suffix list. The 734 ;; except it does not let us override the suffix list. The
691 ;; compression-suffixes search moved to ffap-file-exists-string. 735 ;; compression-suffixes search moved to ffap-file-exists-string.
692 "A generic path-searching function, mimics `load' by default. 736 "A generic path-searching function, mimics `load' by default.
693 Returns path to file that \(load FILE\) would load, or nil. 737 Returns path to file that \(load FILE\) would load, or nil.
694 Optional NOSUFFIX, if nil or t, is like the fourth argument 738 Optional NOSUFFIX, if nil or t, is like the fourth argument
695 for load: whether to try the suffixes (\".elc\" \".el\" \"\"). 739 for load: whether to try the suffixes (\".elc\" \".el\" \"\").
899 ;; Inside an LCD entry like |~/misc/ffap.el.Z|, 943 ;; Inside an LCD entry like |~/misc/ffap.el.Z|,
900 ;; or maybe the holy LCD-Datafile itself: 944 ;; or maybe the holy LCD-Datafile itself:
901 (member (ffap-string-around) '("||" "|\n"))) 945 (member (ffap-string-around) '("||" "|\n")))
902 (concat 946 (concat
903 ;; lispdir.el may not be loaded yet: 947 ;; lispdir.el may not be loaded yet:
904 (ffap-host-to-path 948 (ffap-host-to-filename
905 (ffap-soft-value "elisp-archive-host" 949 (ffap-soft-value "elisp-archive-host"
906 "archive.cis.ohio-state.edu")) 950 "archive.cis.ohio-state.edu"))
907 (file-name-as-directory 951 (file-name-as-directory
908 (ffap-soft-value "elisp-archive-directory" 952 (ffap-soft-value "elisp-archive-directory"
909 "/pub/gnu/emacs/elisp-archive/")) 953 "/pub/gnu/emacs/elisp-archive/"))
910 (substring name 2)))) 954 (substring name 2))))
911 955
912 (defvar ffap-rfc-path 956 (defvar ffap-rfc-path
913 (concat (ffap-host-to-path "ds.internic.net") "/rfc/rfc%s.txt")) 957 (concat (ffap-host-to-filename "ds.internic.net") "/rfc/rfc%s.txt"))
914 958
915 (defun ffap-rfc (name) 959 (defun ffap-rfc (name)
916 (format ffap-rfc-path 960 (format ffap-rfc-path
917 (substring name (match-beginning 1) (match-end 1)))) 961 (substring name (match-beginning 1) (match-end 1))))
918 962
923 '( 967 '(
924 ;; The default, used when the `major-mode' is not found. 968 ;; The default, used when the `major-mode' is not found.
925 ;; Slightly controversial decisions: 969 ;; Slightly controversial decisions:
926 ;; * strip trailing "@" and ":" 970 ;; * strip trailing "@" and ":"
927 ;; * no commas (good for latex) 971 ;; * no commas (good for latex)
928 (file "--:$+<>@-Z_a-z~" "<@" "@>;.,!?:") 972 (file "--:$+<>@-Z_a-z~*?" "<@" "@>;.,!:")
929 ;; An url, or maybe a email/news message-id: 973 ;; An url, or maybe a email/news message-id:
930 (url "--:=&?$+@-Z_a-z~#,%" "^A-Za-z0-9" ":;.,!?") 974 (url "--:=&?$+@-Z_a-z~#,%;*" "^A-Za-z0-9" ":;.,!?")
931 ;; Find a string that does *not* contain a colon: 975 ;; Find a string that does *not* contain a colon:
932 (nocolon "--9$+<>@-Z_a-z~" "<@" "@>;.,!?") 976 (nocolon "--9$+<>@-Z_a-z~" "<@" "@>;.,!?")
933 ;; A machine: 977 ;; A machine:
934 (machine "-a-zA-Z0-9." "" ".") 978 (machine "-a-zA-Z0-9." "" ".")
935 ;; Mathematica paths: allow backquotes 979 ;; Mathematica paths: allow backquotes
950 (defun ffap-string-at-point (&optional mode) 994 (defun ffap-string-at-point (&optional mode)
951 "Return a string of characters from around point. 995 "Return a string of characters from around point.
952 MODE (defaults to value of `major-mode') is a symbol used to look up string 996 MODE (defaults to value of `major-mode') is a symbol used to look up string
953 syntax parameters in `ffap-string-at-point-mode-alist'. 997 syntax parameters in `ffap-string-at-point-mode-alist'.
954 If MODE is not found, we use `file' instead of MODE. 998 If MODE is not found, we use `file' instead of MODE.
999 If the region is active, return a string from the region.
955 Sets `ffap-string-at-point' and `ffap-string-at-point-region'." 1000 Sets `ffap-string-at-point' and `ffap-string-at-point-region'."
956 (let* ((args 1001 (let* ((args
957 (cdr 1002 (cdr
958 (or (assq (or mode major-mode) ffap-string-at-point-mode-alist) 1003 (or (assq (or mode major-mode) ffap-string-at-point-mode-alist)
959 (assq 'file ffap-string-at-point-mode-alist)))) 1004 (assq 'file ffap-string-at-point-mode-alist))))
960 (pt (point)) 1005 (pt (point))
961 (str 1006 (str
962 (buffer-substring 1007 (if (and transient-mark-mode mark-active)
963 (save-excursion 1008 (buffer-substring
964 (skip-chars-backward (car args)) 1009 (setcar ffap-string-at-point-region (region-beginning))
965 (skip-chars-forward (nth 1 args) pt) 1010 (setcar (cdr ffap-string-at-point-region) (region-end)))
966 (setcar ffap-string-at-point-region (point))) 1011 (buffer-substring
967 (save-excursion 1012 (save-excursion
968 (skip-chars-forward (car args)) 1013 (skip-chars-backward (car args))
969 (skip-chars-backward (nth 2 args) pt) 1014 (skip-chars-forward (nth 1 args) pt)
970 (setcar (cdr ffap-string-at-point-region) (point)))))) 1015 (setcar ffap-string-at-point-region (point)))
1016 (save-excursion
1017 (skip-chars-forward (car args))
1018 (skip-chars-backward (nth 2 args) pt)
1019 (setcar (cdr ffap-string-at-point-region) (point)))))))
971 (set-text-properties 0 (length str) nil str) 1020 (set-text-properties 0 (length str) nil str)
972 (setq ffap-string-at-point str))) 1021 (setq ffap-string-at-point str)))
973 1022
974 (defun ffap-string-around nil 1023 (defun ffap-string-around nil
975 ;; Sometimes useful to decide how to treat a string. 1024 ;; Sometimes useful to decide how to treat a string.
1075 ffap-ftp-regexp 1124 ffap-ftp-regexp
1076 ;; Note: by now, we know it is not an url. 1125 ;; Note: by now, we know it is not an url.
1077 ;; Icky regexp avoids: default: 123: foo::bar cs:pub 1126 ;; Icky regexp avoids: default: 123: foo::bar cs:pub
1078 ;; It does match on: mic@cs: cs:/pub mathcs.emory.edu: (point at end) 1127 ;; It does match on: mic@cs: cs:/pub mathcs.emory.edu: (point at end)
1079 "\\`\\([^:@]+@[^:@]+:\\|[^@.:]+\\.[^@:]+:\\|[^:]+:[~/]\\)\\([^:]\\|\\'\\)") 1128 "\\`\\([^:@]+@[^:@]+:\\|[^@.:]+\\.[^@:]+:\\|[^:]+:[~/]\\)\\([^:]\\|\\'\\)")
1080 "Strings matching this are coerced to ftp paths by ffap. 1129 "Strings matching this are coerced to ftp file names by ffap.
1081 That is, ffap just prepends \"/\". Set to nil to disable.") 1130 That is, ffap just prepends \"/\". Set to nil to disable.")
1082 1131
1083 (defun ffap-file-at-point nil 1132 (defun ffap-file-at-point nil
1084 "Return filename from around point if it exists, or nil. 1133 "Return filename from around point if it exists, or nil.
1085 Existence test is skipped for names that look remote. 1134 Existence test is skipped for names that look remote.
1086 If the filename is not obvious, it also tries `ffap-alist', 1135 If the filename is not obvious, it also tries `ffap-alist',
1087 which may actually result in an url rather than a filename." 1136 which may actually result in an url rather than a filename."
1088 ;; Note: this function does not need to look for url's, just 1137 ;; Note: this function does not need to look for url's, just
1089 ;; filenames. On the other hand, it is responsible for converting 1138 ;; filenames. On the other hand, it is responsible for converting
1090 ;; a pseudo-url "site.com://path" to an ftp path 1139 ;; a pseudo-url "site.com://dir" to an ftp file name
1091 (let* ((case-fold-search t) ; url prefixes are case-insensitive 1140 (let* ((case-fold-search t) ; url prefixes are case-insensitive
1092 (data (match-data)) 1141 (data (match-data))
1093 (string (ffap-string-at-point)) ; uses mode alist 1142 (string (ffap-string-at-point)) ; uses mode alist
1094 (name 1143 (name
1095 (or (condition-case nil 1144 (or (condition-case nil
1099 string)) 1148 string))
1100 (abs (file-name-absolute-p name)) 1149 (abs (file-name-absolute-p name))
1101 (default-directory default-directory)) 1150 (default-directory default-directory))
1102 (unwind-protect 1151 (unwind-protect
1103 (cond 1152 (cond
1104 ;; Immediate rejects (/ and // are too common in C++): 1153 ;; Immediate rejects (/ and // and /* are too common in C/C++):
1105 ((member name '("" "/" "//" ".")) nil) 1154 ((member name '("" "/" "//" "/*" ".")) nil)
1106 ;; Immediately test local filenames. If default-directory is 1155 ;; Immediately test local filenames. If default-directory is
1107 ;; remote, you probably already have a connection. 1156 ;; remote, you probably already have a connection.
1108 ((and (not abs) (ffap-file-exists-string name))) 1157 ((and (not abs) (ffap-file-exists-string name)))
1109 ;; Try stripping off line numbers; good for compilation/grep output. 1158 ;; Try stripping off line numbers; good for compilation/grep output.
1110 ((and (not abs) (string-match ":[0-9]" name) 1159 ((and (not abs) (string-match ":[0-9]" name)
1111 (ffap-file-exists-string (substring name 0 (match-beginning 0))))) 1160 (ffap-file-exists-string (substring name 0 (match-beginning 0)))))
1112 ;; Immediately test local filenames. If default-directory is 1161 ;; Try stripping off prominent (non-root - #) shell prompts
1113 ;; remote, you probably already have a connection. 1162 ;; if the ffap-shell-prompt-regexp is non-nil.
1114 ((and (not abs) (ffap-file-exists-string name))) 1163 ((and ffap-shell-prompt-regexp
1164 (not abs) (string-match ffap-shell-prompt-regexp name)
1165 (ffap-file-exists-string (substring name (match-end 0)))))
1115 ;; Accept remote names without actual checking (too slow): 1166 ;; Accept remote names without actual checking (too slow):
1116 ((if abs 1167 ((if abs
1117 (ffap-file-remote-p name) 1168 (ffap-file-remote-p name)
1118 ;; Try adding a leading "/" (common omission in ftp paths): 1169 ;; Try adding a leading "/" (common omission in ftp file names):
1119 (and 1170 (and
1120 ffap-ftp-sans-slash-regexp 1171 ffap-ftp-sans-slash-regexp
1121 (string-match ffap-ftp-sans-slash-regexp name) 1172 (string-match ffap-ftp-sans-slash-regexp name)
1122 (ffap-file-remote-p (concat "/" name))))) 1173 (ffap-file-remote-p (concat "/" name)))))
1123 ;; Ok, not remote, try the existence test even if it is absolute: 1174 ;; Ok, not remote, try the existence test even if it is absolute:
1142 (ffap-file-remote-p try) 1193 (ffap-file-remote-p try)
1143 (ffap-file-exists-string try)))))) 1194 (ffap-file-exists-string try))))))
1144 try)) 1195 try))
1145 ;; Alist failed? Try to guess an active remote connection 1196 ;; Alist failed? Try to guess an active remote connection
1146 ;; from buffer variables, and try once more, both as an 1197 ;; from buffer variables, and try once more, both as an
1147 ;; absolute and relative path on that remote host. 1198 ;; absolute and relative file name on that remote host.
1148 ((let* (ffap-rfs-regexp ; suppress 1199 ((let* (ffap-rfs-regexp ; suppress
1149 (remote-dir 1200 (remote-dir
1150 (cond 1201 (cond
1151 ((ffap-file-remote-p default-directory)) 1202 ((ffap-file-remote-p default-directory))
1152 ((and (eq major-mode 'internal-ange-ftp-mode) 1203 ((and (eq major-mode 'internal-ange-ftp-mode)
1160 ))) 1211 )))
1161 (and remote-dir 1212 (and remote-dir
1162 (or 1213 (or
1163 (and (string-match "\\`\\(/?~?ftp\\)/" name) 1214 (and (string-match "\\`\\(/?~?ftp\\)/" name)
1164 (ffap-file-exists-string 1215 (ffap-file-exists-string
1165 (ffap-replace-path-component 1216 (ffap-replace-file-component
1166 remote-dir (substring name (match-end 1))))) 1217 remote-dir (substring name (match-end 1)))))
1167 (ffap-file-exists-string 1218 (ffap-file-exists-string
1168 (ffap-replace-path-component remote-dir name)))))) 1219 (ffap-replace-file-component remote-dir name))))))
1220 ((and ffap-dired-wildcards
1221 (string-match ffap-dired-wildcards name)
1222 abs
1223 (ffap-file-exists-string (file-name-directory
1224 (directory-file-name name)))
1225 name))
1226 ;; Try all parent directories by deleting the trailing directory
1227 ;; name until existing directory is found or name stops changing
1228 ((let ((dir name))
1229 (while (and dir
1230 (not (ffap-file-exists-string dir))
1231 (not (equal dir (setq dir (file-name-directory
1232 (directory-file-name dir)))))))
1233 (ffap-file-exists-string dir)))
1169 ) 1234 )
1170 (set-match-data data)))) 1235 (set-match-data data))))
1171 1236
1172 ;;; Prompting (`ffap-read-file-or-url'): 1237 ;;; Prompting (`ffap-read-file-or-url'):
1173 ;; 1238 ;;
1196 prompt 1261 prompt
1197 'ffap-read-file-or-url-internal 1262 'ffap-read-file-or-url-internal
1198 dir 1263 dir
1199 nil 1264 nil
1200 (if dir (cons guess (length dir)) guess) 1265 (if dir (cons guess (length dir)) guess)
1201 (list 'file-name-history)))) 1266 (list 'file-name-history)
1267 (and buffer-file-name
1268 (abbreviate-file-name buffer-file-name)))))
1202 ;; Do file substitution like (interactive "F"), suggested by MCOOK. 1269 ;; Do file substitution like (interactive "F"), suggested by MCOOK.
1203 (or (ffap-url-p guess) (setq guess (substitute-in-file-name guess))) 1270 (or (ffap-url-p guess) (setq guess (substitute-in-file-name guess)))
1204 ;; Should not do it on url's, where $ is a common (VMS?) character. 1271 ;; Should not do it on url's, where $ is a common (VMS?) character.
1205 ;; Note: upcoming url.el package ought to handle this automatically. 1272 ;; Note: upcoming url.el package ought to handle this automatically.
1206 guess)) 1273 guess))
1228 1295
1229 ;; The rest of this page is just to work with package complete.el. 1296 ;; The rest of this page is just to work with package complete.el.
1230 ;; This code assumes that you load ffap.el after complete.el. 1297 ;; This code assumes that you load ffap.el after complete.el.
1231 ;; 1298 ;;
1232 ;; We must inform complete about whether our completion function 1299 ;; We must inform complete about whether our completion function
1233 ;; will do filename style completion. For earlier versions of 1300 ;; will do filename style completion.
1234 ;; complete.el, this requires a defadvice. For recent versions
1235 ;; there may be a special variable for this purpose.
1236 1301
1237 (defun ffap-complete-as-file-p nil 1302 (defun ffap-complete-as-file-p nil
1238 ;; Will `minibuffer-completion-table' complete the minibuffer 1303 ;; Will `minibuffer-completion-table' complete the minibuffer
1239 ;; contents as a filename? Assumes the minibuffer is current. 1304 ;; contents as a filename? Assumes the minibuffer is current.
1240 ;; Note: t and non-nil mean somewhat different reasons. 1305 ;; Note: t and non-nil mean somewhat different reasons.
1244 1309
1245 (and 1310 (and
1246 (featurep 'complete) 1311 (featurep 'complete)
1247 (if (boundp 'PC-completion-as-file-name-predicate) 1312 (if (boundp 'PC-completion-as-file-name-predicate)
1248 ;; modern version of complete.el, just set the variable: 1313 ;; modern version of complete.el, just set the variable:
1249 (setq PC-completion-as-file-name-predicate 'ffap-complete-as-file-p) 1314 (setq PC-completion-as-file-name-predicate 'ffap-complete-as-file-p)))
1250 (require 'advice)
1251 (defadvice PC-do-completion (around ffap-fix act)
1252 "Work with ffap."
1253 (let ((minibuffer-completion-table
1254 (if (eq t (ffap-complete-as-file-p))
1255 'read-file-name-internal
1256 minibuffer-completion-table)))
1257 ad-do-it))))
1258 1315
1259 1316
1260 ;;; Highlighting (`ffap-highlight'): 1317 ;;; Highlighting (`ffap-highlight'):
1261 ;; 1318 ;;
1262 ;; Based on overlay highlighting in Emacs 19.28 isearch.el. 1319 ;; Based on overlay highlighting in Emacs 19.28 isearch.el.
1321 "Find FILENAME, guessing a default from text around point. 1378 "Find FILENAME, guessing a default from text around point.
1322 If `ffap-url-regexp' is not nil, the FILENAME may also be an URL. 1379 If `ffap-url-regexp' is not nil, the FILENAME may also be an URL.
1323 With a prefix, this command behaves exactly like `ffap-file-finder'. 1380 With a prefix, this command behaves exactly like `ffap-file-finder'.
1324 If `ffap-require-prefix' is set, the prefix meaning is reversed. 1381 If `ffap-require-prefix' is set, the prefix meaning is reversed.
1325 See also the variables `ffap-dired-wildcards', `ffap-newfile-prompt', 1382 See also the variables `ffap-dired-wildcards', `ffap-newfile-prompt',
1326 and the functions `ffap-file-at-point' and `ffap-url-at-point'. 1383 and the functions `ffap-file-at-point' and `ffap-url-at-point'."
1327
1328 See <ftp://ftp.mathcs.emory.edu/pub/mic/emacs/> for latest version."
1329 (interactive) 1384 (interactive)
1330 (if (and (interactive-p) 1385 (if (and (interactive-p)
1331 (if ffap-require-prefix (not current-prefix-arg) 1386 (if ffap-require-prefix (not current-prefix-arg)
1332 current-prefix-arg)) 1387 current-prefix-arg))
1333 ;; Do exactly the ffap-file-finder command, even the prompting: 1388 ;; Do exactly the ffap-file-finder command, even the prompting:
1336 (or filename (setq filename (ffap-prompter))) 1391 (or filename (setq filename (ffap-prompter)))
1337 (cond 1392 (cond
1338 ((ffap-url-p filename) 1393 ((ffap-url-p filename)
1339 (let (current-prefix-arg) ; w3 2.3.25 bug, reported by KPC 1394 (let (current-prefix-arg) ; w3 2.3.25 bug, reported by KPC
1340 (funcall ffap-url-fetcher filename))) 1395 (funcall ffap-url-fetcher filename)))
1341 ;; This junk more properly belongs in a modified ffap-file-finder: 1396 ((and ffap-pass-wildcards-to-dired
1397 ffap-dired-wildcards
1398 (string-match ffap-dired-wildcards filename))
1399 (funcall ffap-directory-finder filename))
1342 ((and ffap-dired-wildcards 1400 ((and ffap-dired-wildcards
1343 (string-match ffap-dired-wildcards filename)) 1401 (string-match ffap-dired-wildcards filename)
1344 (dired filename)) 1402 find-file-wildcards
1403 ;; Check if it's find-file that supports wildcards arg
1404 (memq ffap-file-finder '(find-file find-alternate-file)))
1405 (funcall ffap-file-finder (expand-file-name filename) t))
1345 ((or (not ffap-newfile-prompt) 1406 ((or (not ffap-newfile-prompt)
1346 (file-exists-p filename) 1407 (file-exists-p filename)
1347 (y-or-n-p "File does not exist, create buffer? ")) 1408 (y-or-n-p "File does not exist, create buffer? "))
1348 (funcall ffap-file-finder 1409 (funcall ffap-file-finder
1349 ;; expand-file-name fixes "~/~/.emacs" bug sent by CHUCKR. 1410 ;; expand-file-name fixes "~/~/.emacs" bug sent by CHUCKR.
1456 Applies `ffap-menu-text-plist' text properties at all matches." 1517 Applies `ffap-menu-text-plist' text properties at all matches."
1457 (interactive) 1518 (interactive)
1458 (let ((ffap-next-regexp (or ffap-menu-regexp ffap-next-regexp)) 1519 (let ((ffap-next-regexp (or ffap-menu-regexp ffap-next-regexp))
1459 (range (- (point-max) (point-min))) 1520 (range (- (point-max) (point-min)))
1460 (mod (buffer-modified-p)) ; was buffer modified? 1521 (mod (buffer-modified-p)) ; was buffer modified?
1461 buffer-read-only ; to set text-properties 1522 ;; inhibit-read-only works on read-only text properties
1523 ;; as well as read-only buffers.
1524 (inhibit-read-only t) ; to set text-properties
1462 item 1525 item
1463 ;; Avoid repeated searches of the *mode-alist: 1526 ;; Avoid repeated searches of the *mode-alist:
1464 (major-mode (if (assq major-mode ffap-string-at-point-mode-alist) 1527 (major-mode (if (assq major-mode ffap-string-at-point-mode-alist)
1465 major-mode 1528 major-mode
1466 'file))) 1529 'file)))
1535 nil)) ; no fallback, return nil 1598 nil)) ; no fallback, return nil
1536 ;; failure: return nil 1599 ;; failure: return nil
1537 ))) 1600 )))
1538 1601
1539 1602
1540 ;;; ffap-other-* commands: 1603 ;;; ffap-other-*, ffap-read-only-*, ffap-alternate-* commands:
1541 ;;
1542 ;; Requested by KPC.
1543 1604
1544 ;; There could be a real `ffap-noselect' function, but we would need 1605 ;; There could be a real `ffap-noselect' function, but we would need
1545 ;; at least two new user variables, and there is no w3-fetch-noselect. 1606 ;; at least two new user variables, and there is no w3-fetch-noselect.
1546 ;; So instead, we just fake it with a slow save-window-excursion. 1607 ;; So instead, we just fake it with a slow save-window-excursion.
1547 1608
1548 (defun ffap-other-window nil 1609 (defun ffap-other-window nil
1549 "Like `ffap', but put buffer in another window. 1610 "Like `ffap', but put buffer in another window.
1550 Only intended for interactive use." 1611 Only intended for interactive use."
1551 (interactive) 1612 (interactive)
1552 (switch-to-buffer-other-window 1613 (let (value)
1553 (save-window-excursion (call-interactively 'ffap) (current-buffer)))) 1614 (switch-to-buffer-other-window
1615 (save-window-excursion
1616 (setq value (call-interactively 'ffap))
1617 (unless (or (bufferp value) (bufferp (car-safe value)))
1618 (setq value (current-buffer)))
1619 (current-buffer)))
1620 value))
1554 1621
1555 (defun ffap-other-frame nil 1622 (defun ffap-other-frame nil
1556 "Like `ffap', but put buffer in another frame. 1623 "Like `ffap', but put buffer in another frame.
1557 Only intended for interactive use." 1624 Only intended for interactive use."
1558 (interactive) 1625 (interactive)
1559 ;; Extra code works around dedicated windows (noted by JENS, 7/96): 1626 ;; Extra code works around dedicated windows (noted by JENS, 7/96):
1560 (let* ((win (selected-window)) (wdp (window-dedicated-p win))) 1627 (let* ((win (selected-window))
1628 (wdp (window-dedicated-p win))
1629 value)
1561 (unwind-protect 1630 (unwind-protect
1562 (progn 1631 (progn
1563 (set-window-dedicated-p win nil) 1632 (set-window-dedicated-p win nil)
1564 (switch-to-buffer-other-frame 1633 (switch-to-buffer-other-frame
1565 (save-window-excursion 1634 (save-window-excursion
1566 (call-interactively 'ffap) 1635 (setq value (call-interactively 'ffap))
1636 (unless (or (bufferp value) (bufferp (car-safe value)))
1637 (setq value (current-buffer)))
1567 (current-buffer)))) 1638 (current-buffer))))
1568 (set-window-dedicated-p win wdp)))) 1639 (set-window-dedicated-p win wdp))
1640 value))
1641
1642 (defun ffap-read-only ()
1643 "Like `ffap', but mark buffer as read-only.
1644 Only intended for interactive use."
1645 (interactive)
1646 (let ((value (call-interactively 'ffap)))
1647 (unless (or (bufferp value) (bufferp (car-safe value)))
1648 (setq value (current-buffer)))
1649 (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
1650 (if (listp value) value (list value)))
1651 value))
1652
1653 (defun ffap-read-only-other-window ()
1654 "Like `ffap', but put buffer in another window and mark as read-only.
1655 Only intended for interactive use."
1656 (interactive)
1657 (let ((value (ffap-other-window)))
1658 (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
1659 (if (listp value) value (list value)))
1660 value))
1661
1662 (defun ffap-read-only-other-frame ()
1663 "Like `ffap', but put buffer in another frame and mark as read-only.
1664 Only intended for interactive use."
1665 (interactive)
1666 (let ((value (ffap-other-frame)))
1667 (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
1668 (if (listp value) value (list value)))
1669 value))
1670
1671 (defun ffap-alternate-file ()
1672 "Like `ffap' and `find-alternate-file'.
1673 Only intended for interactive use."
1674 (interactive)
1675 (let ((ffap-file-finder 'find-alternate-file))
1676 (call-interactively 'ffap)))
1569 1677
1570 1678
1571 ;;; Bug Reporter: 1679 ;;; Bug Reporter:
1572 1680
1573 (defun ffap-bug nil 1681 (defun ffap-bug nil
1601 "Bind `ffap-gnus-next' and `ffap-gnus-menu' to M-l and M-m, resp." 1709 "Bind `ffap-gnus-next' and `ffap-gnus-menu' to M-l and M-m, resp."
1602 (set (make-local-variable 'ffap-foo-at-bar-prefix) "news") ; message-id's 1710 (set (make-local-variable 'ffap-foo-at-bar-prefix) "news") ; message-id's
1603 ;; Note "l", "L", "m", "M" are taken: 1711 ;; Note "l", "L", "m", "M" are taken:
1604 (local-set-key "\M-l" 'ffap-gnus-next) 1712 (local-set-key "\M-l" 'ffap-gnus-next)
1605 (local-set-key "\M-m" 'ffap-gnus-menu)) 1713 (local-set-key "\M-m" 'ffap-gnus-menu))
1714
1715 (defvar gnus-summary-buffer)
1716 (defvar gnus-article-buffer)
1606 1717
1607 (defun ffap-gnus-wrapper (form) ; used by both commands below 1718 (defun ffap-gnus-wrapper (form) ; used by both commands below
1608 (and (eq (current-buffer) (get-buffer gnus-summary-buffer)) 1719 (and (eq (current-buffer) (get-buffer gnus-summary-buffer))
1609 (gnus-summary-select-article)) ; get article of current line 1720 (gnus-summary-select-article)) ; get article of current line
1610 ;; Preserve selected buffer, but do not do save-window-excursion, 1721 ;; Preserve selected buffer, but do not do save-window-excursion,
1644 (if (and (interactive-p) 1755 (if (and (interactive-p)
1645 (if dired-at-point-require-prefix 1756 (if dired-at-point-require-prefix
1646 (not current-prefix-arg) 1757 (not current-prefix-arg)
1647 current-prefix-arg)) 1758 current-prefix-arg))
1648 (let (current-prefix-arg) ; already interpreted 1759 (let (current-prefix-arg) ; already interpreted
1649 (call-interactively 'dired)) 1760 (call-interactively ffap-directory-finder))
1650 (or filename (setq filename (dired-at-point-prompter))) 1761 (or filename (setq filename (dired-at-point-prompter)))
1651 (cond 1762 (cond
1652 ((ffap-url-p filename) 1763 ((ffap-url-p filename)
1653 (funcall ffap-url-fetcher filename)) 1764 (funcall ffap-url-fetcher filename))
1654 ((and ffap-dired-wildcards 1765 ((and ffap-dired-wildcards
1655 (string-match ffap-dired-wildcards filename)) 1766 (string-match ffap-dired-wildcards filename))
1656 (dired filename)) 1767 (funcall ffap-directory-finder filename))
1657 ((file-exists-p filename) 1768 ((file-exists-p filename)
1658 (if (file-directory-p filename) 1769 (if (file-directory-p filename)
1659 (dired (expand-file-name filename)) 1770 (funcall ffap-directory-finder
1660 (dired (concat (expand-file-name filename) "*")))) 1771 (expand-file-name filename))
1661 ((y-or-n-p "Directory does not exist, create it? ") 1772 (funcall ffap-directory-finder
1773 (concat (expand-file-name filename) "*"))))
1774 ((and (file-writable-p
1775 (or (file-name-directory (directory-file-name filename))
1776 filename))
1777 (y-or-n-p "Directory does not exist, create it? "))
1662 (make-directory filename) 1778 (make-directory filename)
1663 (dired filename)) 1779 (funcall ffap-directory-finder filename))
1664 ((error "No such file or directory `%s'" filename))))) 1780 ((error "No such file or directory `%s'" filename)))))
1665 1781
1666 (defun dired-at-point-prompter (&optional guess) 1782 (defun dired-at-point-prompter (&optional guess)
1667 ;; Does guess and prompt step for find-file-at-point. 1783 ;; Does guess and prompt step for find-file-at-point.
1668 ;; Extra complication for the temporary highlighting. 1784 ;; Extra complication for the temporary highlighting.
1669 (unwind-protect 1785 (unwind-protect
1670 (ffap-read-file-or-url 1786 (ffap-read-file-or-url
1671 (if ffap-url-regexp "Dired file or URL: " "Dired file: ") 1787 (if ffap-url-regexp "Dired file or URL: " "Dired file: ")
1672 (prog1 1788 (prog1
1673 (setq guess (or guess (ffap-guesser))) 1789 (setq guess (or guess
1674 (and guess (ffap-highlight)) 1790 (let ((guess (ffap-guesser)))
1675 )) 1791 (if (or (not guess)
1792 (ffap-url-p guess)
1793 (ffap-file-remote-p guess))
1794 guess
1795 (setq guess (abbreviate-file-name
1796 (expand-file-name guess)))
1797 (cond
1798 ;; Interpret local directory as a directory.
1799 ((file-directory-p guess)
1800 (file-name-as-directory guess))
1801 ;; Get directory component from local files.
1802 ((file-regular-p guess)
1803 (file-name-directory guess))
1804 (guess))))
1805 ))
1806 (and guess (ffap-highlight))))
1676 (ffap-highlight t))) 1807 (ffap-highlight t)))
1808
1809 ;;; ffap-dired-other-*, ffap-list-directory commands:
1810
1811 (defun ffap-dired-other-window ()
1812 "Like `dired-at-point', but put buffer in another window.
1813 Only intended for interactive use."
1814 (interactive)
1815 (let (value)
1816 (switch-to-buffer-other-window
1817 (save-window-excursion
1818 (setq value (call-interactively 'dired-at-point))
1819 (current-buffer)))
1820 value))
1821
1822 (defun ffap-dired-other-frame ()
1823 "Like `dired-at-point', but put buffer in another frame.
1824 Only intended for interactive use."
1825 (interactive)
1826 ;; Extra code works around dedicated windows (noted by JENS, 7/96):
1827 (let* ((win (selected-window))
1828 (wdp (window-dedicated-p win))
1829 value)
1830 (unwind-protect
1831 (progn
1832 (set-window-dedicated-p win nil)
1833 (switch-to-buffer-other-frame
1834 (save-window-excursion
1835 (setq value (call-interactively 'dired-at-point))
1836 (current-buffer))))
1837 (set-window-dedicated-p win wdp))
1838 value))
1839
1840 (defun ffap-list-directory ()
1841 "Like `dired-at-point' and `list-directory'.
1842 Only intended for interactive use."
1843 (interactive)
1844 (let ((ffap-directory-finder 'list-directory))
1845 (call-interactively 'dired-at-point)))
1846
1677 1847
1678 ;;; Offer default global bindings (`ffap-bindings'): 1848 ;;; Offer default global bindings (`ffap-bindings'):
1679 1849
1680 (defvar ffap-bindings 1850 (defvar ffap-bindings
1681 '( 1851 '(
1682 (global-set-key [S-mouse-3] 'ffap-at-mouse) 1852 (global-set-key [S-mouse-3] 'ffap-at-mouse)
1683 (global-set-key [C-S-mouse-3] 'ffap-menu) 1853 (global-set-key [C-S-mouse-3] 'ffap-menu)
1854
1684 (global-set-key "\C-x\C-f" 'find-file-at-point) 1855 (global-set-key "\C-x\C-f" 'find-file-at-point)
1856 (global-set-key "\C-x\C-r" 'ffap-read-only)
1857 (global-set-key "\C-x\C-v" 'ffap-alternate-file)
1858
1685 (global-set-key "\C-x4f" 'ffap-other-window) 1859 (global-set-key "\C-x4f" 'ffap-other-window)
1686 (global-set-key "\C-x5f" 'ffap-other-frame) 1860 (global-set-key "\C-x5f" 'ffap-other-frame)
1861 (global-set-key "\C-x4r" 'ffap-read-only-other-window)
1862 (global-set-key "\C-x5r" 'ffap-read-only-other-frame)
1863
1687 (global-set-key "\C-xd" 'dired-at-point) 1864 (global-set-key "\C-xd" 'dired-at-point)
1865 (global-set-key "\C-x4d" 'ffap-dired-other-window)
1866 (global-set-key "\C-x5d" 'ffap-dired-other-frame)
1867 (global-set-key "\C-x\C-d" 'ffap-list-directory)
1868
1688 (add-hook 'gnus-summary-mode-hook 'ffap-gnus-hook) 1869 (add-hook 'gnus-summary-mode-hook 'ffap-gnus-hook)
1689 (add-hook 'gnus-article-mode-hook 'ffap-gnus-hook) 1870 (add-hook 'gnus-article-mode-hook 'ffap-gnus-hook)
1690 (add-hook 'vm-mode-hook 'ffap-ro-mode-hook) 1871 (add-hook 'vm-mode-hook 'ffap-ro-mode-hook)
1691 (add-hook 'rmail-mode-hook 'ffap-ro-mode-hook) 1872 (add-hook 'rmail-mode-hook 'ffap-ro-mode-hook)
1692 ;; (setq dired-x-hands-off-my-keys t) ; the default 1873 ;; (setq dired-x-hands-off-my-keys t) ; the default
1701 "Evaluate the forms in variable `ffap-bindings'." 1882 "Evaluate the forms in variable `ffap-bindings'."
1702 (interactive) 1883 (interactive)
1703 (eval (cons 'progn ffap-bindings))) 1884 (eval (cons 'progn ffap-bindings)))
1704 1885
1705 1886
1887
1888 ;;; arch-tag: 9dd3e88a-5dec-4607-bd57-60ae9ede8ebc
1706 ;;; ffap.el ends here 1889 ;;; ffap.el ends here