1356c4a40515ffb86ffd222ec8b13a723877a166
[notmuch] / completion / notmuch-completion.bash
1 # bash completion for notmuch                              -*- shell-script -*-
2 #
3 # Copyright © 2013 Jani Nikula
4 #
5 # Based on the bash-completion package:
6 # http://bash-completion.alioth.debian.org/
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 2 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program.  If not, see http://www.gnu.org/licenses/ .
20 #
21 # Author: Jani Nikula <jani@nikula.org>
22 #
23 #
24 # BUGS:
25 #
26 # Add space after an --option without parameter (e.g. reply --decrypt)
27 # on completion.
28 #
29
30 _notmuch_shared_options="--help --uuid= --version"
31
32 # $1: current input of the form prefix:partialinput, where prefix is
33 # to or from.
34 _notmuch_email()
35 {
36     local output prefix cur
37
38     prefix="${1%%:*}"
39     cur="${1#*:}"
40
41     # Cut the input to be completed at punctuation because
42     # (apparently) Xapian does not support the trailing wildcard '*'
43     # operator for input with punctuation. We let compgen handle the
44     # extra filtering required.
45     cur="${cur%%[^a-zA-Z0-9]*}"
46
47     case "$prefix" in
48         # Note: It would be more accurate and less surprising to have
49         # output=recipients here for to: addresses, but as gathering
50         # the recipient addresses requires disk access for each
51         # matching message, this becomes prohibitively slow.
52         to|from) output=sender;;
53         *) return;;
54     esac
55
56     # Only emit plain, lower case, unique addresses.
57     notmuch address --output=$output $prefix:"${cur}*" | \
58         sed 's/[^<]*<\([^>]*\)>/\1/' | tr "[:upper:]" "[:lower:]" | sort -u
59 }
60
61 _notmuch_search_terms()
62 {
63     local cur prev words cword split
64     # handle search prefixes and tags with colons and equal signs
65     _init_completion -n := || return
66
67     case "${cur}" in
68         tag:*)
69             COMPREPLY=( $(compgen -P "tag:" -W "`notmuch search --output=tags \*`" -- ${cur##tag:}) )
70             ;;
71         to:*)
72             COMPREPLY=( $(compgen -P "to:" -W "`_notmuch_email ${cur}`" -- ${cur##to:}) )
73             ;;
74         from:*)
75             COMPREPLY=( $(compgen -P "from:" -W "`_notmuch_email ${cur}`" -- ${cur##from:}) )
76             ;;
77         path:*)
78             local path=`notmuch config get database.path`
79             compopt -o nospace
80             COMPREPLY=( $(compgen -d "$path/${cur##path:}" | sed "s|^$path/||" ) )
81             ;;
82         folder:*)
83             local path=`notmuch config get database.path`
84             compopt -o nospace
85             COMPREPLY=( $(compgen -d "$path/${cur##folder:}" | \
86                 sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
87             ;;
88         *)
89             local search_terms="from: to: subject: attachment: mimetype: tag: id: thread: folder: path: date:"
90             compopt -o nospace
91             COMPREPLY=( $(compgen -W "${search_terms}" -- ${cur}) )
92             ;;
93     esac
94     # handle search prefixes and tags with colons
95     __ltrim_colon_completions "${cur}"
96 }
97
98 _notmuch_compact()
99 {
100     local cur prev words cword split
101     _init_completion -s || return
102
103     $split &&
104     case "${prev}" in
105         --backup)
106             _filedir -d
107             return
108             ;;
109     esac
110
111     ! $split &&
112     case "${cur}" in
113         -*)
114             local options="--backup= --quiet ${_notmuch_shared_options}"
115             compopt -o nospace
116             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
117             ;;
118     esac
119 }
120
121 _notmuch_config()
122 {
123     local cur prev words cword split
124     _init_completion || return
125
126     case "${prev}" in
127         config)
128             COMPREPLY=( $(compgen -W "get set list" -- ${cur}) )
129             ;;
130         get|set)
131             COMPREPLY=( $(compgen -W "`notmuch config list | sed 's/=.*\$//'`" -- ${cur}) )
132             ;;
133         # these will also complete on config get, but we don't care
134         database.path)
135             _filedir -d
136             ;;
137         maildir.synchronize_flags)
138             COMPREPLY=( $(compgen -W "true false" -- ${cur}) )
139             ;;
140     esac
141 }
142
143 _notmuch_count()
144 {
145     local cur prev words cword split
146     _init_completion -s || return
147
148     $split &&
149     case "${prev}" in
150         --output)
151             COMPREPLY=( $( compgen -W "messages threads files" -- "${cur}" ) )
152             return
153             ;;
154         --exclude)
155             COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) )
156             return
157             ;;
158         --input)
159             _filedir
160             return
161             ;;
162     esac
163
164     ! $split &&
165     case "${cur}" in
166         -*)
167             local options="--output= --exclude= --batch --input= --lastmod ${_notmuch_shared_options}"
168             compopt -o nospace
169             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
170             ;;
171         *)
172             _notmuch_search_terms
173             ;;
174     esac
175 }
176
177 _notmuch_dump()
178 {
179     local cur prev words cword split
180     _init_completion -s || return
181
182     $split &&
183     case "${prev}" in
184         --format)
185             COMPREPLY=( $( compgen -W "sup batch-tag" -- "${cur}" ) )
186             return
187             ;;
188         --output)
189             _filedir
190             return
191             ;;
192     esac
193
194     ! $split &&
195     case "${cur}" in
196         -*)
197             local options="--gzip --format= --output= ${_notmuch_shared_options}"
198             compopt -o nospace
199             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
200             ;;
201         *)
202             _notmuch_search_terms
203             ;;
204     esac
205 }
206
207 _notmuch_insert()
208 {
209     local cur prev words cword split
210     # handle tags with colons and equal signs
211     _init_completion -s -n := || return
212
213     $split &&
214     case "${prev}" in
215         --folder)
216             local path=`notmuch config get database.path`
217             compopt -o nospace
218             COMPREPLY=( $(compgen -d "$path/${cur}" | \
219                 sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
220             return
221             ;;
222     esac
223
224     ! $split &&
225     case "${cur}" in
226         --*)
227             local options="--create-folder --folder= --keep --no-hooks ${_notmuch_shared_options}"
228             compopt -o nospace
229             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
230             return
231             ;;
232         +*)
233             COMPREPLY=( $(compgen -P "+" -W "`notmuch search --output=tags \*`" -- ${cur##+}) )
234             ;;
235         -*)
236             COMPREPLY=( $(compgen -P "-" -W "`notmuch search --output=tags \*`" -- ${cur##-}) )
237             ;;
238     esac
239     # handle tags with colons
240     __ltrim_colon_completions "${cur}"
241 }
242
243 _notmuch_new()
244 {
245     local cur prev words cword split
246     _init_completion || return
247
248     case "${cur}" in
249         -*)
250             local options="--no-hooks --quiet ${_notmuch_shared_options}"
251             compopt -o nospace
252             COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
253             ;;
254     esac
255 }
256
257 _notmuch_reply()
258 {
259     local cur prev words cword split
260     _init_completion -s || return
261
262     $split &&
263     case "${prev}" in
264         --format)
265             COMPREPLY=( $( compgen -W "default json sexp headers-only" -- "${cur}" ) )
266             return
267             ;;
268         --reply-to)
269             COMPREPLY=( $( compgen -W "all sender" -- "${cur}" ) )
270             return
271             ;;
272     esac
273
274     ! $split &&
275     case "${cur}" in
276         -*)
277             local options="--format= --format-version= --reply-to= --decrypt ${_notmuch_shared_options}"
278             compopt -o nospace
279             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
280             ;;
281         *)
282             _notmuch_search_terms
283             ;;
284     esac
285 }
286
287 _notmuch_restore()
288 {
289     local cur prev words cword split
290     _init_completion -s || return
291
292     $split &&
293     case "${prev}" in
294         --format)
295             COMPREPLY=( $( compgen -W "sup batch-tag auto" -- "${cur}" ) )
296             return
297             ;;
298         --input)
299             _filedir
300             return
301             ;;
302     esac
303
304     ! $split &&
305     case "${cur}" in
306         -*)
307             local options="--format= --accumulate --input= ${_notmuch_shared_options}"
308             compopt -o nospace
309             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
310             ;;
311     esac
312 }
313
314 _notmuch_search()
315 {
316     local cur prev words cword split
317     _init_completion -s || return
318
319     $split &&
320     case "${prev}" in
321         --format)
322             COMPREPLY=( $( compgen -W "json sexp text text0" -- "${cur}" ) )
323             return
324             ;;
325         --output)
326             COMPREPLY=( $( compgen -W "summary threads messages files tags" -- "${cur}" ) )
327             return
328             ;;
329         --sort)
330             COMPREPLY=( $( compgen -W "newest-first oldest-first" -- "${cur}" ) )
331             return
332             ;;
333         --exclude)
334             COMPREPLY=( $( compgen -W "true false flag all" -- "${cur}" ) )
335             return
336             ;;
337     esac
338
339     ! $split &&
340     case "${cur}" in
341         -*)
342             local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate= ${_notmuch_shared_options}"
343             compopt -o nospace
344             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
345             ;;
346         *)
347             _notmuch_search_terms
348             ;;
349     esac
350 }
351
352 _notmuch_address()
353 {
354     local cur prev words cword split
355     _init_completion -s || return
356
357     $split &&
358     case "${prev}" in
359         --format)
360             COMPREPLY=( $( compgen -W "json sexp text text0" -- "${cur}" ) )
361             return
362             ;;
363         --output)
364             COMPREPLY=( $( compgen -W "sender recipients count" -- "${cur}" ) )
365             return
366             ;;
367         --sort)
368             COMPREPLY=( $( compgen -W "newest-first oldest-first" -- "${cur}" ) )
369             return
370             ;;
371         --exclude)
372             COMPREPLY=( $( compgen -W "true false flag all" -- "${cur}" ) )
373             return
374             ;;
375         --deduplicate)
376             COMPREPLY=( $( compgen -W "no mailbox address" -- "${cur}" ) )
377             return
378             ;;
379     esac
380
381     ! $split &&
382     case "${cur}" in
383         -*)
384             local options="--format= --output= --sort= --exclude= --deduplicate= ${_notmuch_shared_options}"
385             compopt -o nospace
386             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
387             ;;
388         *)
389             _notmuch_search_terms
390             ;;
391     esac
392 }
393
394 _notmuch_show()
395 {
396     local cur prev words cword split
397     _init_completion -s || return
398
399     $split &&
400     case "${prev}" in
401         --entire-thread)
402             COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) )
403             return
404             ;;
405         --format)
406             COMPREPLY=( $( compgen -W "text json sexp mbox raw" -- "${cur}" ) )
407             return
408             ;;
409         --exclude|--body)
410             COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) )
411             return
412             ;;
413     esac
414
415     ! $split &&
416     case "${cur}" in
417         -*)
418             local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt --include-html ${_notmuch_shared_options}"
419             compopt -o nospace
420             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
421             ;;
422         *)
423             _notmuch_search_terms
424             ;;
425     esac
426 }
427
428 _notmuch_tag()
429 {
430     local cur prev words cword split
431     # handle tags with colons and equal signs
432     _init_completion -s -n := || return
433
434     $split &&
435     case "${prev}" in
436         --input)
437             _filedir
438             return
439             ;;
440     esac
441
442     ! $split &&
443     case "${cur}" in
444         --*)
445             local options="--batch --input= --remove-all ${_notmuch_shared_options}"
446             compopt -o nospace
447             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
448             return
449             ;;
450         +*)
451             COMPREPLY=( $(compgen -P "+" -W "`notmuch search --output=tags \*`" -- ${cur##+}) )
452             ;;
453         -*)
454             COMPREPLY=( $(compgen -P "-" -W "`notmuch search --output=tags \*`" -- ${cur##-}) )
455             ;;
456         *)
457             _notmuch_search_terms
458             return
459             ;;
460     esac
461     # handle tags with colons
462     __ltrim_colon_completions "${cur}"
463 }
464
465 _notmuch()
466 {
467     local _notmuch_commands="compact config count dump help insert new reply restore search address setup show tag"
468     local arg cur prev words cword split
469
470     # require bash-completion with _init_completion
471     type -t _init_completion >/dev/null 2>&1 || return
472
473     _init_completion || return
474
475     COMPREPLY=()
476
477     # subcommand
478     _get_first_arg
479
480     # complete --help option like the subcommand
481     if [ -z "${arg}" -a "${prev}" = "--help" ]; then
482         arg="help"
483     fi
484
485     if [ -z "${arg}" ]; then
486         # top level completion
487         local top_options="--help --version"
488         case "${cur}" in
489             -*) COMPREPLY=( $(compgen -W "${top_options}" -- ${cur}) ) ;;
490             *) COMPREPLY=( $(compgen -W "${_notmuch_commands}" -- ${cur}) ) ;;
491         esac
492     elif [ "${arg}" = "help" ]; then
493         # handle help command specially due to _notmuch_commands usage
494         local help_topics="$_notmuch_commands hooks search-terms"
495         COMPREPLY=( $(compgen -W "${help_topics}" -- ${cur}) )
496     else
497         # complete using _notmuch_subcommand if one exist
498         local completion_func="_notmuch_${arg//-/_}"
499         declare -f $completion_func >/dev/null && $completion_func
500     fi
501 } &&
502 complete -F _notmuch notmuch