nmh-workers
[Top] [All Lists]

completion (was Re: [Nmh-workers] What is MH ?)

2006-01-10 09:10:43
Nathan Bailey wrote:
PS: Another couple of things I'd like to see on the MH wiki would be:
i) How do you do 'To/Cc/Dcc/Bcc' field completion? (i.e. in the same way 
the GUI clients do, or web browsers do for URLs).  Special bonus if your 
solution supports an LDAP directory (i.e. not just aliases in lib/alias :-)

I use a Zsh script named zprompter to replace prompter. Zsh already has
powerful completion capabilities so it handles the job well. Even stuff
like LDAP is straightforward.

I've attached the script but you may need to tweak it for your own
purposes. You'll need a relatively recent version of zsh installed. I
use the script to quote repl replies (using mhshow -part 1) which works
most of the time so you need to remove the message quoting from
replcomps or modify the script. I use 
comp: -editor zprompter
to enable it.

Pressing tab does completion of aliases (depending on the header). Other
keybindings should be configurable in the bindkey settings. In addition
to normal editing operations are the following:
  Ctrl-F   - add a new header field
  Ctrl-J   - attach a file
  Ctrl-K   - LDAP lookup
  Ctrl-X A - expand alias inline

For LDAP, you may need to change ldapsearch's options and create a
.ldaprc to point to the LDAP server. If you've got better ideas for the
search than the current surname based one then let me know.

If you want completion to work for the From header, you'll need to add
aliases for your own addresses.

There are various problems with it and areas for improvement but I find
it useful.

Oliver



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.
#!/bin/zsh

trap 'exit 1' INT
setopt autolist extendedglob completeinword

# provide function for getent if it doesn't exist
which getent >/dev/null || getent() {
  cat /etc/passwd
}

_complete() {
  [[ "$compstate[insert]" = tab* ]] &&
      compstate[insert]="${compstate[insert]//tab /}"

  case $hdr in
    From|Reply-To) _comp_from;;
    Filename) _comp_files;;
    Header) _comp_headers;;
    *) _comp_aliases;;
  esac
}

