From 2f988221a77ac18edc3046a1294ae85145030f8d Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sun, 22 Jun 2025 17:29:52 +0200 Subject: [PATCH] Tramp: Cache also `file-executable-p' in `file-name-all-completions' * lisp/net/tramp-archive.el (tramp-archive-autoload-file-name-regexp): Fix comment. * lisp/net/tramp-sh.el (tramp-perl-file-name-all-completions): Cache also `file-executable-p'. Suggested by . (tramp-shell-file-name-all-completions): New script. (tramp-bundle-read-file-names): Fix for special characters. Cache also `file-executable-p'. (tramp-sh-handle-file-name-all-completions): Unify different cases. * lisp/net/tramp.el (with-tramp-suspended-timers, without-remote-files): Fix debug spec. (cherry picked from commit 87fc539a0b4d7f84d1697e8479158b30c09b4e49) --- lisp/net/tramp-archive.el | 4 +- lisp/net/tramp-sh.el | 122 ++++++++++++++++++++------------------ lisp/net/tramp.el | 4 +- 3 files changed, 69 insertions(+), 61 deletions(-) diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el index 9df2b657e91..0a1c44d3673 100644 --- a/lisp/net/tramp-archive.el +++ b/lisp/net/tramp-archive.el @@ -176,8 +176,8 @@ It must be supported by libarchive(3).") It must be supported by libarchive(3).") ;; The definition of `tramp-archive-file-name-regexp' contains calls -;; to `regexp-opt', which cannot be autoloaded while loading -;; loaddefs.el. So we use a macro, which is evaluated only when needed. +;; to `rx', which cannot be autoloaded while loading loaddefs.el. So +;; we use a macro, which is evaluated only when needed. ;;;###autoload (progn (defmacro tramp-archive-autoload-file-name-regexp () "Regular expression matching archive file names." diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 7ef6cb3de95..1be2c1628ee 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -731,18 +731,31 @@ print \"(\\n\"; foreach $f (@files) { ($p = $f) =~ s/\\\"/\\\\\\\"/g; ($q = \"$dir/$f\") =~ s/\\\"/\\\\\\\"/g; - print \"(\", - ((-d \"$q\") ? \"\\\"$p/\\\" \\\"$q\\\" t\" : \"\\\"$p\\\" \\\"$q\\\" nil\"), + print \"(\\\"$q\\\"\", ((-e \"$q\") ? \" t\" : \" nil\"), ((-r \"$q\") ? \" t\" : \" nil\"), + ((-d \"$q\") ? \" t\" : \" nil\"), + ((-x \"$q\") ? \" t\" : \" nil\"), \")\\n\"; } print \")\\n\"; ' \"$1\" %n" "Perl script to produce output suitable for use with -`file-name-all-completions' on the remote file system. -Format specifiers are replaced by `tramp-expand-script', percent -characters need to be doubled.") +`file-name-all-completions' on the remote file system. It returns the +same format as `tramp-bundle-read-file-names'. Format specifiers are +replaced by `tramp-expand-script', percent characters need to be +doubled.") + +(defconst tramp-shell-file-name-all-completions + "cd \"$1\" 2>&1; %l -a %n | while IFS= read file; do + quoted=`echo \"$1/$file\" | sed -e \"s#//#/#g\" -e \"s/\\\"/\\\\\\\\\\\\\\\\\\\"/g\"` + printf \"%%b\n\" \"$quoted\" + done | tramp_bundle_read_file_names" + "Shell script to produce output suitable for use with +`file-name-all-completions' on the remote file system. It returns the +same format as `tramp-bundle-read-file-names'. Format specifiers are +replaced by `tramp-expand-script', percent characters need to be +doubled.") ;; Perl script to implement `file-attributes' in a Lisp `read'able ;; output. If you are hacking on this, note that you get *no* output @@ -1172,21 +1185,22 @@ characters need to be doubled.") (defconst tramp-bundle-read-file-names "echo \"(\" -while read file; do - quoted=`echo \"$file\" | sed -e \"s/\\\"/\\\\\\\\\\\\\\\\\\\"/\"` +while IFS= read file; do + quoted=`echo \"$file\" | sed -e \"s/\\\"/\\\\\\\\\\\\\\\\\\\"/g\"` printf \"(%%b\" \"\\\"$quoted\\\"\" if %q \"$file\"; then printf \" %%b\" t; else printf \" %%b\" nil; fi if %m -r \"$file\"; then printf \" %%b\" t; else printf \" %%b\" nil; fi - if %m -d \"$file\"; then printf \" %%b)\n\" t; else printf \" %%b)\n\" nil; fi + if %m -d \"$file\"; then printf \" %%b\" t; else printf \" %%b\" nil; fi + if %m -x \"$file\"; then printf \" %%b)\n\" t; else printf \" %%b)\n\" nil; fi done echo \")\"" - "Script to check file attributes of a bundle of files. -It must be sent formatted with three strings; the tests for file -existence, file readability, and file directory. Input shall be -read via here-document, otherwise the command could exceed -maximum length of command line. -Format specifiers \"%s\" are replaced before the script is used, -percent characters need to be doubled.") + "Shell script to check file attributes of a bundle of files. +For every file, it returns a list with the absolute file name, and the +tests for file existence, file readability, file directory, and file +executable. Input shall be read via here-document, otherwise the +command could exceed maximum length of command line. Format specifiers +\"%s\" are replaced before the script is used, percent characters need +to be doubled.") ;; New handlers should be added here. ;;;###tramp-autoload @@ -1947,47 +1961,40 @@ ID-FORMAT valid values are `string' and `integer'." ;; reliably tagging the directories with a trailing "/". ;; Because I rock. --daniel@danann.net (if (tramp-get-remote-perl v) - (progn - (tramp-maybe-send-script - v tramp-perl-file-name-all-completions - "tramp_perl_file_name_all_completions") - (setq result - (tramp-send-command-and-read - v (format "tramp_perl_file_name_all_completions %s" - (tramp-shell-quote-argument localname)) - 'noerror)) - ;; Cached values. - (dolist (elt result) - (tramp-set-file-property - v (cadr elt) "file-directory-p" (nth 2 elt)) - (tramp-set-file-property - v (cadr elt) "file-exists-p" (nth 3 elt)) - (tramp-set-file-property - v (cadr elt) "file-readable-p" (nth 4 elt))) - ;; Result. - (mapcar #'car result)) - - ;; Do it with ls. - (when (tramp-send-command-and-check - v (format (concat - "cd %s 2>&1 && %s -a 2>%s" - " | while IFS= read f; do" - " if %s -d \"$f\" 2>%s;" - " then echo \"$f/\"; else echo \"$f\"; fi;" - " done") - (tramp-shell-quote-argument localname) - (tramp-get-ls-command v) - (tramp-get-remote-null-device v) - (tramp-get-test-command v) - (tramp-get-remote-null-device v))) - - ;; Now grab the output. - (with-current-buffer (tramp-get-buffer v) - (goto-char (point-max)) - (while (zerop (forward-line -1)) - (push - (buffer-substring (point) (line-end-position)) result))) - result)))))))))) + (tramp-maybe-send-script + v tramp-perl-file-name-all-completions + "tramp_perl_file_name_all_completions") + ;; Used in `tramp-shell-file-name-all-completions'. + (tramp-maybe-send-script + v tramp-bundle-read-file-names "tramp_bundle_read_file_names") + (tramp-maybe-send-script + v tramp-shell-file-name-all-completions + "tramp_shell_file_name_all_completions")) + + (dolist + (elt + (tramp-send-command-and-read + v (format + "%s %s" + (if (tramp-get-remote-perl v) + "tramp_perl_file_name_all_completions" + "tramp_shell_file_name_all_completions") + (tramp-shell-quote-argument localname)) + 'noerror) + result) + ;; Don't cache "." and "..". + (when (string-match-p + directory-files-no-dot-files-regexp + (file-name-nondirectory (car elt))) + (tramp-set-file-property v (car elt) "file-exists-p" (nth 1 elt)) + (tramp-set-file-property v (car elt) "file-readable-p" (nth 2 elt)) + (tramp-set-file-property v (car elt) "file-directory-p" (nth 3 elt)) + (tramp-set-file-property v (car elt) "file-executable-p" (nth 4 elt))) + + (push + (concat + (file-name-nondirectory (car elt)) (and (nth 3 elt) "/")) + result)))))))))) (defun tramp-sh-handle-file-name-completion-annotation (filename) "Like `file-name-completion-annotation' for Tramp files." @@ -3649,7 +3656,8 @@ filled are described in `tramp-bundle-read-file-names'." (tramp-set-file-property vec (car elt) "file-exists-p" (nth 1 elt)) (tramp-set-file-property vec (car elt) "file-readable-p" (nth 2 elt)) - (tramp-set-file-property vec (car elt) "file-directory-p" (nth 3 elt))))) + (tramp-set-file-property vec (car elt) "file-directory-p" (nth 3 elt)) + (tramp-set-file-property vec (car elt) "file-executable-p" (nth 4 elt))))) (defvar tramp-vc-registered-file-names nil "List used to collect file names, which are checked during `vc-registered'.") diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index 0f7b945f84a..0d7b157c857 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -2218,7 +2218,7 @@ This shouldn't be changed globally, but let-bind where needed.") (defmacro with-tramp-suspended-timers (&rest body) "Run BODY with suspended timers. Obey `tramp-dont-suspend-timers'." - (declare (indent 0) (debug ((form body) body))) + (declare (indent 0) (debug t)) `(if tramp-dont-suspend-timers (progn ,@body) (let ((stimers (with-timeout-suspend)) @@ -2759,7 +2759,7 @@ whether HANDLER is to be called. Add operations defined in (progn (defmacro without-remote-files (&rest body) "Deactivate remote file names temporarily. Run BODY." - (declare (indent 0) (debug ((form body) body))) + (declare (indent 0) (debug t)) `(let ((file-name-handler-alist (copy-tree file-name-handler-alist)) tramp-mode) (tramp-unload-file-name-handlers) -- 2.39.5