├── docs └── screencast.gif ├── haskell.plugin.zsh ├── README.md ├── _ghc ├── _ghc-pkg ├── LICENSE └── _cabal /docs/screencast.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coot/zsh-haskell/HEAD/docs/screencast.gif -------------------------------------------------------------------------------- /haskell.plugin.zsh: -------------------------------------------------------------------------------- 1 | source "$(dirname ${0})/_cabal" 2 | source "$(dirname ${0})/_ghc-pkg" 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZSH shell plugin for Haskell 2 | 3 | * completion for **ghc** options 4 | * completion for **cabal** commands; it can expands cabal components (libraries, 5 | tests, benchmarks and executables) and pkgs specs. It also complets options 6 | of `cabal` commands and package names (e.g. `cabal info` or `cabal 7 | install`) 8 | * completion for **ghc-pkgs** commands & options 9 | 10 | # Usage 11 | 12 | The completion script will find and inspect all cabal files under current 13 | directory which are not deeper than four directories away. It does not descent 14 | under `dist-newstye`, `dist`, `.stack-work` or `.git` directories. 15 | 16 | Completion for the following package specs is supported: 17 | 18 | * `component-name` - it can be either a component name or a package name 19 | * `package-name:{lib,test,exe,bench}:component-name` 20 | * `package-name:{libs,tests,exes,benches}` 21 | * `pkg:package-name:{lib,test,exe,bench}:component-name`. 22 | * `pkg:package-name:{libs,tests,exes,benches}`. 23 | * `lib:component-name`, 24 | * `exec:component-name`, 25 | * `bench:component-name`, 26 | * `test:component-name` 27 | 28 | The last six are only triggered when `pkg:`, `lib:`, `exec:`, `bench:` or 29 | `test:` are given **explicitly**. This is in order to avoid providing too many 30 | completion results. 31 | 32 | # Configuration 33 | 34 | ``` 35 | zstyle ":completion::complete:cabal::options:" depth 4 36 | ``` 37 | Maximan directory depth for searching for `*.cabal` files. 38 | 39 | ``` 40 | zstyle ":completion::complete:cabal::options:" 41 | zstyle ":completion::complete:cabal::options:" packages-tmp-file "/tmp/zsh-haskell-cabal-packages" 42 | ``` 43 | File which stores list of package names. It will be created on demenad (e.g. 44 | by completiting `cabal info` or `cabal install`, etc.). 45 | 46 | # Demo 47 | ![](https://raw.githubusercontent.com/coot/zsh-cabal/master/docs/screencast.gif) 48 | -------------------------------------------------------------------------------- /_ghc: -------------------------------------------------------------------------------- 1 | #compdef ghc 2 | # 3 | # Author: Marcin Szamotulski 4 | # Copyright: 2019,2020 5 | 6 | _ghc_packages () { 7 | local -a pkgs 8 | pkgs=( $(ghc --show-packages 2&>/dev/null | grep "^name:" | awk '{print $2}' | uniq) ) 9 | _describe -t pkgs "packages" pkgs 10 | } 11 | 12 | _ghc_package_ids () { 13 | local -a pkgs 14 | pkgs=( $(ghc --show-packages 2&>/dev/null | grep "^id:" | awk '{print $2}' | uniq) ) 15 | _describe -t pkgs "package-ids" pkgs 16 | } 17 | 18 | _ghc () { 19 | local opts current_word 20 | current_word=$words[$CURRENT] 21 | 22 | # only display -XNo options if one is explicitely assking for it 23 | opts=( $(ghc --show-options | \ 24 | grep -v -P '^(-pgm([acFiLlPs]|dll|lc|libtool|lowindres))$' | \ 25 | grep -v -P '^(--exclude-module|-dep-makefile|-dumpdir|-hidir|-odir|-ohi)$' | \ 26 | grep -v -P '^(-package-db|-package|-package-id|-main-is)$' | \ 27 | grep -v -P '^(--show-iface|-fplugin|-plugin-package|-plugin-package-id)$' | \ 28 | ([[ ${current_word:0:4} != '-XNo' ]] && grep -v '^-XNo' || tee) | \ 29 | ([[ ${current_word:0:4} != '-fno' ]] && grep -v '^-fno' || tee) | \ 30 | ([[ ${current_word:0:4} != '-Wno' ]] && grep -v '^-Wno' || tee) ) ); 31 | 32 | _arguments ${opts} \ 33 | '*-package:package:_ghc_packages' \ 34 | '*-plugin-package:package:_ghc_packages' \ 35 | '-pgma:command:_cmdstring' \ 36 | '-pgmc:command:_cmdstring' \ 37 | '-pgmF:command:_cmdstring' \ 38 | '-pgmi:command:_cmdstring' \ 39 | '-pgmL:command:_cmdstring' \ 40 | '-pgml:command:_cmdstring' \ 41 | '-pgmP:command:_cmdstring' \ 42 | '-pgms:command:_cmdstring' \ 43 | '-pgmdll:command:_cmdstring' \ 44 | '-pgmlc:command:_cmdstring' \ 45 | '-pgmlibtool:command:_cmdstring' \ 46 | '-pgmlowindres:command:_cmdstring' \ 47 | '--excluded-module:directory:_files' \ 48 | '-dep-makefile:directory:_files' \ 49 | '-dumpdir:directory:_files -/' \ 50 | '-hidir:directory:_files -/' \ 51 | '-odir:directory:_files -/' \ 52 | '-ohi:directory:_files' \ 53 | '-outputdir:directory:_files -/' \ 54 | '-stubdir:directory:_files -/' \ 55 | '-package-db:package-db:_files' \ 56 | '-package-id:package-id:_ghc_package_ids' \ 57 | '-plugin-package-id:package-id:_ghc_package_ids' \ 58 | '-main-is:main file:_files' \ 59 | '--show-iface:file:_files' \ 60 | '-fplugin:module:_guard ".*" ""' 61 | } 62 | 63 | compdef _ghc ghc 64 | compdef _ghc ghci 65 | 66 | # vim:ft=zsh:expandtab 67 | -------------------------------------------------------------------------------- /_ghc-pkg: -------------------------------------------------------------------------------- 1 | # Author: Marcin Szamotulski 2 | # Copyright: 2019,2020 3 | # 4 | # TODO: --package-db expand the argument: ~/package.db -> /home/user/package.db 5 | 6 | _ghc-pkg_commands () { 7 | local commands 8 | commands=( 9 | "init:Create and initialise a package database at the location {path}." 10 | "register:Register the package using the specified installed packageupdate: description." 11 | "update:Register the package, overwriting any other package with the same name." 12 | "unregister:Unregister the specified packages in the order given." 13 | "expose:Expose the specified package." 14 | "hide:Hide the specified package." 15 | "trust:Trust the specified package." 16 | "distrust:Distrust the specified package." 17 | "list:List registered packages in the global database, and also the user database if --user is given." 18 | "dot:Generate a graph of the package dependencies in a form suitable for input for the graphviz tools." 19 | "find-module:List registered packages exposing module {module} in the global database, and also the user database if --user is given." 20 | "latest:Prints the highest registered version of a package." 21 | "check:Check the consistency of package dependencies and list broken packages." 22 | "describe:Give the registered description for the specified package." 23 | "field:Extract the specified field of the package description for the specified package." 24 | "dump:Dump the registered description for every package." 25 | "recache:Regenerate the package database cache." 26 | ) 27 | _describe -t ghc-pkg-commands 'ghc-pkg commands' commands 28 | } 29 | 30 | _ghc-pkg () { 31 | _arguments '--package-db=:package db:_files' \ 32 | '--package-conf=:package conf:_files' \ 33 | '--global-package-db=:global package db:_files -/' \ 34 | '--no-user-package-db' \ 35 | '--force' \ 36 | '--force-files' \ 37 | '--enable-multi-instance' \ 38 | '--enable-multi-instance' \ 39 | '--expand-env-vars' \ 40 | '--expand-pkgroot' \ 41 | '--no-expand-pkgroot' \ 42 | '-?' \ 43 | '--help' \ 44 | '-V' \ 45 | '--version' \ 46 | '--simple-output' \ 47 | '--names-only' \ 48 | '--simple-output' \ 49 | {--ipid,--unit-id}':interpret package arguments as unit IDs' \ 50 | {-v,--verbose=}':level:(0 1 2 3)' \ 51 | '*:: :->command-argument' \ 52 | '1:commands:->command' && ret=0 53 | 54 | case $state in 55 | (command) 56 | _ghc-pkg_commands 57 | ;; 58 | (command-argument) 59 | case $words[1] in 60 | ("init") 61 | _arguments ':path:_files' 62 | break 63 | ;; 64 | ("register") 65 | _arguments ':filename:_files' 66 | break 67 | ;; 68 | ("unregister") 69 | # TODO: complete installed packages 70 | _arguments ':package:_guard ".*" ""' 71 | break 72 | ;; 73 | ("update") 74 | _arguments ':filename:_files' 75 | break 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | compdef _ghc-pkg ghc-pkg 82 | # vim:ft=zsh:expandtab 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /_cabal: -------------------------------------------------------------------------------- 1 | #compdef cabal 2 | # 3 | # Author: Marcin Szamotulski 4 | # Copyright: 2019,2020 5 | # 6 | # TODO: pkgs specs of the form: pkgname:test:.. 7 | # pkgname:exe:... 8 | # TODO: is there a way to handle strings in --ghc-options (multiple options) 9 | # TODO: -f --flag 10 | # TODO: --package-db 11 | # TODO: --with-PROG=PATH --PROG-option --PROG-options 12 | # TODO: cabal {fetch,install,get,info} - complete packages 13 | # TODO: --package-db=(global user or a file path) 14 | # 15 | # TODO: use only packages defined in `cabal.project` and / or 16 | # `cabal.project.local` files. 17 | # 18 | # TODO: add support for `:{lib|exec|bench|test}:` 19 | 20 | source "$(dirname ${0})/_ghc" 21 | 22 | MAIN_CONTEXT=":complete:cabal:" 23 | 24 | _cabal_default_options () { 25 | zstyle -s ":completion:${MAIN_CONTEXT}:options:" packages-tmp-file PACKAGES_TMP_FILE 26 | if [[ -z ${PACKAGES_TMP_FILE} ]]; then 27 | zstyle ":completion:${MAIN_CONTEXT}:options:" packages-tmp-file "/tmp/zsh-haskell-cabal-packages" 28 | fi 29 | 30 | zstyle -s ":completion:${MAIN_CONTEXT}:options:" depth depth 31 | if [[ -z "${depth}" ]]; then 32 | zstyle ":completion:${MAIN_CONTEXT}:options:" depth 4 33 | fi 34 | } 35 | 36 | _cabal_subcommands=( bench build check clean configure "exec" \ 37 | fetch freeze get gen-bounds haddock haddock-project help \ 38 | hscolour info init install list outdated repl \ 39 | report run sdist "test" unpack update upload \ 40 | user-config list-bin \ 41 | ) 42 | 43 | _cabal_commands () { 44 | local subcommands 45 | subcommands=( 46 | "bench:Run benchmarks" 47 | "build:Compile targets within the project." 48 | "check:Check the package for common mistakes" 49 | "clean:Clean the package store and remove temporary files." 50 | "configure:Add extra project configuration." 51 | "exec:Give a command access to the store." 52 | "fetch:Downloads packages for later installation." 53 | "freeze:Freeze dependencies." 54 | "get:Download/Extract a package's source code (repository)." 55 | "gen-bounds:Generate dependency bounds." 56 | "haddock-project:Build documentation for a cabal project." 57 | "haddock:Build Haddock documentation." 58 | "help:Help about commands." 59 | "hscolour:Generate HsColour colourised code, in HTML format." 60 | "info:Display detailed information about a particular package." 61 | "init:Create a new .cabal package file." 62 | "install:Install packages." 63 | "list:List packages matching a search string." 64 | "outdated:Check for outdated dependencies." 65 | "repl:Open an interactive session for the given component." 66 | "report:Upload build reports to a remote server." 67 | "run:Run an executable." 68 | "sdist:Generate a source distribution file (.tar.gz)." 69 | "test:Run test-suites." 70 | "unpack:Download/Extract a package's source code (repository)." 71 | "update:Updates list of known packages." 72 | "upload:Uploads source packages or documentation to Hackage." 73 | "user-config:Display and update the user's global cabal configuration." 74 | "list-bin:List path to a single executable." 75 | ) 76 | _describe -t subcommands 'cabal subcommands' subcommands 77 | } 78 | 79 | _cabal_list_files () { 80 | # find all cabal files, but do not descent into dist-newstyle, dist or 81 | # .stack-work directories 82 | local depth 83 | zstyle -s ":completion:${MAIN_CONTEXT}:options:" depth depth 84 | # options might not be set if using outside of completion 85 | [[ -z ${depth} ]] && depth=4 86 | find -maxdepth ${depth} \ 87 | -name "dist-newstyle" -prune , \ 88 | -name "dist" -prune , \ 89 | -name ".stack-work" -prune , \ 90 | -name ".git" -prune , \ 91 | -type f -name "*.cabal" \ 92 | 2&>/dev/null 93 | } 94 | 95 | 96 | # find cabal file by package name 97 | _cabal_find_package () { 98 | local pkgname=${1} 99 | local depth 100 | zstyle -s ":completion:${MAIN_CONTEXT}:options:" depth depth 101 | # options might not be set if using outside of completion 102 | [[ -z ${depth} ]] && depth=4 103 | res=$(find -maxdepth ${depth} \ 104 | -name "dist-newstyle" -prune , \ 105 | -name "dist" -prune , \ 106 | -name ".stack-work" -prune , \ 107 | -name ".git" -prune , \ 108 | -type f -name "${pkgname}.cabal" \ 109 | 2&>/dev/null) 110 | if [[ -n $res ]]; then 111 | echo $res 112 | else 113 | for file in $(_cabal_list_files); do 114 | local name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i') 115 | if [[ ${name} == ${pkgname} ]]; then 116 | echo $file 117 | fi 118 | done 119 | fi 120 | } 121 | 122 | _cabal_list_packages () { 123 | # find all cabal packages 124 | local file 125 | for file in $(_cabal_list_files); do 126 | name=$(grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i') 127 | done; 128 | } 129 | 130 | _cabal_list_components () { 131 | # find all components 132 | local file cmps 133 | for file in $(_cabal_list_files); do 134 | grep -i -s -P '^(test-suite|executable|benchmark|library)\s+\S' $file 2&>/dev/null \ 135 | | awk '{print $2}' | sed -e 's/:/\\:/g' 136 | [[ $(grep -s -i "^library\s*$" ${file}) ]] \ 137 | && grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i' 138 | done; 139 | } 140 | 141 | _cabal_list_libraries () { 142 | # find all components 143 | local file cmps 144 | for file in $(_cabal_list_files); do 145 | grep -i -s -P '^library\s+\S' $file | awk '{print $2}' | sed -e 's/:/\\:/g' 2&>/dev/null 146 | [[ $(grep -s -i "^library\s*$" ${file}) ]] \ 147 | && grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i' 148 | done; 149 | } 150 | 151 | _cabal_component_names_in_file () { 152 | local file=$1 153 | local name=$(grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i') 154 | grep -s -i '^\(library\|executable\|test-suite\|benchmark\)' ${file} 2&>/dev/null \ 155 | | sed -e "s/library\s*$/${name}/gi" \ 156 | | sed -e 's/library\s\+\(\S\)/\1/gi' \ 157 | | sed -e 's/executable\s\+//gi' \ 158 | | sed -e 's/test-suite\s\+//gi' \ 159 | | sed -e 's/benchmark\s\+//gi' 160 | } 161 | 162 | _cabal_components_in_file () { 163 | local file=$1 164 | local name=$(grep -i "name:" ${file} 2>/dev/null | sed 's/^name:\s*//i') 165 | grep -s -i '^\(library\|executable\|test-suite\|benchmark\)' ${file} 2&>/dev/null \ 166 | | sed -e "s/library\s*$/${name}/gi" \ 167 | | sed -e 's/library\s\+\(\S\)/\1/gi' \ 168 | | sed -e 's/executable\s\+//gi' \ 169 | | sed -e 's/test-suite\s\+//gi' \ 170 | | sed -e 's/benchmark\s\+//gi' 171 | } 172 | 173 | _cabal_components_in_file_with_prefix () { 174 | local file=$1 175 | local name=$(grep -i "name:" ${file} 2>/dev/null | sed 's/^name:\s*//i') 176 | grep -s -i '^\(library\|executable\|test-suite\|benchmark\)' ${file} 2&>/dev/null \ 177 | | sed -e "s/library\s*$/lib:${name}/gi" \ 178 | | sed -e 's/library\s\+\(\S\)/lib:\1/gi' \ 179 | | sed -e 's/executable\s\+/exe:/gi' \ 180 | | sed -e 's/test-suite\s\+/test:/gi' \ 181 | | sed -e 's/benchmark\s\+/bench:/gi' 182 | } 183 | 184 | _cabal_libraries_in_file () { 185 | local file=$1 186 | local name=$(grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i') 2&>/dev/null 187 | grep -s -P '^library\s+\S' $file | awk '{print $2}' | sed -e "s/^/${name}:/" 188 | [[ $(grep -s -i "^library\s*$" ${file}) ]] \ 189 | && grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i' 190 | } 191 | 192 | _cabal_list_all_executables () { 193 | # find all executable components 194 | local name; 195 | local file; 196 | for file in $(_cabal_list_files); do 197 | name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i') 198 | grep -s -i '^\(test-suite\|executable\|benchmark\)\s\+' $file 2&>/dev/null \ 199 | | awk '{print $2}' | sed -e 's/:/\\:/g' | sed -e "s/^/${name}:/" 200 | done; 201 | } 202 | 203 | _cabal_list_executables () { 204 | # find all executable components 205 | local file 206 | for file in $(_cabal_list_files); do 207 | grep -s -i '^executable\s\+' $file 2&>/dev/null | awk '{print $2}' | sed -e 's/:/\\:/g' 208 | done; 209 | } 210 | 211 | _cabal_executables_in_file () { 212 | local file=$1 213 | grep -s -i '^executable\s\+' $file 2&>/dev/null | awk '{print $2}' | sed -e 's/:/\\:/gi' 214 | } 215 | 216 | _cabal_list_tests () { 217 | # find all components 218 | local name; 219 | local file cmps; 220 | for file in $(_cabal_list_files); do 221 | name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i') 222 | grep -s -P '^test-suite\s+\S' $file 2&>/dev/null | awk '{print $2}' | sed -e "s/^/${name}:/" 223 | done; 224 | } 225 | 226 | _cabal_tests_in_file () { 227 | local file=$1 228 | local name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i'); 229 | grep -s -P '^test-suite\s+\S' $file 2&>/dev/null | awk '{print $2}' | sed -e "s/^/${name}:/" 230 | } 231 | 232 | _cabal_list_benchmarks () { 233 | # find all benchmarks 234 | local file 235 | local name; 236 | for file in $(_cabal_list_files); do 237 | name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i'); 238 | grep -s -i '^benchmark\s\+' $file 2&>/dev/null | awk '{print $2}' | sed -e "s/^/${name}:/" 239 | 240 | done; 241 | } 242 | 243 | _cabal_benchmarks_in_file () { 244 | local file=$1 245 | local name=$(grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i') 246 | grep -s -i '^benchmark\s\+' $file 2&>/dev/null | awk '{print $2}' | sed -e "s/^/${name}:/" 247 | } 248 | 249 | # completion for components 250 | # ``` 251 | # _cabal_components_with_prefix "pkg:" 252 | # ``` 253 | # or 254 | # ``` 255 | # _cabal_components_with_prefix 256 | # ``` 257 | _cabal_components_with_prefix () { 258 | local prefix=$1 259 | local -a components 260 | local -a pkgs 261 | local file name 262 | local libs 263 | local execs 264 | local tests 265 | local benches 266 | for file in $(_cabal_list_files); do 267 | libs=0 268 | execs=0 269 | tests=0 270 | benches=0 271 | name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i') 272 | pkgs+=("${prefix}${name}"); 273 | for component in $(_cabal_components_in_file_with_prefix $file); do 274 | [[ ${component} =~ '^lib:' ]] && (( libs=${libs} + 1 )); 275 | [[ ${component} =~ '^test:' ]] && (( tests=${tests} + 1 )); 276 | [[ ${component} =~ '^exec:' ]] && (( execs=${execs} + 1 )); 277 | [[ ${component} =~ '^benches:' ]] && (( benches=${benches} + 1 )); 278 | done 279 | [[ ${libs} > 1 ]] && pkgs+=("${prefix}${name}:libs"); 280 | [[ ${tests} > 1 ]] && pkgs+=("${prefix}${name}:tests"); 281 | [[ ${execs} > 1 ]] && pkgs+=("${prefix}${name}:execs"); 282 | [[ ${benches} > 1 ]] && pkgs+=("${prefix}${name}:benches"); 283 | done 284 | # multi part inserts final ':' in pakcage names 285 | # _multi_parts ":" pkgs 286 | _arguments "*:pkgspecs:(${pkgs})" 287 | } 288 | 289 | # completion for `package-name:(libs|tests|benches|exes)` and 290 | # `package-name:(lib:test:bench:exe):component-name` 291 | _cabal_components () { 292 | local -a components 293 | local -a pkgs 294 | local file name 295 | local libs 296 | local execs 297 | local tests 298 | local benches 299 | for file in $(_cabal_list_files); do 300 | libs=0 301 | execs=0 302 | tests=0 303 | benches=0 304 | name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i') 305 | pkgs+=("${name}") 306 | for component_with_prefix in $(_cabal_components_in_file_with_prefix $file); do 307 | local component=${component_with_prefix/*:/}; 308 | [[ ${component_with_prefix} =~ '^lib:' ]] && (( libs=${libs} + 1 )); 309 | [[ ${component_with_prefix} =~ '^test:' ]] && (( tests=${tests} + 1 )); 310 | [[ ${component_with_prefix} =~ '^exec:' ]] && (( execs=${execs} + 1 )); 311 | [[ ${component_with_prefix} =~ '^benches:' ]] && (( benches=${benches} + 1 )); 312 | pkgs+=("${name}:${component}"); 313 | done 314 | [[ ${libs} > 1 ]] && pkgs+=("${name}:libs"); 315 | [[ ${tests} > 1 ]] && pkgs+=("${name}:tests"); 316 | [[ ${execs} > 1 ]] && pkgs+=("${name}:execs"); 317 | [[ ${benches} > 1 ]] && pkgs+=("${name}:benches"); 318 | done 319 | # multi part inserts final ':' in pakcage names 320 | # it also does not allow to complete names with the same prefix as in 321 | # `aaa:bbb` and `aaa-ccc:bbb`, after `aaa --> aaa:` not giving a choice 322 | # for `aaa-ccc:bbb`) 323 | # _multi_parts ":" pkgs 324 | _arguments "*:components:(${pkgs})" 325 | } 326 | 327 | _cabal_components_in_package () { 328 | local pkgname=${1} 329 | local word=${2} 330 | local name; 331 | local pkgs; 332 | local libs=0 333 | local execs=0 334 | local tests=0 335 | local benches=0 336 | local file=$(_cabal_find_package ${pkgname}) 337 | name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i') 338 | if [[ ${name} == ${pkgname} ]]; then 339 | for component_with_prefix in $(_cabal_components_in_file_with_prefix ${file}); do 340 | local component=${component_with_prefix/*:/} 341 | [[ ${component_with_prefix} =~ '^lib:' ]] && (( libs=${libs} + 1 )); 342 | [[ ${component_with_prefix} =~ '^test:' ]] && (( tests=${tests} + 1 )); 343 | [[ ${component_with_prefix} =~ '^exe:' ]] && (( execs=${execs} + 1 )); 344 | [[ ${component_with_prefix} =~ '^bench:' ]] && (( benches=${benches} + 1 )); 345 | pkgs+=("${name}:${component}"); 346 | if [[ ${word} =~ ':lib:' || ${word} =~ ':exe:' || ${word} =~ ':bench:' ]]; then 347 | pkgs+=("${name}:${component_with_prefix}"); 348 | fi 349 | done 350 | [[ ${libs} > 1 ]] && pkgs+=("${name}:libs"); 351 | [[ ${tests} > 1 ]] && pkgs+=("${name}:tests"); 352 | [[ ${execs} > 1 ]] && pkgs+=("${name}:execs"); 353 | [[ ${benches} > 1 ]] && pkgs+=("${name}:benches"); 354 | fi 355 | _arguments "*:components:(${pkgs})" 356 | } 357 | 358 | # test-suites, benchmarks and executables 359 | _cabal_all_executables () { 360 | local -a components 361 | components=( $(_cabal_list_all_executables) ) 362 | _arguments "*:components:(${components})" \ 363 | ${_cabal_build_options[@]} 364 | } 365 | 366 | # only executable components 367 | _cabal_executables () { 368 | local -a components 369 | components=( $(_cabal_list_executables) ) 370 | _arguments "*:components:(${components})" \ 371 | ${_cabal_build_options[@]} 372 | } 373 | 374 | _cabal_tests () { 375 | local -a components 376 | components=( $(_cabal_list_tests) ) 377 | _arguments "*:components:(${components})" \ 378 | ${_cabal_build_options[@]} 379 | } 380 | 381 | _cabal_benchmarks () { 382 | local -a components 383 | components=( $(_cabal_list_benchmarks) ) 384 | _arguments "*:components:(${components})" \ 385 | ${_cabal_build_options[@]} 386 | } 387 | 388 | _cabal_packages () { 389 | local -a pkgs 390 | pkgs=( $(_cabal_list_packages ) ) 391 | _describe -t pkgs 'packages' pkgs 392 | } 393 | 394 | # completion for `pkg:package-name:(libs|tests|benches|exes)` and 395 | # `pkg:package-name:(lib:test:bench:exe):component-name` 396 | _cabal_pkgspecs () { 397 | _cabal_components_with_prefix "pkg:" 398 | } 399 | 400 | _cabal_executable_pkgspecs () { 401 | local -a pkgs 402 | local file name 403 | for file in $(_cabal_list_files); do 404 | name=$(grep -i "name:" ${file} | sed 's/^name:\s*//i') 405 | [[ $(grep -s -i -P '^test-suite' ${file} 2&>/dev/null) ]] && pkgs+=("pkg:${name}:tests") 406 | [[ $(grep -s -i -P '^benchmark' ${file} 2&>/dev/null) ]] && pkgs+=("pkg:${name}:benches") 407 | [[ $(grep -s -i -P '^executable' ${file} 2&>/dev/null) ]] && pkgs+=("pkg:${name}:exes") 408 | done 409 | _multi_parts -i ":" pkgs 410 | } 411 | 412 | _cabal_tests_pkgspecs () { 413 | local -a pkgs 414 | local file name 415 | for file in $(_cabal_list_files); do 416 | name=$(grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i') 417 | [[ $(grep -s -i -P '^test-suite' ${file} 2&>/dev/null) ]] && pkgs+=("pkg:${name}:tests") 418 | done 419 | _multi_parts -i ":" pkgs 420 | } 421 | 422 | _cabal_benchmark_pkgspecs () { 423 | local -a pkgs 424 | local file name 425 | for file in $(_cabal_list_files); do 426 | name=$(grep -i "name:" ${file} 2&>/dev/null | sed 's/^name:\s*//i') 427 | [[ $(grep -s -i -P '^benchmark' ${file} 2&>/dev/null) ]] && pkgs+=("pkg:${name}:benches") 428 | done 429 | _multi_parts -i ":" pkgs 430 | } 431 | 432 | # `lib:` pkgspecs 433 | _cabal_pkgspecs_lib () { 434 | local -a pkgs 435 | local cmp name 436 | for cmp in $(_cabal_list_libraries); do 437 | pkgs+=("lib:${cmp}") 438 | done 439 | _multi_parts ":" pkgs 440 | } 441 | 442 | # `exe:` pkgspecs 443 | _cabal_pkgspecs_exe () { 444 | local -a pkgs 445 | local cmp name 446 | for cmp in $(_cabal_list_executables); do 447 | pkgs+=("exe:${cmp}") 448 | done 449 | _multi_parts ":" pkgs 450 | } 451 | 452 | # `test:` pkgspecs 453 | _cabal_pkgspecs_test () { 454 | local -a pkgs 455 | local cmp name 456 | for cmp in $(_cabal_list_tests); do 457 | pkgs+=("test:${cmp}") 458 | done 459 | _multi_parts ":" pkgs 460 | } 461 | 462 | # `bench:` pkgspec 463 | _cabal_pkgspecs_bench () { 464 | local -a pkgs 465 | local cmp name 466 | for cmp in $(_cabal_list_benchmarks); do 467 | pkgs+=("bench:${cmp}") 468 | done 469 | _multi_parts ":" pkgs 470 | } 471 | 472 | # find all ghc which are in $PATH 473 | _cabal_find_ghc () { 474 | local -a ghcs 475 | for p in $( echo ${PATH} | sed 's/:/\n/g' ); do 476 | for f in $(find ${p} -name 'ghc*' 2&>/dev/null | grep -s -P 'ghc(-\d+\.\d+(\.\d+)*)?$' 2&>/dev/null); do 477 | ghcs+=($(basename ${f})) 478 | done 479 | done 480 | _describe -t ghcs 'ghc' ghcs 481 | } 482 | 483 | _cabal_available_packages_cache () { 484 | local packages_tmp_file; 485 | zstyle -s ":completion:${MAIN_CONTEXT}:options:" packages-tmp-file packages_tmp_file; 486 | echo " /creating list of avaialble packages: it might take a while .../" 487 | cabal list --simple-output | awk '{print $1}' | uniq > ${packages_tmp_file} 488 | } 489 | 490 | _cabal_available_packages () { 491 | # TODO: we don't take into account --package-db 492 | local file="/tmp/zsh-haskell-cabal-packages" 493 | local -A packages 494 | local packages_tmp_file 495 | zstyle -s ":completion:${MAIN_CONTEXT}:options:" packages-tmp-file packages_tmp_file 496 | if [[ -e ${packages_tmp_file} ]] 497 | then 498 | else 499 | _cabal_available_packages_cache; 500 | fi 501 | packages=${(f)"$(<${packages_tmp_file})"} 502 | _arguments "*:package:(${packages})" 503 | } 504 | 505 | _cabal_build_options=( {-h,--help} \ 506 | {-v=,--verbose=}':level:(0 1 2 3)' \ 507 | '--builddir=:buiddir:_files -/' \ 508 | {-g,--ghc} \ 509 | '--ghcjs' \ 510 | '--uhc' \ 511 | '--haskell-suite' \ 512 | '--cabal-file=:cabalfile:_files -g "*.cabal"' \ 513 | '(-w --with-compiler)'{-w,--with-compiler}':compiler:_cabal_find_ghc' \ 514 | '--with-hc-pkg=:hcpkg:_files' \ 515 | '--prefix=:dir:_files -/' \ 516 | '--binddir=:dir:_files -/' \ 517 | '--libdir=:dir:_files -/' \ 518 | '--libsubdir=:dir:_files -/' \ 519 | '--dynlibdir=:dir:_files -/' \ 520 | '--libexecdir=:dir:_files -/' \ 521 | '--libexecsubdir=:dir:_files -/' \ 522 | '--datadir=:dir:_files -/' \ 523 | '--datasubdir=:dir:_files -/' \ 524 | '--docdir=:dir:_files -/' \ 525 | '--htmldir=:dir:_files -/' \ 526 | '--haddockdir=:dir:_files -/' \ 527 | '--sysconfdir=:dir:_files -/' \ 528 | '--program-prefix=:dir:_files -/' \ 529 | '--program-suffix=:dir:_files -/' \ 530 | '--enable-library-vanilla' \ 531 | '--disable-library-vanilla' \ 532 | '--disable-library-profiling' \ 533 | '--disable-library-profiling' \ 534 | '--enable-shared' \ 535 | '--disable-shared' \ 536 | '--enable-static' \ 537 | '--disable-static' \ 538 | '--enable-executable-dynamic' \ 539 | '--disable-executable-dynamic' \ 540 | '--enable-executable-static' \ 541 | '--disable-executable-static' \ 542 | {-p,--enable-profiling} \ 543 | '--disable-profiling' \ 544 | '--enable-executable-profiling' \ 545 | '--disable-executable-profiling' \ 546 | '--profiling-detail:detail:(default none exported-functions all-functions)' \ 547 | '--library-profiling-detail:detail:(default none exported-functions all-functions)' \ 548 | {-O-,--enable-optimization=}':level:(0 1 2)' \ 549 | '--disable-optimisation' \ 550 | '--enable-debug-info:(0 1 2 3)' \ 551 | '--disable-debug-info' \ 552 | '--enable-library-for-ghci' \ 553 | '--disable-library-for-ghci' \ 554 | '--enable-split-sections' \ 555 | '--disable-split-sections' \ 556 | '--enable-split-objs' \ 557 | '--disable-split-objs' \ 558 | '--enable-executable-stripping' \ 559 | '--disable-executable-stripping' \ 560 | '--enable-library-stripping' \ 561 | '--disable-library-stripping' \ 562 | '--enable-build-info' \ 563 | '--disable-build-info' \ 564 | '--configure-option::_guard ".*" ""' \ 565 | '--user' \ 566 | '--global' \ 567 | '--package-db=:package DB:_files -]' \ 568 | {-f,--flags} \ 569 | '--enable-deterministic' \ 570 | '--disable-deterministic' \ 571 | '--ipid' \ 572 | '--cid' \ 573 | '--extra-lib-dirs=:extralib:_files -/' \ 574 | '--extra-lib-dirs-static=:extralib:_files -/' \ 575 | '--extra-framework-dirs=:path:_files -/' \ 576 | '--extra-prog-path=:path:_files -/' \ 577 | '--instantiate-with' \ 578 | '--enable-tests' \ 579 | '--disable-tests' \ 580 | '--enable-coverage' \ 581 | '--disable-coverage' \ 582 | '--enable-library-coverage' \ 583 | '--disable-library-coverage' \ 584 | '--enable-benchmarks' \ 585 | '--disable-benchmarks' \ 586 | '--enable-relocatable' \ 587 | '--disable-relocatable' \ 588 | '--disable-response-files' \ 589 | '--allow-depending-on-private-libs' \ 590 | '--cabal-lib-version' \ 591 | '--constraint' \ 592 | '--preference' \ 593 | '--solver' \ 594 | '--allow-older' \ 595 | '--allow-newer' \ 596 | '--write-ghc-environment-files=: :(always never ghc8.4.4+)' \ 597 | '--enable-documentation' \ 598 | '--disable-documentation' \ 599 | '--doc-index-file=: :_files' \ 600 | '--dry-run' \ 601 | '--max-backjumps=:max backjumps:_guard "\d\+" "max backjumps"' \ 602 | '--reorder-goals' \ 603 | '--count-conflicts' \ 604 | '--minimize-conflict-set' \ 605 | '--independent-goals' \ 606 | '--shadow-installed-packages' \ 607 | '--strong-flags' \ 608 | '--allow-boot-library-installs' \ 609 | '--reject-unconstrained-dependencies: :(none all)' \ 610 | '--reinstall' \ 611 | '--avoid-reinstalls' \ 612 | '--force-reinstalls' \ 613 | '--upgrade-dependencies' \ 614 | '--only-dependencies' \ 615 | '--dependencies-only' \ 616 | '--only-download' \ 617 | '--index-state' \ 618 | '--root-cmd=: :_files' \ 619 | '--symlink-bindir=: :_files -/' \ 620 | '--build-summary' \ 621 | '--build-log' \ 622 | '--remote-build-reporting' \ 623 | '--report-planning-failure' \ 624 | '--enable-per-component' \ 625 | '--disable-per-component' \ 626 | '--one-shot' \ 627 | '--run-tests' \ 628 | {-j,--jobs}':number of jobs:' \ 629 | '--keep-going' \ 630 | '--offline' \ 631 | '--project-file=: :_files' \ 632 | '--haddock-hoogle' \ 633 | '--haddock-html' \ 634 | '--haddock-html-location=URL' \ 635 | '--haddock-for-hackage' \ 636 | '--haddock-executables' \ 637 | '--haddock-tests' \ 638 | '--haddock-benchmarks' \ 639 | '--haddock-all' \ 640 | '--haddock-internal' \ 641 | '--haddock-css=: :_files' \ 642 | '--haddock-hyperlink-source' \ 643 | '--haddock-quickjump' \ 644 | '--haddock-hscolour-css=: :_files' \ 645 | '--haddock-contents-location' \ 646 | '--test-log' \ 647 | '--test-machine-log' \ 648 | '--test-show-details' \ 649 | '--test-keep-tix-files' \ 650 | '--test-wrapper=: :_files' \ 651 | '--test-fail-when-no-test-suites' \ 652 | '--test-options' \ 653 | '--test-option' \ 654 | '--only-configure' \ 655 | '--ghc-option:ghc option:_ghc' \ 656 | '--ghc-options:ghc options:_ghc' \ 657 | ) 658 | 659 | _cabal_install_options=( '--lib' \ 660 | '--installdir:dir:_files -/' \ 661 | {--ignore-project,-z}':ignore project' \ 662 | '--package-env: :_files' \ 663 | '--overwrite-policy=:policy:(always never)' \ 664 | '--install-method=:method:(default copy symlink)' \ 665 | ) 666 | 667 | _cabal_subcommand () { 668 | local subcommands 669 | _arguments "*:subcommand:(${_cabal_subcommands})" 670 | } 671 | 672 | _cabal () { 673 | local context state state_descr line word current_word depth 674 | local subcommand="" 675 | typeset -A opt_args 676 | 677 | _cabal_default_options 678 | 679 | current_word=$words[$CURRENT] 680 | for word in $words; do 681 | if [[ -n ${word:*_cabal_subcommands} ]];then 682 | subcommand=$word 683 | break 684 | fi 685 | done 686 | case ${subcommand:+subcommand_}"args" in 687 | args) 688 | # handle subcommands and global options" 689 | _arguments ':subcommand:_cabal_subcommand' \ 690 | {-h,--help} \ 691 | {-v,--version} \ 692 | '--numeric-version' \ 693 | '--config-file=:cabal config file:_files' \ 694 | '--sandbox-config-file=:sandbox config file:_files' \ 695 | '--defalt-user-config=:user cabal config file:_files' \ 696 | '--require-sandbox' \ 697 | '--no-require-sandbox' \ 698 | '--ignore-sandbox' \ 699 | '--ignore-expiry' \ 700 | '--http-transport: :_guard ".*" ""' \ 701 | '--enable-nix' \ 702 | '--disable-nix' \ 703 | '--remote-repo: :_guard ".*" ""' \ 704 | '--remote-repo-cache=:cache directory for remote repos:_files -/' \ 705 | '--local-repo=: :_files -/' \ 706 | {--logs-dir,--logsdir=}':log directory:_files -/' \ 707 | '--world-file=: :_files' \ 708 | {--store-dir=,--storedir=}':store directory:_files -/' 709 | ;; 710 | subcommand_args) 711 | # handle subcommand arguments and options 712 | case ${subcommand} in 713 | build) 714 | if [[ ${current_word:0:4} == "lib:" ]]; then 715 | _arguments '*:pkgspec:_cabal_pkgspecs_lib' 716 | elif [[ ${current_word:0:5} == "test:" ]]; then 717 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 718 | elif [[ ${current_word:0:4} == "exe:" ]]; then 719 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 720 | elif [[ ${current_word:0:6} == "bench:" ]]; then 721 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 722 | elif [[ ${current_word:0:4} == "pkg:" ]]; then 723 | _arguments '*:pkgspec:_cabal_pkgspecs' 724 | elif [[ ${current_word} =~ ':' ]]; then 725 | _cabal_components_in_package ${current_word/:*/} ${current_word} 726 | else 727 | _arguments '*:components:_cabal_components' \ 728 | ${_cabal_build_options[@]} 729 | fi 730 | ;; 731 | bench) 732 | if [[ ${current_word:0:4} == "pkg:" ]]; then 733 | _arguments '*:pkgspec:_cabal_benchmark_pkgspecs' 734 | elif [[ ${current_word:0:6} == "bench:" ]]; then 735 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 736 | else 737 | _alternative 'cmps:components:_cabal_benchmarks' 738 | fi 739 | ;; 740 | check) 741 | _arguments '::' \ 742 | {-h,--help} \ 743 | {-v=,--verbose=}':level:(0 1 2 3)' 744 | ;; 745 | clean) 746 | _arguments '::' \ 747 | {-h,--help} \ 748 | {-v=,--verbose=}':level:(0 1 2 3)' \ 749 | '--builddir=:The directory where Cabal puts generated build files:_files -/' \ 750 | '--project-file=:Set the name of the cabal.project file to search for in parent directories:_guard ".\+"' \ 751 | {-s,--save-config} 752 | 753 | ;; 754 | configure) 755 | _arguments "1:packages:_cabal_packages" \ 756 | ${_cabal_build_options[@]} 757 | ;; 758 | exec) 759 | if [[ ${current_word:0:4} == "pkg:" ]]; then 760 | _arguments '*:pkgspec:_cabal_executable_pkgspecs' 761 | elif [[ ${current_word:0:4} == "lib:" ]]; then 762 | _arguments '*:pkgspec:_cabal_pkgspecs_lib' 763 | elif [[ ${current_word:0:5} == "test:" ]]; then 764 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 765 | elif [[ ${current_word:0:4} == "exe:" ]]; then 766 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 767 | elif [[ ${current_word:0:6} == "bench:" ]]; then 768 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 769 | else 770 | _alternative 'cmps:components:_cabal_all_executables' 771 | fi 772 | ;; 773 | fetch) 774 | _arguments "::" \ 775 | {-h,--help} \ 776 | {-v=,--verbose=}':level:(0 1 2 3)' \ 777 | '--numeric-version' \ 778 | '--config-file=:Set an alternate location for the config file:_files' \ 779 | '--sandbox-config-file=:Set an alternate location for the sandbox config file:_files' \ 780 | '--default-user-config=:Set a location for a cabal.config file for projects without their own cabal.config freeze file.:_files' \ 781 | '--require-sandbox' \ 782 | '--no-require-sandbox' \ 783 | '--ignore-sandbox' \ 784 | '--no-ignore-sandbox' \ 785 | '--http-transport=:Set a transport for http(s) requests.:(curl wget powershell plain-http)' \ 786 | '--enable-nix' \ 787 | '--disable-nix' \ 788 | "*:package:_cabal_available_packages" 789 | 790 | ;; 791 | freeze) 792 | _arguments '::' \ 793 | ${_cabal_build_options[@]} 794 | 795 | ;; 796 | gen-bounds) 797 | _arguments '::' \ 798 | {-h,--help} \ 799 | {-v=,--verbose=}':level:(0 1 2 3)' 800 | ;; 801 | get) 802 | _arguments '::' \ 803 | {-h,--help} \ 804 | {-v=,--verbose=}':level:(0 1 2 3)' \ 805 | {-d,--destdir=}':Where to place the package source.:_files -/' \ 806 | {-s,--source-repository=}':source repository:_guard ".\+"' \ 807 | '--index-state=:User source package index state:_guard ".\+"' \ 808 | '--pristine' \ 809 | "*:package:_cabal_available_packages" 810 | ;; 811 | haddock-project) 812 | _arguments '::' \ 813 | {-h,--help} \ 814 | {-v=,--verbose=}':level:(0 1 2 3)' \ 815 | '--hackage' \ 816 | '--local' \ 817 | '--output:outputdir:_files -/' \ 818 | '--prologue=:prologue:_files' \ 819 | '--gen-index' \ 820 | '--gen-contents' \ 821 | '--hoogle' \ 822 | '--executables' \ 823 | '--tests' \ 824 | '--benchmarks' \ 825 | '--foreign-libraries' \ 826 | '--internal' \ 827 | '--css=:csspath:_files' \ 828 | '--hyperlink-source' \ 829 | '--quickjump' \ 830 | '--hscolour-css:path:_files' \ 831 | '--with-haddock:path:_files' \ 832 | '--with-ghc=:path:_files' \ 833 | '--ghc-options:ghc options:_ghc' \ 834 | '--haddock-options:haddock options:' 835 | ;; 836 | haddock) 837 | if [[ ${current_word:0:4} == "pkg:" ]]; then 838 | _arguments '*:pkgspec:_cabal_pkgspecs' 839 | elif [[ ${current_word:0:4} == "lib:" ]]; then 840 | _arguments '*:pkgspec:_cabal_pkgspecs_lib' 841 | elif [[ ${current_word:0:5} == "test:" ]]; then 842 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 843 | elif [[ ${current_word:0:4} == "exe:" ]]; then 844 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 845 | elif [[ ${current_word:0:6} == "bench:" ]]; then 846 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 847 | elif [[ ${current_word} =~ ':' ]]; then 848 | _cabal_components_in_package ${current_word/:*/} 849 | else 850 | _arguments '*:components:_cabal_components' \ 851 | ${_cabal_build_options[@]} 852 | fi 853 | ;; 854 | hscolour) 855 | _arguments '::' \ 856 | {-h,--help} \ 857 | {-v=,--verbose=}':level:(0 1 2 3)' \ 858 | '--builddir=:buiddir:_files -/' \ 859 | '--executables' \ 860 | '--tests' \ 861 | '--benchmarks' \ 862 | '--foreign-libraries' \ 863 | '--all' \ 864 | '--css:path:_files -/' 865 | ;; 866 | info) 867 | _arguments '::' \ 868 | {-h,--help} \ 869 | {-v=,--verbose=}':level:(0 1 2 3)' \ 870 | '--package-db=:package DB:_files -/' \ 871 | "*:package:_cabal_available_packages" 872 | ;; 873 | init) 874 | # TODO: better _guards 875 | _arguments ':init:' \ 876 | {-h,--help} \ 877 | {-i,--interactive} \ 878 | {-n,--non-interactive} \ 879 | {-q,--quiet} \ 880 | '--no-comments' \ 881 | {-m,--minimal} \ 882 | '--overwrite' \ 883 | '--package-dir=:Root directory of the package (default = current directory).:_files -/' \ 884 | {-p,--package-name=}':Name of the Cabal package to create.:_guard ".\+"' \ 885 | '--version=:Initial version of the package.:_guard ".\+"' \ 886 | '--cabal-version=:Version of the Cabal specification.:_guard ".\+"' \ 887 | {-l,--license=}':Project license.:_guard ".\+"' \ 888 | {-a,--author=}":Name of the project's author.:_guard '.\+'" \ 889 | {-e,--email=}':Email address of the maintainer.:_guard ".\+"' \ 890 | {-u,--homepage=}':Project homepage and/or repository.:_guard ".\+"' \ 891 | {-s,--synopsis=}':Short project synopsis.:_guard ".\+"' \ 892 | {-c,--category=}':Project category.:_guard ".\+"' \ 893 | {-x,--extra-source-file=}':Extra source file to be distributed with tarball.:_files' \ 894 | '--lib' \ 895 | '--exe' \ 896 | '--libandexe' \ 897 | '--tests' \ 898 | '--test-dir=:Directory containing tests.:_files -]' \ 899 | '--simple' \ 900 | '--main-is=:Specify the main module.:_files' \ 901 | '--language=:Specify the default language.:_guard ".\+"' \ 902 | {-o,--expose-module=}':Export a module from the package.:_guard ".\+"' \ 903 | '--extension=:Use a LANGUAGE extension (in the other-extensions field).:_guard "\.+"' \ 904 | {-d,--dependency=}':Package dependency.:_guard ".\+"' \ 905 | '--application-dir=:Directory containing package application executable.:_files' \ 906 | '--source-dir=:Directory containing package library source.:_files' \ 907 | '--build-tool=:Required external build tool.:_files' \ 908 | {-w,--with-compiler=}':give the path to a particular compiler:_files' \ 909 | {-v=,--verbose=}':level:(0 1 2 3)' 910 | ;; 911 | install) 912 | if [[ ${current_word:0:4} == "pkg:" ]]; then 913 | _arguments '*:pkgspec:_cabal_pkgspecs' 914 | elif [[ ${current_word:0:4} == "lib:" ]]; then 915 | _arguments '*:pkgspec:_cabal_pkgspecs_lib' 916 | elif [[ ${current_word:0:5} == "test:" ]]; then 917 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 918 | elif [[ ${current_word:0:4} == "exe:" ]]; then 919 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 920 | elif [[ ${current_word:0:6} == "bench:" ]]; then 921 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 922 | else 923 | if [[ -e "cabal.project" && \ 924 | ${words[(i)-z]} -gt ${#words} && \ 925 | ${words[(i)--ignore-project]} -gt ${#words} 926 | ]] 927 | then 928 | _arguments '*:components:_cabal_components' \ 929 | ${_cabal_build_options[@]} \ 930 | ${_cabal_install_options[@]} 931 | 932 | else 933 | _arguments '*:package:_cabal_available_packages' 934 | # TODO: 935 | # _arguments '*:package:_cabal_available_packages' \ 936 | # ${_cabal_build_options[@]} \ 937 | # ${_cabal_install_options[@]} 938 | 939 | fi 940 | fi 941 | ;; 942 | list) 943 | _arguments '::' \ 944 | {-h,--help} \ 945 | {-v=,--verbose=}':level:(0 1 2 3)' \ 946 | '--installed' \ 947 | '--simple-output' \ 948 | '--package-db=:package DB:_files -/' \ 949 | '*:package:_cabal_available_packages' 950 | ;; 951 | outdated) 952 | _arguments '::' \ 953 | {-h,--help} \ 954 | {-v=,--verbose=}':level:(0 1 2 3)' \ 955 | '--freeze-file' \ 956 | '--project-file=:project file:_files' \ 957 | '--simple-output' \ 958 | '--exit-code' \ 959 | {-q,--quiet} \ 960 | '--ignore' \ 961 | '--minor' 962 | ;; 963 | repl) 964 | if [[ ${current_word:0:4} == "pkg:" ]]; then 965 | _arguments '*:pkgspec:_cabal_pkgspecs' 966 | elif [[ ${current_word:0:4} == "lib:" ]]; then 967 | _arguments '*:pkgspec:_cabal_pkgspecs_lib' 968 | elif [[ ${current_word:0:5} == "test:" ]]; then 969 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 970 | elif [[ ${current_word:0:4} == "exe:" ]]; then 971 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 972 | elif [[ ${current_word:0:6} == "bench:" ]]; then 973 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 974 | elif [[ ${current_word} =~ ':' ]]; then 975 | _cabal_components_in_package ${current_word/:*/} 976 | else 977 | _arguments '*:components:_cabal_components' \ 978 | ${_cabal_build_options[@]} 979 | fi 980 | ;; 981 | report) 982 | _arguments '::' \ 983 | {-h,--help} \ 984 | {-v=,--verbose=}':level:(0 1 2 3)' \ 985 | {-u,--username=}':username:_guard ".\+"' \ 986 | {-p,--password=}':password:_guard ".\+"' 987 | 988 | ;; 989 | run) 990 | if [[ ${current_word:0:4} == "pkg:" ]]; then 991 | _arguments '*:pkgspec:_cabal_executable_pkgspecs' 992 | elif [[ ${current_word:0:5} == "test:" ]]; then 993 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 994 | elif [[ ${current_word:0:4} == "exe:" ]]; then 995 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 996 | elif [[ ${current_word:0:6} == "bench:" ]]; then 997 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 998 | else 999 | _alternative 'cmps:components:_cabal_all_executables' 1000 | fi 1001 | ;; 1002 | sdist) 1003 | _arguments '::' \ 1004 | {-h,--help} \ 1005 | {-v=,--verbose=}':level:(0 1 2 3)' \ 1006 | '--builddir=:builddir:_files -/' \ 1007 | '--project-file=:projectfile:_files' \ 1008 | {-l,--list-only} \ 1009 | {-z,--null-sep} \ 1010 | {-o,--output-dir=}':outputdir:_files -/' 1011 | ;; 1012 | test) 1013 | if [[ ${current_word:0:4} == "pkg:" ]]; then 1014 | _arguments '*:pkgspec:_cabal_tests_pkgspecs' 1015 | elif [[ ${current_word:0:4} == "lib:" ]]; then 1016 | _arguments '*:pkgspec:_cabal_pkgspecs_lib' 1017 | elif [[ ${current_word:0:5} == "test:" ]]; then 1018 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 1019 | elif [[ ${current_word:0:4} == "exe:" ]]; then 1020 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 1021 | elif [[ ${current_word:0:6} == "bench:" ]]; then 1022 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 1023 | else 1024 | _alternative 'cmps:components:_cabal_tests' 1025 | fi 1026 | ;; 1027 | update) 1028 | _alternative 'cmps:components:_cabal_executables' \ 1029 | 'pkg:pkgspec:_cabal_executable_pkgspecs' 1030 | ;; 1031 | upload) 1032 | _arguments '*:tar files:_files' \ 1033 | {-h,--help} \ 1034 | {-v=,--verbose=}':level:(0 1 2 3)' \ 1035 | '--publish' \ 1036 | {-d,--documentation} \ 1037 | {-u,--username} \ 1038 | {-p,--password} \ 1039 | {-P,--password-command} 1040 | ;; 1041 | user-config) 1042 | _arguments '*:user-config-command:(init diff update)' \ 1043 | {-h,--help} \ 1044 | {-v=,--verbose=}':level:(0 1 2 3)' \ 1045 | {-f,--force} \ 1046 | {-a,--augment=}':setting to augment:_guard ".\+"' 1047 | ;; 1048 | list-bin) 1049 | if [[ ${current_word:0:4} == "pkg:" ]]; then 1050 | _arguments '*:pkgspec:_cabal_executable_pkgspecs' 1051 | elif [[ ${current_word:0:5} == "test:" ]]; then 1052 | _arguments '*:pkgspec:_cabal_pkgspecs_test' 1053 | elif [[ ${current_word:0:4} == "exe:" ]]; then 1054 | _arguments '*:pkgspec:_cabal_pkgspecs_exe' 1055 | elif [[ ${current_word:0:6} == "bench:" ]]; then 1056 | _arguments '*:pkgspec:_cabal_pkgspecs_bench' 1057 | else 1058 | _alternative 'cmps:components:_cabal_all_executables' 1059 | fi 1060 | esac 1061 | esac 1062 | } 1063 | 1064 | compdef _cabal cabal 1065 | --------------------------------------------------------------------------------