_comp_from() {
  compadd -X '%Balias%b' -S '' \
      ${${(f)"$(ali -user $(mhparam Alternate-Mailboxes))"}:#*(_at_)*}
}

_comp_aliases() {
  local nick list suf

  compset -P '*,'
  compset -S ',*' || suf=( -qS, )
  nick=( ${(f)"$(ali)"} )
  zformat -a list ' --' "${nick[(_at_)]}"
  nick=( ${nick%%:*} )
  compadd -Q -X '%Balias%b' -d list "$suf[(_at_)]" -a nick
}

_comp_lookup() {
  local -a res all suf
  local dn cn
  local -l mail

  compset -P '*,'
  compset -S ',*' || suf=( -qS, )
  res=( ${(f)"$(ldapsearch -x -LLL "(sn=$PREFIX*$SUFFIX)" cn mail)"} )
  for dn cn mail in "${res[(_at_)]}"; do
    all+=( "\"${cn#*: }\" <${mail#*: }>" )
  done
  compadd -X '%Bmatching names%b' $suf -i "$IPREFIX" -I "$ISUFFIX" -UQ -a all
}

_comp_files() {
  local glob suf='-S/'
  compset -S '/*' && suf=( -S '' )

  if [[ $PREFIX = \~[^/]# ]]; then
    compset -P \~
    compadd -X '%Buser%b' $suf ${${(f)"$(getent passwd)"}%%:*}
  else
    compset -P '*/'
    [[ $PREFIX = .* ]] && glob=D
    compadd -X '%Bfile%b' -f -W ${~IPREFIX:-$PWD/} ${~IPREFIX:-./}*(${glob}N:t)
  fi
}

_comp_headers() {
  compadd -X '%Badditional header%b' -M 'M:{A-Za-z}={a-zA-Z}' -S '' \
      Bcc cc Dcc Mail-Followup-To Reply-To
}

_expand_alias() {
  local suf

  compset -P '*,'
  compset -S ',*' || suf=( -qS, )
  [[ -n $PREFIX$SUFFIX ]] && compadd $suf -i "$IPREFIX" -I "$ISUFFIX" -UQ \
      "$(ali $PREFIX$SUFFIX)"
}

attachment() {
  local hdr=Filename
  read-from-minibuffer 'Filename: '
  attachments+=( ${(Q)${(z)REPLY}} )
}

new-header() {
  local hdr=Header
  read-from-minibuffer 'Header: '
  hdr="$REPLY"
  read-from-minibuffer "$hdr: "
  value[$hdr]=$REPLY
}

zmodload zsh/complist
LISTPROMPT=''
MENUSELECT=''
WORDCHARS="$WORDCHARS @."
zle -C complete-word complete-word _complete
zle -C complete-lookup menu-complete _comp_lookup
zle -C expand-alias menu-complete _expand_alias
zle -N attachment
zle -N new-header
autoload -U read-from-minibuffer

bindkey -v
bindkey '^A'      beginning-of-line
bindkey '^E'      end-of-line
bindkey '^F'      new-header
bindkey '^I'      complete-word
bindkey '^J'      attachment
bindkey '^K'      complete-lookup
bindkey '^Z'      undo
bindkey '^Xa'     expand-alias
bindkey '^[[P'    delete-char
bindkey '\e[3~'   delete-char
bindkey '^[[139q' overwrite-mode
bindkey '^[[2~'   overwrite-mode
bindkey '^[^[[D'  backward-kill-word
bindkey '^[[160q' backward-kill-word
bindkey '^[[3D'   backward-kill-word
bindkey '^[^[[C'  kill-word
bindkey '^[[3C'   kill-word
bindkey '^[[169q' kill-word
bindkey '^[OD'    backward-word
bindkey '^[[159q' backward-word
bindkey '^[[1;5D' backward-word
bindkey '^[OC'    forward-word
bindkey '^[[168q' forward-word
bindkey '^[[1;5C' forward-word

typeset -A value from

edit=( Resent-To To cc From Subject )
aliexp=( Resent-To Reply-To Bcc Dcc To cc From )
headers=()
attachments=()

exec 4<$1
while IFS= read -r line && [[ $line != "--------" ]]; do
  if [[ "$line" = [[:blank:]]* ]]; then
    value[$hdr]+="${line##[[:blank:]]#}"
  else
    hdr=${line%%:*}
    value[$hdr]="${${line#*:}##[[:blank:]]#}"
    headers+=( $hdr )
  fi
done <&4
quoting="${(f)"$(<&4)"}"

# if we have a cc header but no To, swap it
if (( ${headers[(I)cc]} && ! ${headers[(I)To]} )); then
  headers[(I)cc]=To
  value[To]="$value[cc]"
  unset 'value[cc]'
fi

for hdr in ${(M)headers:#(${(j.|.)~edit})}; do
  vared -c -p "$hdr: " "value[$hdr]"
done

# expand aliases in relevant headers
for exp in ${(Mk)value:#(${(j.|.)~aliexp})}; do
  new=()
  for r in ${(s:,:)value[$exp]}; do
    if [[ $r = *[\"@\\]* ]]; then
      new+=( "${r##[[:blank:]]#}" )
    else
      new+=( "$(ali ${r##[[:blank:]]#})" )
    fi
  done
  value[$exp]="${(j:, :)new}"
done

exec 3>$1

for h in ${(k)value}; do
  print -r "$h: $value[$h]" >&3
done

# exit now for the dist command
[[ $mhdist = 1 ]] && exit

echo "--------" >&3
print -r "$quoting" >&3
if [[ -n $editalt ]]; then
  mhshow -part 1 -form mhl.null -file $editalt | sed -e '1 d' -e 's/^/> /' >&3
fi

# get possible mime types
types=( ${${(f)"$(cat /etc/mime.types(N) ~/.mime.types(N))"}:#\#*} )

for file in $attachments; do
  type=${${(M)types:#*[[:blank:]]${${file:e}:- 
}((#e)|[[:blank:]])*}%%[[:blank:]]*}
  [[ -z $type && $(file $~file) = *\ text ]] && type="text/plain"
  print "#${type:-application/octet-stream}; name="'"'${file:t}'"' $~file >&3
done

NEXINIT='set wrapmargin=8' nvi "+$(($#value + 2))" $1

_______________________________________________
Nmh-workers mailing list
Nmh-workers(_at_)nongnu(_dot_)org
http://lists.nongnu.org/mailman/listinfo/nmh-workers
<Prev in Thread] Current Thread [Next in Thread>