diff options
| author | Noam Postavsky | 2016-10-27 22:17:11 -0400 |
|---|---|---|
| committer | Noam Postavsky | 2016-12-11 21:36:08 -0500 |
| commit | a92a027d58cb4df5bb6c7e3c546a72183a192f45 (patch) | |
| tree | 6de406718d319b0a8d514548852a48c7583bcd96 | |
| parent | 2783e0e3899cf92910e97dc8bfda3e47b3df1478 (diff) | |
| download | emacs-a92a027d58cb4df5bb6c7e3c546a72183a192f45.tar.gz emacs-a92a027d58cb4df5bb6c7e3c546a72183a192f45.zip | |
Quote filenames containing '~' in prompts
When in a directory named '~', the default value given by
`read-file-name' should be quoted by prepending '/:', in order to
prevent it from being interpreted as referring to the $HOME
directory (Bug#16984).
* lisp/minibuffer.el (minibuffer-maybe-quote-filename): New function.
(completion--sifn-requote, read-file-name-default): Use it instead of
`minibuffer--double-dollars'.
* test/lisp/files-tests.el (files-test-read-file-in-~): Test it.
| -rw-r--r-- | lisp/minibuffer.el | 25 | ||||
| -rw-r--r-- | test/lisp/files-tests.el | 23 |
2 files changed, 41 insertions, 7 deletions
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index 175189c1b48..576b8041be9 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el | |||
| @@ -2251,6 +2251,17 @@ This is only used when the minibuffer area has no active minibuffer.") | |||
| 2251 | (replace-regexp-in-string "\\$" (lambda (dollar) (concat dollar dollar)) | 2251 | (replace-regexp-in-string "\\$" (lambda (dollar) (concat dollar dollar)) |
| 2252 | str)) | 2252 | str)) |
| 2253 | 2253 | ||
| 2254 | (defun minibuffer-maybe-quote-filename (filename) | ||
| 2255 | "Protect FILENAME from `substitute-in-file-name', as needed. | ||
| 2256 | Useful to give the user default values that won't be substituted." | ||
| 2257 | (if (and (not (file-name-quoted-p filename)) | ||
| 2258 | (file-name-absolute-p filename) | ||
| 2259 | (string-match-p (if (memq system-type '(windows-nt ms-dos)) | ||
| 2260 | "[/\\\\]~" "/~") | ||
| 2261 | (file-local-name filename))) | ||
| 2262 | (file-name-quote filename) | ||
| 2263 | (minibuffer--double-dollars filename))) | ||
| 2264 | |||
| 2254 | (defun completion--make-envvar-table () | 2265 | (defun completion--make-envvar-table () |
| 2255 | (mapcar (lambda (enventry) | 2266 | (mapcar (lambda (enventry) |
| 2256 | (substring enventry 0 (string-match-p "=" enventry))) | 2267 | (substring enventry 0 (string-match-p "=" enventry))) |
| @@ -2420,7 +2431,7 @@ same as `substitute-in-file-name'." | |||
| 2420 | (substitute-in-file-name | 2431 | (substitute-in-file-name |
| 2421 | (substring qstr 0 (1- qpos))))) | 2432 | (substring qstr 0 (1- qpos))))) |
| 2422 | (setq qpos (1- qpos))) | 2433 | (setq qpos (1- qpos))) |
| 2423 | (cons qpos #'minibuffer--double-dollars)))) | 2434 | (cons qpos #'minibuffer-maybe-quote-filename)))) |
| 2424 | 2435 | ||
| 2425 | (defalias 'completion--file-name-table | 2436 | (defalias 'completion--file-name-table |
| 2426 | (completion-table-with-quoting #'completion-file-name-table | 2437 | (completion-table-with-quoting #'completion-file-name-table |
| @@ -2596,10 +2607,10 @@ See `read-file-name' for the meaning of the arguments." | |||
| 2596 | (let ((insdef (cond | 2607 | (let ((insdef (cond |
| 2597 | ((and insert-default-directory (stringp dir)) | 2608 | ((and insert-default-directory (stringp dir)) |
| 2598 | (if initial | 2609 | (if initial |
| 2599 | (cons (minibuffer--double-dollars (concat dir initial)) | 2610 | (cons (minibuffer-maybe-quote-filename (concat dir initial)) |
| 2600 | (length (minibuffer--double-dollars dir))) | 2611 | (length (minibuffer-maybe-quote-filename dir))) |
| 2601 | (minibuffer--double-dollars dir))) | 2612 | (minibuffer-maybe-quote-filename dir))) |
| 2602 | (initial (cons (minibuffer--double-dollars initial) 0))))) | 2613 | (initial (cons (minibuffer-maybe-quote-filename initial) 0))))) |
| 2603 | 2614 | ||
| 2604 | (let ((completion-ignore-case read-file-name-completion-ignore-case) | 2615 | (let ((completion-ignore-case read-file-name-completion-ignore-case) |
| 2605 | (minibuffer-completing-file-name t) | 2616 | (minibuffer-completing-file-name t) |
| @@ -2693,7 +2704,7 @@ See `read-file-name' for the meaning of the arguments." | |||
| 2693 | ;; with what we will actually return. As an exception, | 2704 | ;; with what we will actually return. As an exception, |
| 2694 | ;; if that's the same as the second item in | 2705 | ;; if that's the same as the second item in |
| 2695 | ;; file-name-history, it's really a repeat (Bug#4657). | 2706 | ;; file-name-history, it's really a repeat (Bug#4657). |
| 2696 | (let ((val1 (minibuffer--double-dollars val))) | 2707 | (let ((val1 (minibuffer-maybe-quote-filename val))) |
| 2697 | (if history-delete-duplicates | 2708 | (if history-delete-duplicates |
| 2698 | (setcdr file-name-history | 2709 | (setcdr file-name-history |
| 2699 | (delete val1 (cdr file-name-history)))) | 2710 | (delete val1 (cdr file-name-history)))) |
| @@ -2703,7 +2714,7 @@ See `read-file-name' for the meaning of the arguments." | |||
| 2703 | (if add-to-history | 2714 | (if add-to-history |
| 2704 | ;; Add the value to the history--but not if it matches | 2715 | ;; Add the value to the history--but not if it matches |
| 2705 | ;; the last value already there. | 2716 | ;; the last value already there. |
| 2706 | (let ((val1 (minibuffer--double-dollars val))) | 2717 | (let ((val1 (minibuffer-maybe-quote-filename val))) |
| 2707 | (unless (and (consp file-name-history) | 2718 | (unless (and (consp file-name-history) |
| 2708 | (equal (car file-name-history) val1)) | 2719 | (equal (car file-name-history) val1)) |
| 2709 | (setq file-name-history | 2720 | (setq file-name-history |
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index 80d5e5befbc..f4ccd5c2044 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el | |||
| @@ -220,5 +220,28 @@ form.") | |||
| 220 | (should-not yes-or-no-p-prompts) | 220 | (should-not yes-or-no-p-prompts) |
| 221 | (should (equal kill-emacs-args '(nil))))) | 221 | (should (equal kill-emacs-args '(nil))))) |
| 222 | 222 | ||
| 223 | (ert-deftest files-test-read-file-in-~ () | ||
| 224 | "Test file prompting in directory named '~'. | ||
| 225 | If we are in a directory named '~', the default value should not | ||
| 226 | be $HOME." | ||
| 227 | (cl-letf (((symbol-function 'completing-read) | ||
| 228 | (lambda (_prompt _coll &optional _pred _req init _hist def _) | ||
| 229 | (or def init))) | ||
| 230 | (dir (make-temp-file "read-file-name-test" t))) | ||
| 231 | (unwind-protect | ||
| 232 | (let ((subdir (expand-file-name "./~/"))) | ||
| 233 | (make-directory subdir t) | ||
| 234 | (with-temp-buffer | ||
| 235 | (setq default-directory subdir) | ||
| 236 | (should-not (equal | ||
| 237 | (expand-file-name (read-file-name "File: ")) | ||
| 238 | (expand-file-name "~/"))) | ||
| 239 | ;; Don't overquote either! | ||
| 240 | (setq default-directory (concat "/:" subdir)) | ||
| 241 | (should-not (equal | ||
| 242 | (expand-file-name (read-file-name "File: ")) | ||
| 243 | (concat "/:/:" subdir))))) | ||
| 244 | (delete-directory dir 'recursive)))) | ||
| 245 | |||
| 223 | (provide 'files-tests) | 246 | (provide 'files-tests) |
| 224 | ;;; files-tests.el ends here | 247 | ;;; files-tests.el ends here |