about summary refs log tree commit diff
path: root/Completion
diff options
context:
space:
mode:
authorDaniel Shahaf <d.s@daniel.shahaf.name>2022-01-26 14:18:45 +0000
committerDaniel Shahaf <d.s@daniel.shahaf.name>2022-01-29 10:08:42 +0000
commita803a5f4c46629c18c05a9ee09d5ae34407e35c4 (patch)
tree12bd900db2a611a5118744c96d67767b6317af14 /Completion
parentcb2b0e7c6cdd851f79b6856335e8ab7a3d3d1935 (diff)
downloadzsh-a803a5f4c46629c18c05a9ee09d5ae34407e35c4.tar.gz
zsh-a803a5f4c46629c18c05a9ee09d5ae34407e35c4.tar.xz
zsh-a803a5f4c46629c18c05a9ee09d5ae34407e35c4.zip
49713: _subversion: commit, diff, revert: Update completions for svn 1.7 and newer
* _svn_deletedfiles: Remove.
    The last version of svn(1) under which that function could possibly
    complete anything, svn 1.6.x, was EOLed in 2013.  Newer versions
    don't have a "text-base" directory, so $controlled is set to an
    empty array, so this function returned false for all files, so
    in 'svn rm' (up to the previous commit) all files were completed
    (because that's what '_files -g "*(e:false:)"' does).

* _svn_status: Remove.
    Versions of svn newer than the aforementioned 1.6.x have an
    entries file but never modify it, so the "mtime has changed" check
    would false negative.  Therefore, sequences such as:
    .
        svn <TAB>
        echo >> some/versioned/file
        svn ci <TAB>
    .
    wouldn't offer some/versioned/file.
    .
    Furthermore, completion would offer directories with no changed
    files in them, and even unversioned directories.  Now only changed
    files/directories are offered.

* _cache_svn_status, _cache_svn_mtime: Remove.
    If these hadn't been removed, I would have moved their declarations
    to file scope so _svn_status could be used from outside this file,
    too.

The replacement function, _svn_modified, doesn't have cache support, but
does honour the 'verbose' style to inhibit recursion to subdirectories.
Diffstat (limited to 'Completion')
-rw-r--r--Completion/Unix/Command/_subversion69
1 files changed, 43 insertions, 26 deletions
diff --git a/Completion/Unix/Command/_subversion b/Completion/Unix/Command/_subversion
index 9ef3077f6..cb5cbd374 100644
--- a/Completion/Unix/Command/_subversion
+++ b/Completion/Unix/Command/_subversion
@@ -68,7 +68,6 @@ _svn () {
     ;;
     args)
       local cmd args usage idx
-      typeset -gHA _cache_svn_status _cache_svn_mtime
 
       cmd="${${(k)_svn_cmds[(R)*:$words[1]:*]}:-${(k)_svn_cmds[(i):$words[1]:]}}"
       if (( $#cmd )); then
@@ -141,7 +140,7 @@ _svn () {
           (commit)
             args=(
 	      ${args/(#b)(*--file*):arg:/$match[1]:file:_files}
-              '*:file:_files -g "*(e:_svn_status:)"'
+              '*:file: _svn_modified "committable"'
             )
           ;;
           (delete)
@@ -151,7 +150,7 @@ _svn () {
           ;;
           (diff)
             args+=(
-	      '*: : _alternative "files:file:_files -g \*\(e:_svn_status:\)" "urls:URL:_svn_urls"'
+	      '*: : _alternative "files:file: _svn_modified revertable" "urls:URL:_svn_urls"'
 	    )
           ;;
           (help)
@@ -201,7 +200,7 @@ _svn () {
           ;;
           (revert)
             args+=(
-              '*:file:_files -g "(.svn|*)(/e:_svn_deletedfiles:,e:_svn_status:)"'
+              '*:file: _svn_modified "revertable"'
             )
           ;;
           (x-unshelve)
@@ -368,33 +367,51 @@ _svn_conflicts() {
   () { (( $# > 0 )) } $REPLY.(mine|r<->)(NY1)
 }
 
-(( $+functions[_svn_deletedfiles] )) ||
-_svn_deletedfiles() {
-  # Typical usage would be _files -g '.svn(/e:_svn_deletedfiles:)'
-  local cont controlled
-  reply=( )
-  [[ $REPLY = (*/|).svn ]] || return
-  controlled=( $REPLY/text-base/*.svn-base(N:r:t) )
-  for cont in ${controlled}; do
-    [[ -e $REPLY:h/$cont ]] || reply+=( ${REPLY%.svn}$cont )
-  done
-}
+(( $+functions[_svn_modified] )) ||
+_svn_modified() {
+  setopt localoptions extendedglob
 
-(( $+functions[_svn_status] )) ||
-_svn_status() {
-  local dir=$REPLY:h
-  local pat="${1:-([ADMR~]|?M)}"
+  local depth dir expl partial_word space=' '
 
-  zmodload -F zsh/stat b:zstat 2>/dev/null
-  local key="$(zstat +device $dir):$(zstat +inode $dir)"
-  local mtime="$(zstat +mtime $dir/.svn/entries)"
+  local svn_context=$1
 
-  if (( ! $+_cache_svn_status[$key] || _cache_svn_mtime[$key] != mtime )); then
-    _cache_svn_status[$key]="$(_call_program files svn status -q -N -- $dir)"
-    _cache_svn_mtime[$key]="$mtime"
+  local partial_word=${(Q)words[CURRENT]}
+  if [[ -z $partial_word ]]; then
+    dir="./"
+  elif [[ -d $partial_word ]]; then
+    dir=$partial_word
+  else
+    dir=${partial_word:h}
   fi
 
-  (( ${(M)#${(f)_cache_svn_status[$key]}:#(#s)${~pat}*$REPLY} ))
+  if zstyle -T ":completion:${curcontext}:${curtag}" verbose; then
+    depth=infinity
+  else
+    depth=immediates
+  fi
+
+  local -a status_lines
+  # Run 'status'
+  status_lines=( ${(f)"$(_call_program modified-files "svn status -q --depth=${(q)depth} -- ${(q)dir}")"} )
+  # Filter to only the right set of statuses
+  case $svn_context in
+    (committable)
+      status_lines=( ${(M)status_lines:#(#s)([ADMR]?|?M)${space}???${space}${space}*} )
+      ;;
+    (revertable)
+      status_lines=( ${(M)status_lines:#(#s)([ACDMR~!]?|?[CM])${space}????${space}*} )
+      ;;
+  esac
+  # Strip the 7 status-letter columns and the column of spaces
+  status_lines=( ${status_lines#????????} )
+  # Strip one leading space.  This is in case `svn status` ever adds another
+  # column.  If that hasn't happened and you're reading this comment because
+  # the following line broke your use of filenames that start with a literal
+  # space, well, nice to meet you!  I didn't know you existed.
+  status_lines=( ${status_lines#${space}} )
+
+  _wanted svn-modified expl 'modified files in svn' \
+    compadd - "${status_lines[@]}"
 }
 
 (( $+functions[_svn_remote_paths] )) ||