Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: completing email addresses
- X-seq: zsh-workers 18121
- From: Oliver Kiddle <okiddle@xxxxxxxxxxx>
- To: Zsh workers <zsh-workers@xxxxxxxxxx>
- Subject: PATCH: completing email addresses
- Date: Thu, 16 Jan 2003 15:13:55 +0100
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
- Sender: kiddleo@xxxxxxxxxx
The patch contains an updated version of the function I posted last
month along with the relevant changes to other completion functions to
call it.
The main change is that with a strip-comments style set (or -c option),
it will strip addresses down to just user@host form. The method I used
to do this seems to work but perhaps more by luck than judgement. If
you can simplify it, get it to handle all address forms, get it to
strip comments embedded in the stuff $~__addrspec matches or get it to
also extract the comments for use in descriptions then please go ahead.
Thanks again to Bart for his rfc822 regex grammar.
strip-comments is looked up within the _next_labels loop so you can
apply it only for particular tag labels. To do this, I've had to make
use of $curtag. I hope that's okay (Sven?). There's quite a lot of
scope for cunning use of tag labels and _next_tags with this function.
It may take a bit of fiddling if you want to use the ldap plugin. It
needs the filter style to be set to do anything at all and you probably
need a command style and/or .ldaprc before it can connect to your
server. I only have access to one ldap server and it would be useful to
know if the function is sufficiently adaptable. In case it helps, I use:
# match against surnames and login
#zstyle ':completion:*:email-ldap' filter sn rdn
# getting the whole list results in an 'Administrative limit reached' error
# so skip ldap lookup unless at least two characters have been typed
zstyle -e ':completion:*:email-ldap' filter '(( $#PREFIX+$#SUFFIX > 2 )) && reply=( sn rdn )'
# -x option needed to turn of SASL authentication
zstyle ':completion:*:email-ldap' command 'ldapsearch -x -LLL $filter cn mail'
And, my .ldaprc contains a `HOST host:port' line
Any comments, ideas or extra plugins would be welcome.
Oliver
Index: Completion/Unix/Command/_elm
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Command/_elm,v
retrieving revision 1.1
diff -u -r1.1 _elm
--- Completion/Unix/Command/_elm 13 Apr 2001 18:42:15 -0000 1.1
+++ Completion/Unix/Command/_elm 16 Jan 2003 13:59:59 -0000
@@ -1,9 +1,7 @@
#compdef elm
-local curcontext="$curcontext" state line expl suf
-
-_arguments -C -s \
- '::recipient:->userhost' \
+_arguments -s \
+ '::recipient:_email_addresses' \
'-a[use the arrow pointer regardless]' \
'-A+[attach file]:file attachment:_files' \
'-c[check the given aliases only]:*:alias' \
@@ -17,17 +15,4 @@
'-V[enable sendmail voyeur mode]' \
'-v[display elm version]' \
'-w[write .elm/elmrc]' \
- '-z[start only if new messages]' && return 0
-
-if [[ "$state" = userhost ]]; then
- if compset -P '*@'; then
- _description hosts expl 'remote host name'
- _hosts "$expl[@]" && return 0
- else
- compset -S '@*' || suf='@'
- _description users expl 'login name'
- _users "$expl[@]" -q -S "$suf" && return 0
- fi
-fi
-
-return 1
+ '-z[start only if new messages]'
Index: Completion/Unix/Command/_mail
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Command/_mail,v
retrieving revision 1.2
diff -u -r1.2 _mail
--- Completion/Unix/Command/_mail 19 Aug 2002 14:52:45 -0000 1.2
+++ Completion/Unix/Command/_mail 16 Jan 2003 13:59:59 -0000
@@ -1,24 +1,9 @@
-#compdef mail mailx Mail mush zmail nail
+#compdef mail mailx=mail Mail=mail mush zmail nail=mail
-local curcontext="$curcontext" state line expl suf
-
-_arguments -C -s \
+_arguments -s \
'(-f -u)*-b[specify a BCC recipient]:BCC recipient:->userhost' \
'(-f -u)*-c[specify a CC recipient]:CC recipient:->userhost' \
'(-b -c -u -s *)-f+[specify mail folder]:mailbox:_mailboxes' \
'(-f -u)-s+[specify a subject]:subject:' \
"(-b -c -f -s *)-u+[read specified user's mail]:user:_users" \
- '(-f -u)*:recipient:->userhost' && return 0
-
-if [[ "$state" = userhost ]]; then
- if compset -P '*@'; then
- _description hosts expl 'remote host name'
- _hosts "$expl[@]" && return 0
- else
- compset -S '@*' || suf='@'
- _description users expl 'login name'
- _users "$expl[@]" -q -S "$suf" && return 0
- fi
-fi
-
-return 1
+ "(-f -u)*:recipient:_email_addresses -n $service"
Index: Completion/Unix/Command/_mutt
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Command/_mutt,v
retrieving revision 1.2
diff -u -r1.2 _mutt
--- Completion/Unix/Command/_mutt 13 Apr 2001 18:42:15 -0000 1.2
+++ Completion/Unix/Command/_mutt 16 Jan 2003 13:59:59 -0000
@@ -1,13 +1,10 @@
#compdef mutt
-local curcontext="$curcontext" state line expl suf
-typeset -A opt_args
-
-_arguments -C -s \
- '::recipient:->userhost' \
+_arguments -s \
+ '::recipient:_email_addresses -n mutt' \
'*-a[attach file using MIME]:file attachment:_files' \
- '*-b[specify a BCC recipient]:BCC recipient:->userhost' \
- '*-c[specify a CC recipient]:CC recipient:->userhost' \
+ '*-b[specify a BCC recipient]:BCC recipient:_email_addresses -n mutt' \
+ '*-c[specify a CC recipient]:CC recipient:_email_addresses -n mutt' \
'-e+[specify a post-init configuration command]:post-init configuration:' \
'-f+[specify mailbox to load]:mailbox: _mailboxes' \
'-F+[specify an init file]:init file:_files' \
@@ -23,17 +20,4 @@
'-x[emulate mailx compose]' \
'-y[start listing mailboxes]' \
'-z[start only if new messages]' \
- '-Z[open first mailbox with new mail]' && return 0
-
-if [[ "$state" = userhost ]]; then
- if compset -P '*@'; then
- _description hosts expl 'remote host name'
- _hosts "$expl[@]" -q -S, && return 0
- else
- compset -S '@*' || suf='@'
- _description users expl 'login name'
- _users "$expl[@]" -q -S "$suf" && return 0
- fi
-fi
-
-return 1
+ '-Z[open first mailbox with new mail]'
Index: Completion/Unix/Command/_pine
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Command/_pine,v
retrieving revision 1.6
diff -u -r1.6 _pine
--- Completion/Unix/Command/_pine 25 Feb 2002 09:09:36 -0000 1.6
+++ Completion/Unix/Command/_pine 16 Jan 2003 13:59:59 -0000
@@ -1,9 +1,8 @@
#compdef pine pinef
-local curcontext="$curcontext" state line expl suf
local optfile getopts='pine -conf' sortorder lusortorder opts send idx
-if [[ -n $+_cache_pine_options ]]; then
+if (( $#_cache_pine_options )); then
for optfile in ~/.pinerc /etc/pine.conf; do
if [[ -f $optfile ]]; then
getopts="cat $optfile"
@@ -20,7 +19,7 @@
idx=( -f -c -i -I -n -o -sort ) # options used when viewing messages
send=( -attach -attachlist -attach_and_delete -url ) # options when sending
-_arguments -C -s \
+_arguments -s \
"($opts $idx $send -bail -d -k -z -r -p -P *)-h[display help]" \
"($opts $idx $send -bail -d -k -z -r -p -P *)-v[display version information]" \
"($opts $idx $send -r *)-F+[specify file to open and page through]:file:_files" \
@@ -32,7 +31,7 @@
"($opts $idx -url)-attach[go directly into composer with given file]:file:_files" \
"($opts $idx -url)-attachlist[go to composer with given files]:file:_files" \
"($opts $idx -url)-attach_and_delete[go to composer, attach file, delete when finished]:file:_files" \
- "($opts $idx $send)-url[open the given URL]:url:->url" \
+ "($opts $idx $send)-url[open the given URL]:url:_email_addresses -c -P mailto\:" \
"($opts $send)-f+[specify mailbox to load]:mailbox: _mailboxes" \
"($opts $send)-c+[specify context to apply to -f arg]: :_guard '[0-9]#' number" \
"($opts $send)-sort[specify sort order of folder]:sort order:(${(j: :)sortorder})" \
@@ -48,26 +47,5 @@
\(${(j. .)opts:#-F}')-P+[use alternate pine.conf file]:alternate pine.conf:_files' \
\(${(j. .)opts:#-F}')-x[use configuration exceptions file]:configuration exceptions file:_files' \
\(${(j. .)opts:#-F}")-bail[exit if pinerc file doesn't already exist]" \
- '*::recipient:->userhost' \
- ${^_cache_pine_options}':option value' && return 0
-
-if [[ "$state" = url ]]; then
- if compset -P 'mailto:'; then
- state=userhost
- else
- compadd -S: mailto && return 0
- fi
-fi
-
-if [[ "$state" = userhost ]]; then
- if compset -P '*@'; then
- _description hosts expl 'remote host name'
- _hosts "$expl[@]" && return 0
- else
- compset -S '@*' || suf='@'
- _description users expl 'login name'
- _users "$expl[@]" -q -S "$suf" && return 0
- fi
-fi
-
-return 1
+ '*::recipient:_email_addresses -n pine' \
+ ${^_cache_pine_options}':option value'
Index: Completion/Unix/Type/_email_addresses
===================================================================
RCS file: Completion/Unix/Type/_email_addresses
diff -N Completion/Unix/Type/_email_addresses
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Completion/Unix/Type/_email_addresses 16 Jan 2003 13:59:59 -0000
@@ -0,0 +1,172 @@
+#autoload
+# options:
+#
+# -n plugin - can complete nicknames from specified plugin
+# -s sep - complete a list of addresses separated by specified character
+# -c - e-mail address must be of form user@host (no comments or aliases)
+#
+# Plugins are written as separate functions with names starting `_email-'.
+# They should either do their own completion or return the addresses in the
+# ali array in the form 'alias:address' and return 300. The -c option is
+# passed on to plugins (and -n could be if needed ever). New plugins will be
+# picked up and run automatically.
+
+# plugins
+(( $+functions[_email-mail] )) ||
+_email-mail() {
+ ali=( ${${${(M)${(f)"$(<$files[$plugin])"}:#alias*}##alias[[:blank:]]##}/[[:blank:]]##/:} )
+ return 300
+}
+(( $+functions[_email-mutt] )) || _email-mutt() { _email-mail }
+(( $+functions[_email-mush] )) || _email-mush() { _email-mail }
+
+(( $+functions[_email-MH] )) ||
+_email-MH() {
+ ali=( ${${(f)"$(_call_program aliases ali)"}/: /:} )
+ return 300
+}
+
+(( $+functions[_email-pine] )) ||
+_email-pine() {
+ ali=( ${${${${${(f)"$(<~/.addressbook)"}:#*DELETED*}:#\ *}/ [^ ]# /:}%% *} )
+ return 300
+}
+
+(( $+functions[_email-ldap] )) ||
+_email-ldap() {
+ local -a expl ali res filter
+ local -A opts
+ local dn cn mail
+
+ zparseopts -D -E -A opts c
+
+ zstyle -a ":completion:${curcontext}:$curtag" filter filter
+ (( $#filter )) || return
+
+ filter=( "("${filter}"=${PREFIX}*${SUFFIX})" )
+ (( $#filter > 1 )) && filter="(|"${(j..)filter}")"
+ res=( ${(f)"$(_call_program $curtag ldapsearch -LLL \$filter cn mail 2>/dev/null)"} )
+ (( $#res > 1 )) || return
+
+ for dn cn mail in "${res[@]}"; do
+ if (( $+opts[-c] )); then
+ ali+=( "${mail#*: }" )
+ else
+ cn="${cn#*: }"
+ [[ $cn = *$~__specials* ]] && cn="\"$cn\""
+ ali+=( "$cn <${mail#*: }>" )
+ fi
+ done
+ compstate[insert]=menu
+ _wanted email-ldap expl 'matching names' \
+ compadd -U -i "$IPREFIX" -I "$ISUFFIX" "$@" -a - ali
+}
+
+(( $+functions[_email-local] )) ||
+_email-local() {
+ local suf opts
+ zparseopts -D -E -A opts c S:=suf
+
+ if compset -P '*@'; then
+ _hosts "$@" "$suf[@]"
+ else
+ suf=()
+ compset -S '@*' || suf=( -qS @ )
+ _users "$suf[@]" "$@"
+ fi
+}
+
+_email_addresses() {
+ local -a plugins ali list args
+ local -A opts files
+ local plugin rcfile expl ret fret
+
+ local __specialx='][()<>@,;:\\".'
+ local __spacex=" " # Space, tab
+ local __specials="[$__specialx]"
+ local __atom="[^$__specialx$__spacex]##"
+ local __space="[$__spacex]#" # Really, space or comment
+ local __qtext='[^"\\]'
+ local __qpair='\\?'
+ local __beginq='"'
+ local __endq='(|[^\\])"'
+ local __dot="$__space.$__space"
+
+ local __domainref="$__atom"
+ local __domainlit='\[([^]]|'"$__qpair"')#(|[^\\])\]'
+ local __quotedstring="$__beginq($__qtext|$__qpair)#$__endq"
+ local __word="($__atom|$__quotedstring)"
+ local __phrase="($__space$__word$__space)#" # Strictly, should use `##'
+ local __localpart="$__word($__dot$__word)#"
+
+ local __subdomain="($__domainref|$__domainlit)"
+ local __domain="$__subdomain($__dot$__subdomain)#"
+ local __addrspec="$__localpart$__space@$__space$__domain"
+
+ local __addresses="($__qtext|$__quotedstring)##"
+
+ zparseopts -D -E -A opts n: s: c
+ set -- "$@" -M 'r:|[.@]=* r:|=* m:{a-zA-Z}={A-Za-z}'
+
+ if [[ -n $opts[-s] ]]; then
+ # remove up to the last unquoted separator
+ if [[ ${(Q)PREFIX} = (#b)($~__addresses$opts[-s])* ]]; then
+ IFS="$opts[-s]" eval 'compset -P $(( ${#${=${:-x${match[1]}x}}} - 1 )) "*${opts[-s]}"'
+ fi
+
+ # for the suffix, I'm too lazy to work out how to preserve quoted separators
+ compset -S "$opts[-s]*" || set -- -q -S "$opts[-s]" "$@"
+ fi
+
+ # get list of all plugins except any with missing config files
+ files=( mutt ~/.muttrc mush ~/.mushrc mail ${MAILRC:-~/.mailrc} pine ~/.addressbook )
+ plugins=(
+ ${${(k)functions[(I)_email-*]#*-}:#(${(kj.|.)~files})}
+ $files(Ne:'REPLY=( ${(k)files[(r)$REPLY]} ):')
+ )
+
+ ret=1
+ _tags email-$plugins
+ while _tags; do
+ for plugin in $plugins; do
+ if _requested email-$plugin; then
+ while _next_label email-$plugin expl 'email address'; do
+
+ args=()
+ if (( $+opts[-c] )) || zstyle -t \
+ ":completion:${curcontext}:$curtag" strip-comments
+ then
+ args=( '-c' )
+ fi
+
+ if ! _call_function fret _email-$plugin "$@" $args; then
+ _message "$plugin: plugin not found"
+ continue
+ fi
+ ret=$(( ret && fret ))
+
+ if (( fret == 300 )); then
+ if (( ! $+opts[-c] )) && [[ $opts[-n] = $plugin ]]; then
+ zformat -a list ' -- ' "${ali[@]}"
+ _wanted mail-aliases expl 'alias' compadd "$@" \
+ -d list - ${ali%%:*} && ret=0
+ else
+ if (( $#args )); then
+ ali=( ${(SM)${ali#*:}##$~__addrspec} )
+ else
+ # remove lines not containing `@' as they probably aren't addresses
+ ali=( "${(@)${(M@)ali:#*@*}#*:}" )
+ fi
+ compadd -a "$@" "$expl[@]" ali && ret=0
+ fi
+ fi
+ done
+ fi
+ done
+ (( ret )) || return 0
+ done
+
+ return 1
+}
+
+_email_addresses "$@"
Index: Completion/X/Command/_mozilla
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/X/Command/_mozilla,v
retrieving revision 1.1
diff -u -r1.1 _mozilla
--- Completion/X/Command/_mozilla 11 Dec 2001 20:09:55 -0000 1.1
+++ Completion/X/Command/_mozilla 16 Jan 2003 13:59:59 -0000
@@ -58,13 +58,7 @@
fi
;;
mailto*)
- compset -P "*,"
- if compset -P '*@'; then
- _wanted hosts expl 'remote host name' _hosts -q -S, && ret=0
- else
- compset -S "@*" || suf="@"
- _wanted users expl 'login name' _users -q -S "$suf" && ret=0
- fi
+ _email_addresses -s, -c && ret=0
;;
*)
compset -S '(|\\)\(*' || suf="${${QIPREFIX:+(}:-\(}"
@@ -83,13 +77,15 @@
license logo memory-cache mozilla plugins && ret=0
elif compset -P news: ; then
_newsgroups "$@" && ret=0
+ elif compset -P mailto: ; then
+ _email_addresses -c && ret=0
else
_tags prefixes
while _tags; do
while _next_label prefixes expl 'URL prefix' "$@"; do
_urls "$expl[@]" && ret=0
compset -S '[^:]*'
- compadd -S '' "$expl[@]" about: news: mocha: javascript: && ret=0
+ compadd -S '' "$expl[@]" about: news: mailto: mocha: javascript: && ret=0
done
(( ret )) || return 0
done
Index: Completion/X/Command/_netscape
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/X/Command/_netscape,v
retrieving revision 1.4
diff -u -r1.4 _netscape
--- Completion/X/Command/_netscape 7 Jan 2002 14:39:44 -0000 1.4
+++ Completion/X/Command/_netscape 16 Jan 2003 13:59:59 -0000
@@ -48,13 +48,7 @@
fi
;;
mailto*)
- compset -P "*,"
- if compset -P '*@'; then
- _wanted hosts expl 'remote host name' _hosts -q -S, && ret=0
- else
- compset -S "@*" || suf="@"
- _wanted users expl 'login name' _users -q -S "$suf" && ret=0
- fi
+ _email_addresses -s, -c && ret=0
;;
*)
compset -S '(|\\)\(*' || suf="${${QIPREFIX:+(}:-\(}"
@@ -77,13 +71,15 @@
image-cache license logo memory-cache mozilla plugins && ret=0
elif compset -P news: ; then
_newsgroups "$@" && ret=0
+ elif compset -P mailto: ; then
+ _email_addresses -c && ret=0
else
_tags prefixes
while _tags; do
while _next_label prefixes expl 'URL prefix' "$@"; do
_urls "$expl[@]" && ret=0
compset -S '[^:]*'
- compadd -S '' "$expl[@]" about: news: mocha: javascript: && ret=0
+ compadd -S '' "$expl[@]" about: news: mailto: mocha: javascript: && ret=0
done
(( ret )) || return 0
done
Index: Completion/Zsh/Command/_zstyle
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Zsh/Command/_zstyle,v
retrieving revision 1.12
diff -u -r1.12 _zstyle
--- Completion/Zsh/Command/_zstyle 26 Jun 2002 11:07:46 -0000 1.12
+++ Completion/Zsh/Command/_zstyle 16 Jan 2003 13:59:59 -0000
@@ -48,6 +48,7 @@
fake-parameters c:fake-params
file-patterns c:filepat
file-sort c:fsort
+ filter c:
force-list c:
format c:
glob c:bool
@@ -109,6 +110,7 @@
squeeze-slashes c:bool
stop c:stop
stop-keys c:
+ strip-comments c:bool
subst-globs-only c:bool
substitute c:bool
suffix c:bool
@@ -143,6 +145,7 @@
prefixes printers processes processes-names ps regex sequences
sessions signals strings styles tags targets timezones types urls
users values variant visuals warnings widgets windows zsh-options
+ email-address ${(k)functions[(I)_email-*]#_}
)
_arguments -C \
@@ -294,7 +297,7 @@
if compset -P '*:*:'; then
_message -e descriptions description
elif compset -P '*:'; then
- _message -e aliases 'tag alias'
+ _message -e labels 'tag label'
else
suf=()
compset -S ':*' || suf=( -qS: )
Index: Completion/Debian/Command/_bts
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Debian/Command/_bts,v
retrieving revision 1.2
diff -u -r1.2 _bts
--- Completion/Debian/Command/_bts 24 Jul 2002 15:47:57 -0000 1.2
+++ Completion/Debian/Command/_bts 16 Jan 2003 13:59:59 -0000
@@ -13,7 +13,7 @@
show|close|unmerge|notforwarded)
if [[ CURRENT -eq 2 ]];
then
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
else
_wanted sep expl 'separator' compadd -S ' ' , .
fi
@@ -29,7 +29,7 @@
reopen)
if [[ CURRENT -eq 2 ]];
then
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
elif [[ CURRENT -eq 3 ]];
then
_wanted submitter expl 'new submitter' compadd $DEBEMAIL
@@ -40,10 +40,10 @@
retitle)
if [[ CURRENT -eq 2 ]];
then
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
elif [[ CURRENT -eq 3 ]];
then
- _wanted submitter expl 'new title' compadd
+ _message -e submitter 'new title'
else
_wanted sep expl 'separator' compadd -S ' ' , .
fi
@@ -51,7 +51,7 @@
reassign)
if [[ CURRENT -eq 2 ]];
then
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
elif [[ CURRENT -eq 3 ]];
then
_wanted submitter expl 'new package' _deb_packages avail
@@ -60,7 +60,7 @@
fi
;;
merge)
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
if [[ CURRENT -gt 2 ]];
then
_wanted sep expl 'separator' compadd -S ' ' , .
@@ -69,7 +69,7 @@
tag)
if [[ CURRENT -eq 2 ]];
then
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
elif [[ CURRENT -eq 3 ]];
then
_wanted operator expl 'operator' compadd - '+' '-' '='
@@ -90,7 +90,7 @@
severity)
if [[ CURRENT -eq 2 ]];
then
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
elif [[ CURRENT -eq 3 ]];
then
_wanted severity expl 'severity' \
@@ -102,10 +102,10 @@
forwarded)
if [[ CURRENT -eq 2 ]];
then
- _wanted bugnum expl 'bug number' compadd
+ _message -e bugnum 'bug number'
elif [[ CURRENT -eq 3 ]];
then
- _wanted upstream expl 'upstream email' compadd
+ _wanted upstream expl 'upstream email' _email_addresses -c
else
_wanted sep expl 'separator' compadd -S ' ' , .
fi
This e-mail and any attachment is for authorised use by the intended recipient(s) only. It may contain proprietary material, confidential information and/or be subject to legal privilege. It should not be copied, disclosed to, retained or used by, any other party. If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender. Thank you.
Messages sorted by:
Reverse Date,
Date,
Thread,
Author