]> code.delx.au - gnu-emacs/blobdiff - lisp/ffap.el
Merge from origin/emacs-25
[gnu-emacs] / lisp / ffap.el
index d481f90541265fe7dc2017f67aa6dca0e41e8337..abf979f612933a224c5115dd9ae75384ab42b407 100644 (file)
@@ -1,6 +1,6 @@
 ;;; ffap.el --- find file (or url) at point
 
-;; Copyright (C) 1995-1997, 2000-2015 Free Software Foundation, Inc.
+;; Copyright (C) 1995-1997, 2000-2016 Free Software Foundation, Inc.
 
 ;; Author: Michelangelo Grigni <mic@mathcs.emory.edu>
 ;; Maintainer: emacs-devel@gnu.org
@@ -90,7 +90,6 @@
 
 \f
 ;;; Todo list:
-;; * use kpsewhich
 ;; * let "/dir/file#key" jump to key (tag or regexp) in /dir/file
 ;; * find file of symbol if TAGS is loaded (like above)
 ;; * break long menus into multiple panes (like imenu?)
@@ -413,9 +412,9 @@ Optional SERVICE specifies the port used (default \"discard\").
 Optional QUIET flag suppresses the \"Pinging...\" message.
 Optional STRATEGY overrides the three variables above.
 Returned values:
- t      means that HOST answered.
-'accept means the relevant variable told us to accept.
-\"mesg\"  means HOST exists, but does not respond for some reason."
+ t       means that HOST answered.
+`accept' means the relevant variable told us to accept.
+\"mesg\"   means HOST exists, but does not respond for some reason."
   ;; Try some (Emory local):
   ;; (ffap-machine-p "ftp" nil nil 'ping)
   ;; (ffap-machine-p "nonesuch" nil nil 'ping)
@@ -571,7 +570,7 @@ Looks at `ffap-ftp-default-user', returns \"\" for \"localhost\"."
 (defvaralias 'ffap-newsgroup-heads  'thing-at-point-newsgroup-heads)
 (defalias 'ffap-newsgroup-p 'thing-at-point-newsgroup-p)
 
-(defsubst ffap-url-p (string)
+(defun ffap-url-p (string)
   "If STRING looks like an URL, return it (maybe improved), else nil."
   (when (and (stringp string) ffap-url-regexp)
     (let* ((case-fold-search t)
@@ -894,6 +893,24 @@ URL, or nil.  If nil, search the alist for further matches.")
   "Path where `ffap-tex-mode' looks for TeX files.
 If t, `ffap-tex-init' will initialize this when needed.")
 
+(defvar ffap-latex-guess-rules '(("" . ".sty")
+                               ("" . ".cls")
+                               ("" . ".ltx")
+                               ("" . ".tex")
+                               ("" . "") ;; in some rare cases the
+                                         ;; extension is already in
+                                         ;; the buffer.
+                               ("beamertheme" . ".sty")
+                               ("beamercolortheme". ".sty")
+                               ("beamerfonttheme". ".sty")
+                               ("beamerinnertheme". ".sty")
+                               ("beameroutertheme". ".sty")
+                               ("" . ".ldf"))
+  "List of rules for guessing a filename.
+Each rule is a cons (PREFIX . SUFFIX) used for guessing a
+filename from the word at point by prepending PREFIX and
+appending SUFFIX.")
+
 (defun ffap-tex-init ()
   ;; Compute ffap-tex-path if it is now t.
   (and (eq t ffap-tex-path)
@@ -917,9 +934,56 @@ If t, `ffap-tex-init' will initialize this when needed.")
   (ffap-locate-file name '(".tex" "") ffap-tex-path))
 
 (defun ffap-latex-mode (name)
-  (ffap-tex-init)
-  ;; only rare need for ""
-  (ffap-locate-file name '(".cls" ".sty" ".tex" "") ffap-tex-path))
+  "`ffap' function suitable for latex buffers.
+This uses the program kpsewhich if available. In this case, the
+variable `ffap-latex-guess-rules' is used for building a filename
+out of NAME."
+  (cond ((file-exists-p name)
+         name)
+        ((not (executable-find "kpsewhich"))
+         (ffap-tex-init)
+         (ffap-locate-file name '(".cls" ".sty" ".tex" "") ffap-tex-path))
+        (t
+         (let ((curbuf (current-buffer))
+               (guess-rules ffap-latex-guess-rules)
+               (preferred-suffix-rules '(("input" . ".tex")
+                                         ("include" . ".tex")
+                                         ("usepackage" . ".sty")
+                                         ("RequirePackageWithOptions" . ".sty")
+                                         ("RequirePackage" . ".sty")
+                                         ("documentclass" . ".cls")
+                                         ("documentstyle" . ".cls")
+                                         ("LoadClass" . ".cls")
+                                         ("LoadClassWithOptions" . ".cls")
+                                         ("bibliography" . ".bib")
+                                         ("addbibresource" . ""))))
+           ;; We now add preferred suffix in front of suffixes.
+           (when
+               ;; The condition is essentially:
+               ;; (assoc (TeX-current-macro)
+               ;;        (mapcar 'car preferred-suffix-rules))
+               ;; but (TeX-current-macro) can take time, so we just
+               ;; check if one of the `car' in preferred-suffix-rules
+               ;; is found before point on the current line.  It
+               ;; should cover most cases.
+               (save-excursion
+                 (re-search-backward (regexp-opt
+                                      (mapcar 'car preferred-suffix-rules))
+                                     (point-at-bol)
+                                     t))
+             (push (cons "" (cdr (assoc (match-string 0) ; i.e. "(TeX-current-macro)"
+                                        preferred-suffix-rules)))
+                   guess-rules))
+           (with-temp-buffer
+             (let ((process-environment (buffer-local-value
+                                         'process-environment curbuf))
+                   (exec-path (buffer-local-value 'exec-path curbuf)))
+               (apply #'call-process "kpsewhich" nil t nil
+                      (mapcar (lambda (rule)
+                                          (concat (car rule) name (cdr rule)))
+                                        guess-rules)))
+             (when (< (point-min) (point-max))
+               (buffer-substring (goto-char (point-min)) (point-at-eol))))))))
 
 (defun ffap-tex (name)
   (ffap-tex-init)
@@ -1004,7 +1068,7 @@ If a given RFC isn't in these then `ffap-rfc-path' is offered."
     ;; Slightly controversial decisions:
     ;; * strip trailing "@" and ":"
     ;; * no commas (good for latex)
-    (file "--:\\\\$\\{\\}+<>@-Z_[:alpha:]~*?" "<@" "@>;.,!:")
+    (file "--:\\\\${}+<>@-Z_[:alpha:]~*?" "<@" "@>;.,!:")
     ;; An url, or maybe a email/news message-id:
     (url "--:=&?$+@-Z_[:alpha:]~#,%;*()!'" "^[0-9a-zA-Z]" ":;.,!?")
     ;; Find a string that does *not* contain a colon:
@@ -1013,6 +1077,9 @@ If a given RFC isn't in these then `ffap-rfc-path' is offered."
     (machine "-[:alnum:]." "" ".")
     ;; Mathematica paths: allow backquotes
     (math-mode ",-:$+<>@-Z_[:lower:]~`" "<" "@>;.,!?`:")
+    ;; (La)TeX: don't allow braces
+    (latex-mode "--:\\\\$+<>@-Z_[:alpha:]~*?" "<@" "@>;.,!:")
+    (tex-mode "--:\\\\$+<>@-Z_[:alpha:]~*?" "<@" "@>;.,!:")
     )
   "Alist of (MODE CHARS BEG END), where MODE is a symbol,
 possibly a major-mode name, or one of the symbols