]> git.cworth.org Git - notmuch/blob - completion/notmuch-completion.bash
tests: make timeout configurable with NOTMUCH_TEST_TIMEOUT (default: 2m)
[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 # https://github.com/scop/bash-completion
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 https://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_mimetype()
62 {
63     # use mime types from mime-support package if available, and fall
64     # back to a handful of common ones otherwise
65     if [ -r "/etc/mime.types" ]; then
66         sed -n '/^[[:alpha:]]/{s/[[:space:]].*//;p;}' /etc/mime.types
67     else
68         cat <<EOF
69 application/gzip
70 application/msword
71 application/pdf
72 application/zip
73 audio/mpeg
74 audio/ogg
75 image/gif
76 image/jpeg
77 image/png
78 message/rfc822
79 text/calendar
80 text/html
81 text/plain
82 text/vcard
83 text/x-diff
84 text/x-vcalendar
85 EOF
86     fi
87 }
88
89 _notmuch_search_terms()
90 {
91     local cur prev words cword split
92     # handle search prefixes and tags with colons and equal signs
93     _init_completion -n := || return
94
95     case "${cur}" in
96         tag:*)
97             COMPREPLY=( $(compgen -P "tag:" -W "`notmuch search --output=tags \*`" -- ${cur##tag:}) )
98             ;;
99         to:*)
100             COMPREPLY=( $(compgen -P "to:" -W "`_notmuch_email ${cur}`" -- ${cur##to:}) )
101             ;;
102         from:*)
103             COMPREPLY=( $(compgen -P "from:" -W "`_notmuch_email ${cur}`" -- ${cur##from:}) )
104             ;;
105         path:*)
106             local path=`notmuch config get database.path`
107             compopt -o nospace
108             COMPREPLY=( $(compgen -d "$path/${cur##path:}" | sed "s|^$path/||" ) )
109             ;;
110         folder:*)
111             local path=`notmuch config get database.path`
112             compopt -o nospace
113             COMPREPLY=( $(compgen -d "$path/${cur##folder:}" | \
114                 sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
115             ;;
116         mimetype:*)
117             compopt -o nospace
118             COMPREPLY=( $(compgen -P "mimetype:" -W "`_notmuch_mimetype ${cur}`" -- ${cur##mimetype:}) )
119             ;;
120         query:*)
121             compopt -o nospace
122             COMPREPLY=( $(compgen -P "query:" -W "`notmuch config list | sed -n '/^query\./s/^query\.\([^=]*\)=.*/\1/p'`" -- ${cur##query:}) )
123             ;;
124         *)
125             local search_terms="from: to: subject: attachment: mimetype: tag: id: thread: folder: path: date: lastmod: query: property:"
126             compopt -o nospace
127             COMPREPLY=( $(compgen -W "${search_terms}" -- ${cur}) )
128             ;;
129     esac
130     # handle search prefixes and tags with colons
131     __ltrim_colon_completions "${cur}"
132 }
133
134 _notmuch_compact()
135 {
136     local cur prev words cword split
137     _init_completion -s || return
138
139     $split &&
140     case "${prev}" in
141         --backup)
142             _filedir -d
143             return
144             ;;
145     esac
146
147     ! $split &&
148     case "${cur}" in
149         -*)
150             local options="--backup= --quiet ${_notmuch_shared_options}"
151             compopt -o nospace
152             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
153             ;;
154     esac
155 }
156
157 _notmuch_config()
158 {
159     local cur prev words cword split
160     _init_completion || return
161
162     case "${prev}" in
163         config)
164             COMPREPLY=( $(compgen -W "get set list" -- ${cur}) )
165             ;;
166         get|set)
167             COMPREPLY=( $(compgen -W "`notmuch config list | sed 's/=.*\$//'`" -- ${cur}) )
168             ;;
169         # these will also complete on config get, but we don't care
170         database.path)
171             _filedir -d
172             ;;
173         maildir.synchronize_flags)
174             COMPREPLY=( $(compgen -W "true false" -- ${cur}) )
175             ;;
176     esac
177 }
178
179 _notmuch_count()
180 {
181     local cur prev words cword split
182     _init_completion -s || return
183
184     $split &&
185     case "${prev}" in
186         --output)
187             COMPREPLY=( $( compgen -W "messages threads files" -- "${cur}" ) )
188             return
189             ;;
190         --exclude)
191             COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) )
192             return
193             ;;
194         --input)
195             _filedir
196             return
197             ;;
198     esac
199
200     ! $split &&
201     case "${cur}" in
202         -*)
203             local options="--output= --exclude= --batch --input= --lastmod ${_notmuch_shared_options}"
204             compopt -o nospace
205             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
206             ;;
207         *)
208             _notmuch_search_terms
209             ;;
210     esac
211 }
212
213 _notmuch_dump()
214 {
215     local cur prev words cword split
216     _init_completion -s || return
217
218     $split &&
219     case "${prev}" in
220         --format)
221             COMPREPLY=( $( compgen -W "sup batch-tag" -- "${cur}" ) )
222             return
223             ;;
224         --output)
225             _filedir
226             return
227             ;;
228     esac
229
230     ! $split &&
231     case "${cur}" in
232         -*)
233             local options="--gzip --format= --output= ${_notmuch_shared_options}"
234             compopt -o nospace
235             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
236             ;;
237         *)
238             _notmuch_search_terms
239             ;;
240     esac
241 }
242
243 _notmuch_emacs_mua()
244 {
245     local cur prev words cword split
246     _init_completion -s || return
247
248     $split &&
249     case "${prev}" in
250         --to|--cc|--bcc)
251             COMPREPLY=( $(compgen -W "`_notmuch_email to:${cur}`" -- ${cur}) )
252             return
253             ;;
254         --body)
255             _filedir
256             return
257             ;;
258     esac
259
260     ! $split &&
261     case "${cur}" in
262         -*)
263             local options="--subject= --to= --cc= --bcc= --body= --no-window-system --client --auto-daemon --create-frame --print --help --hello"
264
265             compopt -o nospace
266             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
267             ;;
268         *)
269             COMPREPLY=( $(compgen -W "`_notmuch_email to:${cur}`" -- ${cur}) )
270             return
271             ;;
272     esac
273 }
274
275 _notmuch_insert()
276 {
277     local cur prev words cword split
278     # handle tags with colons and equal signs
279     _init_completion -s -n := || return
280
281     $split &&
282     case "${prev}" in
283         --folder)
284             local path=`notmuch config get database.path`
285             compopt -o nospace
286             COMPREPLY=( $(compgen -d "$path/${cur}" | \
287                 sed "s|^$path/||" | grep -v "\(^\|/\)\(cur\|new\|tmp\)$" ) )
288             return
289             ;;
290         --decrypt)
291             COMPREPLY=( $( compgen -W "true false auto nostash" -- "${cur}" ) )
292             return
293             ;;
294     esac
295
296     ! $split &&
297     case "${cur}" in
298         --*)
299             local options="--create-folder --folder= --keep --no-hooks --decrypt= ${_notmuch_shared_options}"
300             compopt -o nospace
301             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
302             return
303             ;;
304         +*)
305             COMPREPLY=( $(compgen -P "+" -W "`notmuch search --output=tags \*`" -- ${cur##+}) )
306             ;;
307         -*)
308             COMPREPLY=( $(compgen -P "-" -W "`notmuch search --output=tags \*`" -- ${cur##-}) )
309             ;;
310     esac
311     # handle tags with colons
312     __ltrim_colon_completions "${cur}"
313 }
314
315 _notmuch_new()
316 {
317     local cur prev words cword split
318     _init_completion -s || return
319
320     $split &&
321     case "${prev}" in
322         --decrypt)
323             COMPREPLY=( $( compgen -W "true false auto nostash" -- "${cur}" ) )
324             return
325             ;;
326     esac
327
328     ! $split &&
329     case "${cur}" in
330         -*)
331             local options="--no-hooks --decrypt= --quiet ${_notmuch_shared_options}"
332             compopt -o nospace
333             COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
334             ;;
335     esac
336 }
337
338 _notmuch_reply()
339 {
340     local cur prev words cword split
341     _init_completion -s || return
342
343     $split &&
344     case "${prev}" in
345         --format)
346             COMPREPLY=( $( compgen -W "default json sexp headers-only" -- "${cur}" ) )
347             return
348             ;;
349         --reply-to)
350             COMPREPLY=( $( compgen -W "all sender" -- "${cur}" ) )
351             return
352             ;;
353         --decrypt)
354             COMPREPLY=( $( compgen -W "true auto false" -- "${cur}" ) )
355             return
356             ;;
357     esac
358
359     ! $split &&
360     case "${cur}" in
361         -*)
362             local options="--format= --format-version= --reply-to= --decrypt= ${_notmuch_shared_options}"
363             compopt -o nospace
364             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
365             ;;
366         *)
367             _notmuch_search_terms
368             ;;
369     esac
370 }
371
372 _notmuch_restore()
373 {
374     local cur prev words cword split
375     _init_completion -s || return
376
377     $split &&
378     case "${prev}" in
379         --format)
380             COMPREPLY=( $( compgen -W "sup batch-tag auto" -- "${cur}" ) )
381             return
382             ;;
383         --input)
384             _filedir
385             return
386             ;;
387     esac
388
389     ! $split &&
390     case "${cur}" in
391         -*)
392             local options="--format= --accumulate --input= ${_notmuch_shared_options}"
393             compopt -o nospace
394             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
395             ;;
396     esac
397 }
398
399 _notmuch_search()
400 {
401     local cur prev words cword split
402     _init_completion -s || return
403
404     $split &&
405     case "${prev}" in
406         --format)
407             COMPREPLY=( $( compgen -W "json sexp text text0" -- "${cur}" ) )
408             return
409             ;;
410         --output)
411             COMPREPLY=( $( compgen -W "summary threads messages files tags" -- "${cur}" ) )
412             return
413             ;;
414         --sort)
415             COMPREPLY=( $( compgen -W "newest-first oldest-first" -- "${cur}" ) )
416             return
417             ;;
418         --exclude)
419             COMPREPLY=( $( compgen -W "true false flag all" -- "${cur}" ) )
420             return
421             ;;
422     esac
423
424     ! $split &&
425     case "${cur}" in
426         -*)
427             local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate= ${_notmuch_shared_options}"
428             compopt -o nospace
429             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
430             ;;
431         *)
432             _notmuch_search_terms
433             ;;
434     esac
435 }
436
437 _notmuch_reindex()
438 {
439     local cur prev words cword split
440     _init_completion -s || return
441
442     $split &&
443     case "${prev}" in
444         --decrypt)
445             COMPREPLY=( $( compgen -W "true false auto nostash" -- "${cur}" ) )
446             return
447             ;;
448     esac
449
450     ! $split &&
451     case "${cur}" in
452         -*)
453             local options="--decrypt= ${_notmuch_shared_options}"
454             compopt -o nospace
455             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
456             ;;
457         *)
458             _notmuch_search_terms
459             ;;
460     esac
461 }
462
463 _notmuch_address()
464 {
465     local cur prev words cword split
466     _init_completion -s || return
467
468     $split &&
469     case "${prev}" in
470         --format)
471             COMPREPLY=( $( compgen -W "json sexp text text0" -- "${cur}" ) )
472             return
473             ;;
474         --output)
475             COMPREPLY=( $( compgen -W "sender recipients count address" -- "${cur}" ) )
476             return
477             ;;
478         --sort)
479             COMPREPLY=( $( compgen -W "newest-first oldest-first" -- "${cur}" ) )
480             return
481             ;;
482         --exclude)
483             COMPREPLY=( $( compgen -W "true false flag all" -- "${cur}" ) )
484             return
485             ;;
486         --deduplicate)
487             COMPREPLY=( $( compgen -W "no mailbox address" -- "${cur}" ) )
488             return
489             ;;
490     esac
491
492     ! $split &&
493     case "${cur}" in
494         -*)
495             local options="--format= --output= --sort= --exclude= --deduplicate= ${_notmuch_shared_options}"
496             compopt -o nospace
497             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
498             ;;
499         *)
500             _notmuch_search_terms
501             ;;
502     esac
503 }
504
505 _notmuch_show()
506 {
507     local cur prev words cword split
508     _init_completion -s || return
509
510     $split &&
511     case "${prev}" in
512         --entire-thread)
513             COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) )
514             return
515             ;;
516         --format)
517             COMPREPLY=( $( compgen -W "text json sexp mbox raw" -- "${cur}" ) )
518             return
519             ;;
520         --exclude|--body)
521             COMPREPLY=( $( compgen -W "true false" -- "${cur}" ) )
522             return
523             ;;
524         --decrypt)
525             COMPREPLY=( $( compgen -W "true auto false stash" -- "${cur}" ) )
526             return
527             ;;
528     esac
529
530     ! $split &&
531     case "${cur}" in
532         -*)
533             local options="--entire-thread= --format= --exclude= --body= --format-version= --part= --verify --decrypt= --include-html ${_notmuch_shared_options}"
534             compopt -o nospace
535             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
536             ;;
537         *)
538             _notmuch_search_terms
539             ;;
540     esac
541 }
542
543 _notmuch_tag()
544 {
545     local cur prev words cword split
546     # handle tags with colons and equal signs
547     _init_completion -s -n := || return
548
549     $split &&
550     case "${prev}" in
551         --input)
552             _filedir
553             return
554             ;;
555     esac
556
557     ! $split &&
558     case "${cur}" in
559         --*)
560             local options="--batch --input= --remove-all ${_notmuch_shared_options}"
561             compopt -o nospace
562             COMPREPLY=( $(compgen -W "$options" -- ${cur}) )
563             return
564             ;;
565         +*)
566             COMPREPLY=( $(compgen -P "+" -W "`notmuch search --output=tags \*`" -- ${cur##+}) )
567             ;;
568         -*)
569             COMPREPLY=( $(compgen -P "-" -W "`notmuch search --output=tags \*`" -- ${cur##-}) )
570             ;;
571         *)
572             _notmuch_search_terms
573             return
574             ;;
575     esac
576     # handle tags with colons
577     __ltrim_colon_completions "${cur}"
578 }
579
580 _notmuch()
581 {
582     local _notmuch_commands="compact config count dump help insert new reply restore reindex search address setup show tag emacs-mua"
583     local arg cur prev words cword split
584
585     # require bash-completion with _init_completion
586     type -t _init_completion >/dev/null 2>&1 || return
587
588     _init_completion || return
589
590     COMPREPLY=()
591
592     # subcommand
593     _get_first_arg
594
595     # complete --help option like the subcommand
596     if [ -z "${arg}" -a "${prev}" = "--help" ]; then
597         arg="help"
598     fi
599
600     if [ -z "${arg}" ]; then
601         # top level completion
602         case "${cur}" in
603             -*)
604                 # XXX: handle ${_notmuch_shared_options} and --config=
605                 local options="--help --version"
606                 COMPREPLY=( $(compgen -W "${options}" -- ${cur}) )
607                 ;;
608             *)
609                 COMPREPLY=( $(compgen -W "${_notmuch_commands}" -- ${cur}) )
610                 ;;
611         esac
612     elif [ "${arg}" = "help" ]; then
613         # handle help command specially due to _notmuch_commands usage
614         local help_topics="$_notmuch_commands hooks search-terms properties"
615         COMPREPLY=( $(compgen -W "${help_topics}" -- ${cur}) )
616     else
617         # complete using _notmuch_subcommand if one exist
618         local completion_func="_notmuch_${arg//-/_}"
619         declare -f $completion_func >/dev/null && $completion_func
620     fi
621 } &&
622 complete -F _notmuch notmuch