diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index 46e64c2a27..e4a1369a74 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -250,7 +250,7 @@ Visiting @end group @end example - With a prefix argument @kbd{C-u}, the meaning of + With a prefix argument @kbd{C-x &}, the meaning of @code{find-file-asynchronously} will be reverted. If this user option is @code{nil}, visiting a file is performed asynchronously. Contrary, if this user option is address@hidden, visiting a file is performed diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 9faa47b455..54737ebe64 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -119,7 +119,7 @@ Visiting Functions If @var{async} is address@hidden, the file will be loaded into the buffer asynchronously. Interactively, this is indicated by either setting user option @code{find-file-asynchronously} to address@hidden, -or by a prefix argument. +or by a prefix argument @kbd{C-x &}. When @code{find-file} is called interactively, it prompts for @var{filename} in the minibuffer. @@ -232,8 +232,8 @@ Visiting Functions If this variable is address@hidden, a file will be visited asynchronously when called interactively. If it is a regular expression, it must match the file name to be visited. This behavior -is toggled by a prefix argument to the interactive call of the file -visiting command. +is toggled by a prefix argument @kbd{C-x &} to the interactive call of +the file visiting command. @end defopt @defopt find-file-hook diff --git a/lisp/files.el b/lisp/files.el index 195694a7b6..ccdbaeb315 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -1576,14 +1576,56 @@ minibuffer-with-setup-hook ,@body) (remove-hook 'minibuffer-setup-hook ,hook))))) +(defun universal-file-visiting-argument (async) + "Execute a file visiting or saving command using the ASYNC argument. +See `find-file-asynchronously' for valid values of ASYNC." + (interactive + (list (and (featurep 'threads) (not find-file-asynchronously)))) + (let* ((find-file-asynchronously async) + (keyseq (read-key-sequence (format "Command to visit or save file:"))) + (cmd (key-binding keyseq)) + prefix) + ;; `read-key-sequence' ignores quit, so make an explicit check. + ;; Like many places, this assumes quit == C-g, but it need not be. + (if (equal last-input-event ?\C-g) + (keyboard-quit)) + (when (memq cmd '(universal-argument digit-argument)) + (call-interactively cmd) + + ;; Process keys bound in `universal-argument-map'. + (while (progn + (setq keyseq (read-key-sequence nil t) + cmd (key-binding keyseq t)) + (not (eq cmd 'universal-argument-other-key))) + (let ((current-prefix-arg prefix-arg) + ;; Have to bind `last-command-event' here so that + ;; `digit-argument', for instance, can compute the + ;; prefix arg. + (last-command-event (aref keyseq 0))) + (call-interactively cmd))) + + ;; This is the final call to `universal-argument-other-key', which + ;; set's the final `prefix-arg. + (let ((current-prefix-arg prefix-arg)) + (call-interactively cmd)) + + ;; Read the command to execute with the given prefix arg. + (setq prefix prefix-arg + keyseq (read-key-sequence nil t) + cmd (key-binding keyseq))) + + (let ((current-prefix-arg prefix)) + (message "") + (call-interactively cmd)))) + +(define-key ctl-x-map "&" 'universal-file-visiting-argument) + (defun find-file-read-args (prompt mustmatch &optional wildcards) "Return the interactive spec ( ). If WILDCARDS is non-nil, return the spec ( t )." (let ((filename (read-file-name prompt nil default-directory mustmatch)) - (async (and (xor find-file-asynchronously current-prefix-arg) - (featurep 'threads)))) - (when (and async (stringp find-file-asynchronously)) - (setq async (string-match-p find-file-asynchronously filename))) + (async (and (featurep 'threads) find-file-asynchronously))) + (when (stringp async) (setq async (string-match-p async filename))) (if wildcards `(,filename t ,async) `(,filename ,async)))) (defmacro find-file-with-threads (filename async &rest body) @@ -1794,8 +1836,8 @@ find-alternate-file-other-window (list (read-file-name "Find alternate file: " file-dir nil (confirm-nonexistent-file-or-buffer) file-name) - t (and (xor find-file-asynchronously current-prefix-arg) - (featurep 'threads)))))) + t (and (featurep 'threads) find-file-asynchronously))))) + (when (stringp async) (setq async (string-match-p async filename))) (if (one-window-p) (find-file-other-window filename wildcards async) (save-selected-window @@ -1839,8 +1881,8 @@ find-alternate-file (list (read-file-name "Find alternate file: " file-dir nil (confirm-nonexistent-file-or-buffer) file-name) - t (and (xor find-file-asynchronously current-prefix-arg) - (featurep 'threads))))) + t (and (featurep 'threads) find-file-asynchronously)))) + (when (stringp async) (setq async (string-match-p async filename))) (unless (run-hook-with-args-until-failure 'kill-buffer-query-functions) (user-error "Aborted")) (and (buffer-modified-p) buffer-file-name