1# ri completion for Ruby documentation                     -*- shell-script -*-
2# by Ian Macdonald <ian@caliban.org>
3
4_ri_get_methods()
5{
6    local regex
7
8    if [[ $ri_version == integrated ]]; then
9        if [[ -z $separator ]]; then
10            regex="(Instance|Class)"
11        elif [[ $separator == "#" ]]; then
12            regex=Instance
13        else
14            regex=Class
15        fi
16
17        COMPREPLY+=(
18            "$(ri "${classes[@]}" 2>/dev/null | ruby -ane \
19                'if /^'"$regex"' methods:/.../^------------------|^$/ and \
20            /^ / then print $_.split(/, |,$/).grep(/^[^\[]*$/).join("\n"); \
21            end' 2>/dev/null | sort -u)")
22    else
23        # older versions of ri didn't distinguish between class/module and
24        # instance methods
25        COMPREPLY+=(
26            "$(ruby -W0 $ri_path "${classes[@]}" 2>/dev/null | ruby -ane \
27                'if /^-/.../^-/ and ! /^-/ and ! /^ +(class|module): / then \
28            print $_.split(/, |,$| +/).grep(/^[^\[]*$/).join("\n"); \
29            end' | sort -u)")
30    fi
31    COMPREPLY=($(compgen $prefix -W '${COMPREPLY[@]}' -- $method))
32}
33
34# needs at least Ruby 1.8.0 in order to use -W0
35_ri()
36{
37    local cur prev words cword split
38    _init_completion -s -n : || return
39
40    case $prev in
41        --help | --width | -!(-*)[hw])
42            return
43            ;;
44        --format | -!(-*)f)
45            COMPREPLY=($(compgen -W 'ansi bs html rdoc' -- "$cur"))
46            return
47            ;;
48        --doc-dir | -!(-*)d)
49            _filedir -d
50            return
51            ;;
52        --dump)
53            _filedir ri
54            return
55            ;;
56    esac
57
58    $split && return
59
60    if [[ $cur == -* ]]; then
61        COMPREPLY=($(compgen -W '$(_parse_help "$1")' -- "$cur"))
62        [[ ${COMPREPLY-} == *= ]] && compopt -o nospace
63        return
64    fi
65
66    local class method prefix ri_path ri_version ri_major separator IFS
67    local -a classes
68
69    ri_path=$(type -p ri)
70    # which version of ri are we using?
71    # -W0 is required here to stop warnings from older versions of ri
72    # from being captured when used with Ruby 1.8.1 and later
73    ri_version="$(ruby -W0 $ri_path -v 2>&1)" || ri_version=integrated
74    [[ $ri_version != "${ri_version%200*}" ]] && ri_version=integrated
75    [[ $ri_version =~ ri[[:space:]]v?([0-9]+) ]] && ri_major=${BASH_REMATCH[1]}
76
77    # need to also split on commas
78    IFS=$', \n\t'
79    if [[ $cur == [A-Z]*[#.]* ]]; then
80        [[ $cur == *#* ]] && separator=# || separator=.
81        # we're completing on class and method
82        class=${cur%$separator*}
83        method=${cur#*$separator}
84        classes=($class)
85        prefix="-P $class$separator"
86        _ri_get_methods
87        return
88    fi
89
90    if [[ $ri_version == integrated ]]; then
91        # integrated ri from Ruby 1.9
92        classes=($(ri -c 2>/dev/null | ruby -ne 'if /^\s*$/..$stdin.eof then \
93        if /^ +[A-Z]/ then print; end; end' 2>/dev/null))
94    elif [[ $ri_major && $ri_major -ge 3 ]]; then
95        classes=($(ri -l 2>/dev/null))
96    elif [[ $ri_version == "ri 1.8a" ]]; then
97        classes=($(ruby -W0 $ri_path |
98            ruby -ne 'if /^'"'"'ri'"'"' has/..$stdin.eof then \
99            if /^ .*[A-Z]/ then print; end; end'))
100    else
101        classes=($(ruby -W0 $ri_path |
102            ruby -ne 'if /^I have/..$stdin.eof then \
103                if /^ .*[A-Z]/ then print; end; end'))
104    fi
105
106    COMPREPLY=($(compgen -W '${classes[@]}' -- "$cur"))
107    __ltrim_colon_completions "$cur"
108
109    if [[ $cur == [A-Z]* ]]; then
110        # we're completing on class or module alone
111        return
112    fi
113
114    # we're completing on methods
115    method=$cur
116    _ri_get_methods
117} &&
118    complete -F _ri ri
119
120# ex: filetype=sh
121