diff options
Diffstat (limited to 'lisp/ffap.el')
-rw-r--r-- | lisp/ffap.el | 166 |
1 files changed, 152 insertions, 14 deletions
diff --git a/lisp/ffap.el b/lisp/ffap.el index e60478c0b26..ccba2911445 100644 --- a/lisp/ffap.el +++ b/lisp/ffap.el @@ -54,6 +54,8 @@ ;; C-x 5 r ffap-read-only-other-frame ;; C-x 5 d ffap-dired-other-frame ;; +;; C-x t f ffap-other-tab +;; ;; S-mouse-3 ffap-at-mouse ;; C-S-mouse-3 ffap-menu ;; @@ -108,8 +110,6 @@ (require 'url-parse) (require 'thingatpt) -(define-obsolete-variable-alias 'ffap-version 'emacs-version "23.2") - (defgroup ffap nil "Find file or URL at point." :group 'matching @@ -1080,7 +1080,7 @@ If a given RFC isn't in these then `ffap-rfc-path' is offered." ;; Slightly controversial decisions: ;; * strip trailing "@", ":" and enclosing "{"/"}". ;; * no commas (good for latex) - (file "--:\\\\${}+<>@-Z_[:alpha:]~*?" "{<@" "@>;.,!:}") + (file "--:\\\\${}+<>@-Z_[:alpha:]~*?#" "{<@" "@>;.,!:}") ;; An url, or maybe an email/news message-id: (url "--:=&?$+@-Z_[:alpha:]~#,%;*()!'" "^[0-9a-zA-Z]" ":;.,!?") ;; Find a string that does *not* contain a colon: @@ -1107,6 +1107,121 @@ The arguments CHARS, BEG and END are handled as described in ;; Added at suggestion of RHOGEE (for ff-paths), 7/24/95. "Last string returned by the function `ffap-string-at-point'.") +(defcustom ffap-file-name-with-spaces nil + "If non-nil, enable looking for paths with spaces in `ffap-string-at-point'. +Enabling this variable may lead to `find-file-at-point' guessing +wrong more often when trying to find a file name intermingled +with normal text, but can be useful when working on systems that +normally use spaces in file names (like Microsoft Windows and the +like)." + :type 'boolean + :version "28.1") + +(defun ffap-search-backward-file-end (&optional dir-separator end) + "Search backward position point where file would probably end. +Optional DIR-SEPARATOR defaults to \"/\". The search maximum is +`line-end-position' or optional END point. + +Suppose the cursor is somewhere that might be near end of file, +the guessing would position point before punctuation (like comma) +after the file extension: + + C:\temp\file.log, which contain .... + =============================== (before) + ---------------- (after) + + + C:\temp\file.log on Windows or /tmp/file.log on Unix + =============================== (before) + ---------------- (after) + +The strategy is to search backward until DIR-SEPARATOR which defaults to +\"/\" and then take educated guesses. + +Move point and return point if an adjustment was done." + (unless dir-separator + (setq dir-separator "/")) + (let ((opoint (point)) + point punct end whitespace-p) + (when (re-search-backward + (regexp-quote dir-separator) (line-beginning-position) t) + ;; Move to the beginning of the match.. + (forward-char 1) + ;; ... until typical punctuation. + (when (re-search-forward "\\([][<>()\"'`,.:;]\\)" + (or end + (line-end-position)) + t) + (setq end (match-end 0)) + (setq punct (match-string 1)) + (setq whitespace-p (looking-at "[ \t\r\n]\\|$")) + (goto-char end) + (cond + ((and (string-equal punct ".") + whitespace-p) ;end of sentence + (setq point (1- (point)))) + ((and (string-equal punct ".") + (looking-at "[a-zA-Z0-9.]+")) ;possibly file extension + (setq point (match-end 0))) + (t + (setq point (point))))) + (goto-char opoint) + (when point + (goto-char point) + point)))) + +(defun ffap-search-forward-file-end (&optional dir-separator) + "Search DIR-SEPARATOR and position point at file's maximum ending. +This includes spaces. +Optional DIR-SEPARATOR defaults to \"/\". +Call `ffap-search-backward-file-end' to refine the ending point." + (unless dir-separator + (setq dir-separator "/")) + (let* ((chars ;expected chars in file name + (concat "[^][^<>()\"'`;,#*|" + ;; exclude the opposite as we know the separator + (if (string-equal dir-separator "/") + "\\\\" + "/") + "\t\r\n]")) + (re (concat + chars "*" + (if dir-separator + (regexp-quote dir-separator) + "/") + chars "*"))) + (when (looking-at re) + (goto-char (match-end 0))))) + +(defun ffap-dir-separator-near-point () + "Search backward and forward for closest slash or backlash in line. +Return string slash or backslash. Point is moved to closest position." + (let ((point (point)) + str pos) + (when (looking-at ".*?/") + (setq str "/" + pos (match-end 0))) + (when (and (looking-at ".*?\\\\") + (or (null pos) + (< (match-end 0) pos))) + (setq str "\\" + pos (match-end 0))) + (goto-char point) + (when (and (re-search-backward "/" (line-beginning-position) t) + (or (null pos) + (< (- point (point)) (- pos point)))) + (setq str "/" + pos (1+ (point)))) ;1+ to keep cursor at the end of char + (goto-char point) + (when (and (re-search-backward "\\\\" (line-beginning-position) t) + (or (null pos) + (< (- point (point)) (- pos point)))) + (setq str "\\" + pos (1+ (point)))) + (when pos + (goto-char pos)) + str)) + (defun ffap-string-at-point (&optional mode) "Return a string of characters from around point. @@ -1126,7 +1241,8 @@ Set the variables `ffap-string-at-point' and When the region is active and larger than `ffap-max-region-length', return an empty string, and set `ffap-string-at-point-region' to '(1 1)." - (let* ((args + (let* (dir-separator + (args (cdr (or (assq (or mode major-mode) ffap-string-at-point-mode-alist) (assq 'file ffap-string-at-point-mode-alist)))) @@ -1135,14 +1251,25 @@ return an empty string, and set `ffap-string-at-point-region' to '(1 1)." (beg (if region-selected (region-beginning) (save-excursion - (skip-chars-backward (car args)) - (skip-chars-forward (nth 1 args) pt) + (if (and ffap-file-name-with-spaces + (memq mode '(nil file))) + (when (setq dir-separator (ffap-dir-separator-near-point)) + (while (re-search-backward + (regexp-quote dir-separator) + (line-beginning-position) t) + (goto-char (match-beginning 0)))) + (skip-chars-backward (car args)) + (skip-chars-forward (nth 1 args) pt)) (point)))) (end (if region-selected (region-end) (save-excursion (skip-chars-forward (car args)) (skip-chars-backward (nth 2 args) pt) + (when (and ffap-file-name-with-spaces + (memq mode '(nil file))) + (ffap-search-forward-file-end dir-separator) + (ffap-search-backward-file-end dir-separator)) (point)))) (region-len (- (max beg end) (min beg end)))) @@ -1607,7 +1734,7 @@ Each ALIST entry looks like (STRING . DATA) and defines one choice. Function CONT is applied to the entry chosen by the user." ;; Note: this function is used with a different continuation ;; by the ffap-url add-on package. - ;; Could try rewriting to use easymenu.el or lmenu.el. + ;; Could try rewriting to use easymenu.el. (let (choice) (cond ;; Emacs mouse: @@ -1624,7 +1751,7 @@ Function CONT is applied to the entry chosen by the user." ;; Bug: prompting may assume unique strings, no "". (setq choice (completing-read - (format "%s (default %s): " title (car (car alist))) + (format-prompt title (car (car alist))) alist nil t ;; (cons (car (car alist)) 0) nil))) @@ -1758,6 +1885,14 @@ Only intended for interactive use." (set-window-dedicated-p win wdp)) value)) +(defun ffap-other-tab (filename) + "Like `ffap', but put buffer in another tab. +Only intended for interactive use." + (interactive (list (ffap-prompter nil " other tab"))) + (pcase (save-window-excursion (find-file-at-point filename)) + ((or (and (pred bufferp) b) `(,(and (pred bufferp) b) . ,_)) + (switch-to-buffer-other-tab b)))) + (defun ffap--toggle-read-only (buffer-or-list) (dolist (buffer (if (listp buffer-or-list) buffer-or-list @@ -1791,6 +1926,14 @@ Only intended for interactive use." (ffap--toggle-read-only value) value)) +(defun ffap-read-only-other-tab (filename) + "Like `ffap', but put buffer in another tab and mark as read-only. +Only intended for interactive use." + (interactive (list (ffap-prompter nil " read only other tab"))) + (let ((value (window-buffer (ffap-other-tab filename)))) + (ffap--toggle-read-only value) + value)) + (defun ffap-alternate-file (filename) "Like `ffap' and `find-alternate-file'. Only intended for interactive use." @@ -1815,12 +1958,6 @@ Only intended for interactive use." (defalias 'find-file-literally-at-point 'ffap-literally) -;;; Bug Reporter: - -(define-obsolete-function-alias 'ffap-bug 'report-emacs-bug "23.1") -(define-obsolete-function-alias 'ffap-submit-bug 'report-emacs-bug "23.1") - - ;;; Hooks for Gnus, VM, Rmail: ;; ;; If you do not like these bindings, write versions with whatever @@ -2013,6 +2150,7 @@ This hook is intended to be put in `file-name-at-point-functions'." (global-set-key [remap find-file-other-window] 'ffap-other-window) (global-set-key [remap find-file-other-frame] 'ffap-other-frame) + (global-set-key [remap find-file-other-tab] 'ffap-other-tab) (global-set-key [remap find-file-read-only-other-window] 'ffap-read-only-other-window) (global-set-key [remap find-file-read-only-other-frame] 'ffap-read-only-other-frame) |