Mercurial > emacs
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 |