3 ##################################################
5 # cabal command line completion
7 # Copyright 2007-2008 "Lennart Kolmodin" <kolmodin@gentoo.org>
8 # "Duncan Coutts" <dcoutts@gentoo.org>
9 # Copyright 2019- "Sam Boosalis" <samboosalis@gmail.com>
12 # Compatibility — Bash 3.
14 # OSX won't update Bash 3 (last updated circa 2009) to Bash 4,
15 # and we'd like this completion script to work on both Linux and Mac.
17 # For example, OSX Yosemite (released circa 2014) ships with Bash 3:
19 # $ echo $BASH_VERSION
22 # While Ubuntu LTS 14.04 (a.k.a. Trusty, also released circa 2016)
23 # ships with the latest version, Bash 4 (updated circa 2016):
25 # $ echo $BASH_VERSION
31 # (1) Invoke « shellcheck »
33 # * source: « https://github.com/koalaman/shellcheck »
34 # * run: « shellcheck ./cabal-install/bash-completion/cabal »
36 # (2) Interpret via Bash 3
38 # * source: « https://ftp.gnu.org/gnu/bash/bash-3.2.tar.gz »
39 # * run: « bash --noprofile --norc --posix ./cabal-install/bash-completion/cabal »
43 ##################################################
46 command -v cabal
>/dev
/null
47 command -v grep >/dev
/null
48 command -v sed >/dev
/null
50 ##################################################
52 # List project-specific (/ internal) packages:
56 function _cabal_list_packages
()
61 CabalFiles
=( .
/*.cabal .
/*/*.cabal .
/*/*/*.cabal
)
63 for FILE
in "${CabalFiles[@]}"
66 BASENAME
=$
(basename "$FILE")
67 PACKAGE
="${BASENAME%.cabal}"
76 # [1] « "${string%suffix}" » strips « suffix » from « string »,
79 # [2] « done | sort | uniq » removes duplicates from the output of the for-loop.
82 ##################################################
84 # List cabal targets by type, pass:
86 # - ‹test-suite› for test suites
87 # - ‹benchmark› for benchmarks
88 # - ‹executable› for executables
89 # - ‹library› for internal libraries
90 # - ‹foreign-library› for foreign libraries
91 # - nothing for all components.
94 function _cabal_list_targets
()
98 # ^ NOTE « _cabal_list_targets » must be a subshell to temporarily enable « nullglob ».
99 # hence, « function _ () ( ... ) » over « function _ () { ... } ».
100 # without « nullglob », if a glob-pattern fails, it becomes a literal
101 # (i.e. the string with an asterix, rather than an empty string).
103 CabalComponent
=${1:-library|executable|test-suite|benchmark|foreign-library}
106 CabalFiles
=( .
/*.cabal .
/*/*.cabal .
/*/*/*.cabal
)
108 for FILE
in "${CabalFiles[@]}"
111 grep -E -i "^[[:space:]]*($CabalComponent)[[:space:]]" "$FILE" 2>/dev
/null |
sed -e "s/.* \([^ ]*\).*/\1/" |
sed -e '/^$/d'
118 # [1] in « sed '/^$/d' »:
120 # * « d » is the sed command to delete a line.
121 # * « ^$ » is a regular expression matching only a blank line
122 # (i.e. a line start followed by a line end).
124 # dropping blank lines is necessary to ignore public « library » stanzas,
125 # while still matching private « library _ » stanzas.
130 #TODO# rm duplicate components and qualify with « PACKAGE: » (from basename):
134 ##################################################
136 # List possible targets depending on the command supplied as parameter. The
137 # ideal option would be to implement this via --list-options on cabal directly.
138 # This is a temporary workaround.
140 function _cabal_targets
()
145 for Completion
in "$@"; do
147 [ "$Completion" == new-build
] && _cabal_list_targets
&& break
148 [ "$Completion" == new-repl
] && _cabal_list_targets
&& break
149 [ "$Completion" == new-run
] && _cabal_list_targets
"executable" && break
150 [ "$Completion" == new-test
] && _cabal_list_targets
"test-suite" && break
151 [ "$Completion" == new-bench
] && _cabal_list_targets
"benchmark" && break
152 [ "$Completion" == new-haddock
] && _cabal_list_targets
&& break
154 [ "$Completion" == new-install
] && _cabal_list_targets
"executable" && break
155 # ^ Only complete for local packages (not all 1000s of remote packages).
157 [ "$Completion" == build
] && _cabal_list_targets
"executable|test-suite|benchmark" && break
158 [ "$Completion" == repl
] && _cabal_list_targets
"executable|test-suite|benchmark" && break
159 [ "$Completion" == run
] && _cabal_list_targets
"executable" && break
160 [ "$Completion" == test ] && _cabal_list_targets
"test-suite" && break
161 [ "$Completion" == bench
] && _cabal_list_targets
"benchmark" && break
168 # [1] « $@ » will be the full command-line (so far).
173 ##################################################
175 # List possible subcommands of a cabal subcommand.
177 # In example "sandbox" is a cabal subcommand that itself has subcommands. Since
178 # "cabal --list-options" doesn't work in such cases we have to get the list
181 function _cabal_subcommands
()
188 # Get list of "cabal sandbox" subcommands from its help message.
190 sed -n '1,/^Subcommands:$/d;/^Flags for sandbox:$/,$d;/^ /d;s/^\(.*\):/\1/p'
191 break # Terminate for loop.
197 ##################################################
199 function __cabal_has_doubledash
()
203 # Ignore the last word, because it is replaced anyways.
204 # This allows expansion for flags on "cabal foo --",
205 # but does not try to complete after "cabal foo -- ".
206 local n
=$
((${#COMP_WORDS[@]} - 1))
207 while [ $c -lt $n ]; do
208 if [ "--" = "${COMP_WORDS[c]}" ]; then
217 ##################################################
222 # no completion past cabal arguments.
223 __cabal_has_doubledash
&& return
225 # get the word currently being completed
227 CurrentWord
=${COMP_WORDS[$COMP_CWORD]}
229 # create a command line to run
231 # copy all words the user has entered
232 CommandLine
=( "${COMP_WORDS[@]}" )
234 # replace the current word with --list-options
235 CommandLine
[${COMP_CWORD}]="--list-options"
237 # the resulting completions should be put into this array
238 COMPREPLY
=( $
( compgen
-W "$( eval "${CommandLine[@]}" 2>/dev/null ) $( _cabal_targets "${CommandLine[@]}" ) $( _cabal_subcommands "${COMP_WORDS[@]}" )" -- "$CurrentWord" ) )
242 # { IFS=" " read -a ExampleArray <<< "$abc"; echo ${ExampleArray[@]}; echo ${!ExampleArray[@]}; }
244 ##################################################
246 complete
-F _cabal
-o default cabal