1# /* vim: set ai ts=4 ft=sh: */
2#
3# Copyright 2011, The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18_adb() {
19    unset -v have
20    type $1 &> /dev/null && have="yes"
21
22    if [ "$have" != "yes" ]; then
23        return
24    fi
25
26    local where i cur serial
27    COMPREPLY=()
28
29    serial="${ANDROID_SERIAL:-none}"
30    where=OPTIONS
31    for ((i=1; i <= COMP_CWORD; i++)); do
32        cur="${COMP_WORDS[i]}"
33        case "${cur}" in
34            -s)
35                where=OPT_SERIAL
36                ;;
37            -p)
38                where=OPT_PATH
39                ;;
40            -*)
41                where=OPTIONS
42                ;;
43            *)
44                if [[ $where == OPT_SERIAL ]]; then
45                    where=OPT_SERIAL_ARG
46                elif [[ $where == OPT_SERIAL_ARG ]]; then
47                    serial=${cur}
48                    where=OPTIONS
49                else
50                    where=COMMAND
51                    break
52                fi
53                ;;
54        esac
55    done
56
57    if [[ $where == COMMAND && $i -ge $COMP_CWORD ]]; then
58        where=OPTIONS
59    fi
60
61    OPTIONS="-d -e -s -p"
62    COMMAND="devices connect disconnect push pull sync shell emu logcat lolcat forward jdwp install uninstall bugreport help version start-server kill-server get-state get-serialno status-window remount reboot reboot-bootloader root usb tcpip"
63
64    case $where in
65        OPTIONS|OPT_SERIAL|OPT_PATH)
66            COMPREPLY=( $(compgen -W "$OPTIONS $COMMAND" -- "$cur") )
67            ;;
68        OPT_SERIAL_ARG)
69            local devices=$(command adb devices 2> /dev/null | grep -v "List of devices" | awk '{ print $1 }')
70            COMPREPLY=( $(compgen -W "${devices}" -- ${cur}) )
71            ;;
72        COMMAND)
73            if [[ $i -eq $COMP_CWORD ]]; then
74                COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
75            else
76                i=$((i+1))
77                case "${cur}" in
78                    install)
79                        _adb_cmd_install "$serial" $i
80                        ;;
81                    sideload)
82                        _adb_cmd_sideload "$serial" $i
83                        ;;
84                    pull)
85                        _adb_cmd_pull "$serial" $i
86                        ;;
87                    push)
88                        _adb_cmd_push "$serial" $i
89                        ;;
90                    reboot)
91                        if [[ $COMP_CWORD == $i ]]; then
92                            args="bootloader recovery"
93                            COMPREPLY=( $(compgen -W "${args}" -- "${COMP_WORDS[i]}") )
94                        fi
95                        ;;
96                    shell)
97                        _adb_cmd_shell "$serial" $i
98                        ;;
99                    uninstall)
100                        _adb_cmd_uninstall "$serial" $i
101                        ;;
102                esac
103            fi
104            ;;
105    esac
106
107    return 0
108}
109
110_adb_cmd_install() {
111    local serial i cur where
112
113    serial=$1
114    i=$2
115
116    where=OPTIONS
117    for ((; i <= COMP_CWORD; i++)); do
118        cur="${COMP_WORDS[i]}"
119        case "${cur}" in
120            -*)
121                where=OPTIONS
122                ;;
123            *)
124                where=FILE
125                break
126                ;;
127        esac
128    done
129
130    cur="${COMP_WORDS[COMP_CWORD]}"
131    if [[ $where == OPTIONS ]]; then
132        COMPREPLY=( $(compgen -W "-d -l -r -s" -- "${cur}") )
133        return
134    fi
135
136    _adb_util_complete_local_file "${cur}" '!*.apk'
137}
138
139_adb_cmd_sideload() {
140    local serial i cur
141
142    serial=$1
143    i=$2
144
145    cur="${COMP_WORDS[COMP_CWORD]}"
146
147    _adb_util_complete_local_file "${cur}" '!*.zip'
148}
149
150_adb_cmd_push() {
151    local serial IFS=$'\n' i cur
152
153    serial=$1
154    i=$2
155
156    cur="${COMP_WORDS[COMP_CWORD]}"
157
158    if [[ $COMP_CWORD == $i ]]; then
159        _adb_util_complete_local_file "${cur}"
160    elif [[ $COMP_CWORD == $(($i+1)) ]]; then
161        if [ "${cur}" == "" ]; then
162            cur="/"
163        fi
164        _adb_util_list_files $serial "${cur}"
165    fi
166}
167
168_adb_cmd_pull() {
169    local serial IFS=$'\n' i cur
170
171    serial=$1
172    i=$2
173
174    cur="${COMP_WORDS[COMP_CWORD]}"
175
176    if [[ $COMP_CWORD == $i ]]; then
177        if [ "${cur}" == "" ]; then
178            cur="/"
179        fi
180        _adb_util_list_files $serial "${cur}"
181    elif [[ $COMP_CWORD == $(($i+1)) ]]; then
182        _adb_util_complete_local_file "${cur}"
183    fi
184}
185
186_adb_cmd_shell() {
187    local serial IFS=$'\n' i cur
188    local -a args
189
190    serial=$1
191    i=$2
192
193    cur="${COMP_WORDS[i]}"
194    if [ "$serial" != "none" ]; then
195        args=(-s $serial)
196    fi
197
198    if [[ $i -eq $COMP_CWORD && ${cur:0:1} != "/" ]]; then
199        paths=$(command adb ${args[@]} shell echo '$'PATH 2> /dev/null | tr -d '\r' | tr : '\n')
200        COMMAND=$(command adb ${args[@]} shell ls $paths '2>' /dev/null | tr -d '\r' | {
201            while read -r tmp; do
202                command=${tmp##*/}
203                printf '%s\n' "$command"
204            done
205        })
206        COMPREPLY=( $(compgen -W "$COMMAND" -- "$cur") )
207        return 0
208    fi
209
210    i=$((i+1))
211    case "$cur" in
212        ls)
213            _adb_shell_ls $serial $i
214            ;;
215        /*)
216            _adb_util_list_files $serial "$cur"
217            ;;
218        *)
219            COMPREPLY=( )
220            ;;
221    esac
222
223    return 0
224}
225
226_adb_cmd_uninstall() {
227    local serial i where cur packages
228
229    serial=$1
230    i=$2
231    if [ "$serial" != "none" ]; then
232        args=(-s $serial)
233    fi
234
235    where=OPTIONS
236    for ((; i <= COMP_CWORD; i++)); do
237        cur="${COMP_WORDS[i]}"
238        case "${cur}" in
239            -*)
240                where=OPTIONS
241                ;;
242            *)
243                where=FILE
244                break
245                ;;
246        esac
247    done
248
249    cur="${COMP_WORDS[COMP_CWORD]}"
250    if [[ $where == OPTIONS ]]; then
251        COMPREPLY=( $(compgen -W "-k" -- "${cur}") )
252    fi
253
254    packages="$(
255        command adb ${args[@]} shell pm list packages '2>' /dev/null 2> /dev/null | tr -d '\r' | {
256            while read -r tmp; do
257                local package=${tmp#package:}
258                echo -n "${package} "
259            done
260        }
261    )"
262
263    COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${packages}" -- "${cur}") )
264}
265
266_adb_shell_ls() {
267    local serial i cur file
268    local -a args
269
270    serial=$1
271    i=$2
272    if [ "$serial" != "none" ]; then
273        args=(-s $serial)
274    fi
275
276    where=OPTIONS
277    for ((; i <= COMP_CWORD; i++)); do
278        cur="${COMP_WORDS[i]}"
279        case "${cur}" in
280            -*)
281                where=OPTIONS
282                ;;
283            *)
284                where=FILE
285                break
286                ;;
287        esac
288    done
289
290    file="${COMP_WORDS[COMP_CWORD]}"
291    if [[ ${file} == "" ]]; then
292        file="/"
293    fi
294
295    case $where in
296        OPTIONS)
297            COMPREPLY=( $(compgen -W "$OPTIONS" -- "$cur") )
298            _adb_util_list_files $serial "$file"
299            ;;
300        FILE)
301            _adb_util_list_files $serial "$file"
302            ;;
303    esac
304
305    return 0
306}
307
308_adb_util_list_files() {
309    local serial dir IFS=$'\n'
310    local -a toks
311    local -a args
312
313    serial="$1"
314    file="$2"
315
316    if [ "$serial" != "none" ]; then
317        args=(-s $serial)
318    fi
319
320    toks=( ${toks[@]-} $(
321        command adb ${args[@]} shell ls -dF ${file}"*" '2>' /dev/null 2> /dev/null | tr -d '\r' | {
322            while read -r tmp; do
323                filetype=${tmp%% *}
324                filename=${tmp:${#filetype}+1}
325                if [[ ${filetype:${#filetype}-1:1} == d ]]; then
326                    printf '%s/\n' "$filename"
327                else
328                    printf '%s\n' "$filename"
329                fi
330            done
331        }
332    ))
333
334    # Since we're probably doing file completion here, don't add a space after.
335    if [[ $(type -t compopt) = "builtin" ]]; then
336        compopt -o nospace
337    fi
338
339    COMPREPLY=( ${COMPREPLY[@]:-} "${toks[@]}" )
340}
341
342_adb_util_complete_local_file()
343{
344    local file xspec i j IFS=$'\n'
345    local -a dirs files
346
347    file=$1
348    xspec=$2
349
350    # Since we're probably doing file completion here, don't add a space after.
351    if [[ $(type -t compopt) = "builtin" ]]; then
352        compopt -o plusdirs
353        if [[ "${xspec}" == "" ]]; then
354            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
355        else
356            compopt +o filenames
357            COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
358        fi
359    else
360        # Work-around for shells with no compopt
361
362        dirs=( $(compgen -d -- "${cur}" ) )
363
364        if [[ "${xspec}" == "" ]]; then
365            files=( ${COMPREPLY[@]:-} $(compgen -f -- "${cur}") )
366        else
367            files=( ${COMPREPLY[@]:-} $(compgen -f -X "${xspec}" -- "${cur}") )
368        fi
369
370        COMPREPLY=( $(
371            for i in "${files[@]}"; do
372                local skip=
373                for j in "${dirs[@]}"; do
374                    if [[ $i == $j ]]; then
375                        skip=1
376                        break
377                    fi
378                done
379                [[ -n $skip ]] || printf "%s\n" "$i"
380            done
381        ))
382
383        COMPREPLY=( ${COMPREPLY[@]:-} $(
384            for i in "${dirs[@]}"; do
385                printf "%s/\n" "$i"
386            done
387        ))
388    fi
389}
390
391
392if [[ $(type -t compopt) = "builtin" ]]; then
393    complete -F _adb adb
394else
395    complete -o nospace -F _adb adb
396fi
397