Hi everyone,

I strongly felt the urge to have some way of bash-completing URLS from the command line when doing checkouts, listing, cat (for README/REVNOTES files) and so on... I looked up the "tools/client-side/bash_completion" script only to realize it works for local (file:///) but not remote URLs. So I came up with the attached patch, which works for me (tested with bash 4.1.2, svn 1.6.11) The idea was (apart from adding sub-dir completion with a gross "svn ls" command) to (manually) list known repositories within a ~/.svn_repos file, one per line:

http://srv1/proj1
svn://srv2/proj2

The reason behind this is that data cached in ~/.subversion/auth/svn.simple does not contain the full project URL (only the server name) and I could not find a way to get that information anywhere else.

I known it would've made more sense to ask for advice *BEFORE* touching the code, but still... :-)

Thanks in advance for your feedback!
Gerlando

P.S. I'm not subscribed to the list, so please Cc: me, thanks!
diff --git a/svn-completion.bash b/svn-completion.bash
index 12285f4..c2684b3 100644
--- a/svn-completion.bash
+++ b/svn-completion.bash
@@ -35,6 +35,12 @@
 
 shopt -s extglob
 
+function _debug()
+{
+   # echo "$@" >> /tmp/svn-completion.debug
+   true
+}
+
 # Tree helper functions which only use bash, to ease readability.
 
 # look for value associated to key from stdin in K/V hash file format
@@ -112,6 +118,53 @@ function _svn_lls()
     done
 }
 
+# _svn_remotels currUrl proto
+# e.g. currUrl = //server/project/dirprefix
+#      proto = http:
+# list svn files/dirs (using svn ls) from a given path
+# NOTE: this function outputs full URLs (except the protocol part), like
+# //srv/proj/branches/ //srv/proj/tags/ //srv/proj/trunk/
+function _svn_remotels()
+{
+    local currUrl=$1
+    local proto=$2
+
+    local fullUrl=$2$1
+    _debug "Trying to complete $opt"
+
+    # HACK: fullUrl is something like http://srv/proj/ or http://srv/proj/ta
+    # so we add an X and get the dirname from there in order to see where we
+    # should run "svn ls" against (that is, http://srv/proj)
+    local urlDir=$(dirname "${fullUrl}X")/
+
+    # now get the prefix part of the file (e.g. "ta" for "target.def")
+    # (this is used for local filtering)
+    local filepref=${fullUrl#${urlDir}}
+
+    # This output prefix "//srv/proj/" will be re-added to the individual ls 
entries
+    # so to get something like a "full path" listing (except leading 
"protocol:")
+    local outurlDir=${urlDir#${proto}}
+
+    _debug "prefix to be matched is $filepref"
+
+    local files=()
+    local f=
+    svn ls --non-interactive $urlDir </dev/null 2>/dev/null | while IFS= read 
-r f
+    do
+       _debug -n "... $f:"
+       # if the filename matches the provided string, add it to the list
+       if [[ -z "$filepref" || $f == $filepref* ]]
+       then
+           _debug YES
+            echo "$outurlDir$f"
+        else
+           _debug NO
+       fi
+    done
+
+    return 0
+}
+
 # This completion guides the command/option order along the one suggested
 # by "svn help", although other syntaxes are allowed.
 #
@@ -395,9 +448,22 @@ _svn()
        fi
 
        # URL completion
-       if [[ $cmd == @(co|checkout|ls|list) && $stat = 'arg' && \
+       if [[ $cmd == @(co|checkout|ls|list|cat) && $stat = 'arg' && \
                        $SVN_BASH_COMPL_EXT == *urls* ]]
        then
+               # whenever a colon (:) is present, bash will split it into 
three different parts:
+               # 1) http
+               # 2) :
+               # 3) //full/path/to
+               # So we need to reconstruct this
+               #FIXME this should be made more robust
+
+               local prefixUrl=${COMP_WORDS[i-3]}${COMP_WORDS[i-2]}    #http:
+               local currUrl=${COMP_WORDS[i-1]}                        #//srv-
+               local 
partUrl=${COMP_WORDS[i-3]}${COMP_WORDS[i-2]}${COMP_WORDS[i-1]}
+
+               _debug partUrl=${partUrl} cur = ${cur}
+
                # see about COMP_WORDBREAKS workaround in prop completion
                if [[ $cur == file:* ]]
                then
@@ -405,27 +471,50 @@ _svn()
                        local where=${cur/file:/}
                        COMPREPLY=( $(compgen -d -S '/' -X '*/.*' -- $where ) )
                        return
-               elif [[ $cur == *:* ]]
+               elif [[ $partUrl == *://*/* ]]
                then
+                       local IFS=$'\n'
+                       # Get the list of remote files (as full paths)
+                       local results="$(_svn_remotels ${currUrl} ${prefixUrl} 
)"
+                       COMPREPLY=( $(compgen -W "${results}" ))
+                       _debug "...completion results are: ${COMPREPLY[@]}"
+                       # Set output options:
+                       # - nospace: DO NOT add a new space even if it's the 
only completion
+                       # - filenames: remove common leading paths
+                       compopt -o nospace -o filenames
+                       return 0
+               elif [[ $partUrl == *:* ]]
+               then
+                       _debug trying to get known urls
                        # get known urls
                        local urls= file=
-                       for file in ~/.subversion/auth/svn.simple/* ; do
-                               if [ -r $file ] ; then
-                                       local url=$(_svn_read_hashfile 
svn:realmstring < $file)
-                                       url=${url/*</}
-                                       url=${url/>*/}
-                                       urls="$urls $url"
-                               fi
+#                      for file in ~/.subversion/auth/svn.simple/* ; do
+#                              if [ -r $file ] ; then
+#                                      local url=$(_svn_read_hashfile 
svn:realmstring < $file)
+#                                      url=${url/*</}
+#                                      url=${url/>*/}
+#                                      urls="$urls $url"
+#                              fi
+#                      done
+                       for url in $(< ~/.svn_repos)
+                       do
+                               urls="$urls $url"
                        done
-
+                       _debug "...known urls are: ${urls}"
                        # only suggest/show possible suffixes
-                       local prefix=${cur%:*} suffix=${cur#*:} c= choices=
+                       local prefix=${partUrl%:*} suffix=${partUrl#*:} c= 
choices=
+
                        for c in $urls ; do
+                               _debug "evaluating ${c} prefix=${prefix} 
suffix=${suffix}"
                                [[ $c == $prefix:* ]] && choices="$choices 
${c#*:}"
                        done
+                       _debug "choices is now ${choices}"
 
-                       COMPREPLY=( $(compgen -W "$choices" -- $suffix ) )
-                       return
+                       COMPREPLY=( $(compgen -W "$choices" -- $cur ) )
+                       # Set output options:
+                       # - nospace: DO NOT add a new space even if it's the 
only completion
+                       compopt -o nospace
+                       return 0
                else
                        # show schemas
                        COMPREPLY=( $(compgen -W "$urlSchemas" -- $cur) )

Reply via email to