about summary refs log tree commit diff
path: root/Completion/Unix
diff options
context:
space:
mode:
authorEric Cook <illua@users.sourceforge.net>2024-08-03 20:07:51 -0400
committerEric Cook <illua@users.sourceforge.net>2024-08-03 20:07:51 -0400
commit5cb32ec5ab1eafdad62500e7e6bdada2c3205a59 (patch)
treea254f3489e9783f46ff20727bf871f74d6e3e99c /Completion/Unix
parent0bb140f9911851e9712dba311925f9c9ab521fd2 (diff)
downloadzsh-5cb32ec5ab1eafdad62500e7e6bdada2c3205a59.tar.gz
zsh-5cb32ec5ab1eafdad62500e7e6bdada2c3205a59.tar.xz
zsh-5cb32ec5ab1eafdad62500e7e6bdada2c3205a59.zip
52989: _rsync: support rsync 3.2.4+ remote filename handling.
Diffstat (limited to 'Completion/Unix')
-rw-r--r--Completion/Unix/Command/_rsync10
-rw-r--r--Completion/Unix/Type/_remote_files20
2 files changed, 24 insertions, 6 deletions
diff --git a/Completion/Unix/Command/_rsync b/Completion/Unix/Command/_rsync
index c65266dbd..81d25a3f4 100644
--- a/Completion/Unix/Command/_rsync
+++ b/Completion/Unix/Command/_rsync
@@ -60,7 +60,14 @@ elif compset -P 1 '*::' || compset -P 1 'rsync://*/'; then
 elif compset -P 'rsync://'; then
   _rsync_user_or_host / "$@"
 elif compset -P 1 '*:'; then
-  _remote_files -- ssh
+  if [[ -v opt_args[(i)client---old-args] || $RSYNC_OLD_ARGS = 1 ]]; then
+    _remote_files -- ssh
+  else
+    # the 3.2.4+ way that rsync handles filenames does not protect *, ? and []
+    # so those characters still need to be escaped to prevent being treated as
+    # a pattern in the remote shell.
+    _remote_files -Q '[][*?]' -- ssh
+  fi
 else
   _rsync_user_or_host : "$@"
 fi
@@ -236,6 +243,7 @@ _rsync() {
     '*--include=[do not exclude files matching pattern]:pattern' \
     '--files-from=[read list of source-file names from specified file]:file:_files' \
     '(-0 --from0)'{-0,--from0}'[all *-from file lists are delimited by nulls]' \
+    '--old-args[disable the modern arg-protection idiom]' \
     '(-s --secluded-args)'{-s,--secluded-args}'[use the protocol to safely send arguments]' \
     "--trust-sender[trust the remote sender's file list]" \
     '--copy-as=[specify user & optional group for the copy]:user:_rsync_users_groups' \
diff --git a/Completion/Unix/Type/_remote_files b/Completion/Unix/Type/_remote_files
index 93e1b7f43..15c20e5c1 100644
--- a/Completion/Unix/Type/_remote_files
+++ b/Completion/Unix/Type/_remote_files
@@ -11,6 +11,8 @@
 # - -g: specify a pattern to match against files
 #       p, = and * glob qualifiers supported
 # - -h: specify the remote host, default is ${IPREFIX%:}
+# - -Q: specify a pattern of characters to escape in the returned filenames,
+#       instead of shell metacharacters that ${(q)name} does
 # - -W: specify the parent directory to list files from,
 #       default is the home directory
 #
@@ -31,14 +33,14 @@
 
 
 # There should be coloring based on all the different ls -F classifiers.
-local expl rempat remfiles remdispf remdispd args cmd suf ret=1
+local expl rempat remfiles remdispf{,q} remdispd{,q} args cmd suf ret=1
 local -a args cmd_args
-local glob host dir dirprefix
+local glob host dir esc dirprefix
 
 if zstyle -T ":completion:${curcontext}:files" remote-access; then
 
   # Parse options to _remote_files. Stops at the first "--".
-  zparseopts -D -E -a args / g:=glob h:=host W:=dir
+  zparseopts -D -E -a args / g:=glob h:=host W:=dir Q:=esc
   (( $#host)) && shift host || host="${IPREFIX%:}"
 
   args=( ${argv[1,(i)--]} )
@@ -85,6 +87,14 @@ if zstyle -T ":completion:${curcontext}:files" remote-access; then
     remdispf=( ${(M)remdispf:#${~glob[2]}} )
   fi
 
+  if (( $#esc )); then
+    remdispfq=(${${remdispf%[*=|]}//(#b)(${~esc[2]})/\\$match[1]})
+    remdispdq=(${${remdispd%/}//(#b)(${~esc[2]})/\\$match[1]})
+  else
+    remdispfq=(${(q)remdispf%[*=|]})
+    remdispdq=(${(q)remdispd%/})
+  fi
+
   local -a autoremove
   [[ -o autoremoveslash ]] && autoremove=(-r "/ \t\n\-")
 
@@ -92,9 +102,9 @@ if zstyle -T ":completion:${curcontext}:files" remote-access; then
   while _tags; do
     while _next_label remote-files expl ${suf:-remote directory}; do
       [[ -n $suf ]] &&
-          compadd "$args[@]" "$expl[@]" -d remdispf -- ${(q)remdispf%[*=|]} && ret=0
+        compadd "$args[@]" "$expl[@]" -d remdispf -- $remdispfq && ret=0
       compadd ${suf:+-S/} $autoremove "$args[@]" "$expl[@]" -d remdispd \
-	-- ${(q)remdispd%/} && ret=0
+        -- $remdispdq && ret=0
     done
     (( ret )) || return 0
   done