]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix `W' in Dired with non-ASCII file names
authorLars Ingebrigtsen <larsi@gnus.org>
Mon, 7 Mar 2022 02:27:55 +0000 (03:27 +0100)
committerLars Ingebrigtsen <larsi@gnus.org>
Mon, 7 Mar 2022 02:28:32 +0000 (03:28 +0100)
* lisp/net/browse-url.el (browse-url--file-name-coding-system):
Factor out into own function.
(browse-url-file-url): Property encode non-ASCII characters so
that external browsers can understand them.
(browse-url-emacs): Make `W' in Dired work with non-ASCII file
names (bug#54271).

lisp/net/browse-url.el
test/lisp/net/browse-url-tests.el

index e4c485eccde5888583ea4ddf6b4fa4dcdcdad083..ccb4e12a9f13daca024d69daa23b23f5b5c4906e 100644 (file)
@@ -708,16 +708,29 @@ interactively.  Turn the filename into a URL with function
   (browse-url (browse-url-file-url file))
   (run-hooks 'browse-url-of-file-hook))
 
+(defun browse-url--file-name-coding-system ()
+  (if (equal system-type 'windows-nt)
+      ;; W32 pretends that file names are UTF-8 encoded.
+      'utf-8
+    (or file-name-coding-system default-file-name-coding-system)))
+
 (defun browse-url-file-url (file)
   "Return the URL corresponding to FILE.
 Use variable `browse-url-filename-alist' to map filenames to URLs."
-  (let ((coding (if (equal system-type 'windows-nt)
-                   ;; W32 pretends that file names are UTF-8 encoded.
-                   'utf-8
-                 (and (or file-name-coding-system
-                          default-file-name-coding-system)))))
-    (if coding (setq file (encode-coding-string file coding))))
-  (setq file (browse-url-url-encode-chars file "[*\"()',=;?% ]"))
+  (when-let ((coding (browse-url--file-name-coding-system)))
+    (setq file (encode-coding-string file coding)))
+  (if (and (file-remote-p file)
+           ;; We're applying special rules for FTP URLs for historical
+           ;; reasons.
+           (seq-find (lambda (match)
+                       (and (string-match-p (car match) file)
+                            (not (string-match "\\`file:" (cadr match)))))
+                     browse-url-filename-alist))
+      (setq file (browse-url-url-encode-chars file "[*\"()',=;?% ]"))
+    ;; Encode all other file names properly.
+    (setq file (mapconcat #'url-hexify-string
+                          (file-name-split file)
+                          "/")))
   (dolist (map browse-url-filename-alist)
     (when (and map (string-match (car map) file))
       (setq file (replace-match (cdr map) t nil file))))
@@ -1213,10 +1226,12 @@ currently selected window instead."
   (require 'url-handlers)
   (let ((parsed (url-generic-parse-url url))
         (func (if same-window 'find-file 'find-file-other-window)))
-    (if (and (equal (url-type parsed) "file")
-             (file-directory-p (url-filename parsed)))
-        ;; It's a directory; just open it.
-        (funcall func (url-filename parsed))
+    (if (equal (url-type parsed) "file")
+        ;; It's a file; just open it.
+        (let ((file (url-unhex-string (url-filename parsed))))
+          (when-let ((coding (browse-url--file-name-coding-system)))
+            (setq file (decode-coding-string file 'utf-8)))
+          (funcall func file))
       (let ((file-name-handler-alist
              (cons (cons url-handler-regexp 'url-file-handler)
                    file-name-handler-alist)))
index 8f180f3d6bb67644115b3d209e5c42c507709d8c..c94719c97aff2a36fb78650af5f4b00df837b28c 100644 (file)
 
 (ert-deftest browse-url-tests-file-url ()
   (should (equal (browse-url-file-url "/foo") "file:///foo"))
-  (should (equal (browse-url-file-url "/foo:") "ftp://foo/"))
-  (should (equal (browse-url-file-url "/ftp@foo:") "ftp://foo/"))
-  (should (equal (browse-url-file-url "/anonymous@foo:")
-                 "ftp://foo/")))
+  (when (file-remote-p "/foo:")
+    (should (equal (browse-url-file-url "/foo:") "ftp://foo/")))
+  (when (file-remote-p "/ftp@foo:")
+    (should (equal (browse-url-file-url "/ftp@foo:") "ftp://foo/")))
+  (when (file-remote-p "/anonymous@foo:")
+    (should (equal (browse-url-file-url "/anonymous@foo:")
+                   "ftp://foo/"))))
 
 (ert-deftest browse-url-tests-delete-temp-file ()
   (ert-with-temp-file browse-url-temp-file-name