about summary refs log tree commit diff
path: root/Completion/Base/_combination
blob: 6315473118a67d893287b3ad16a18d8bc322cc97 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#autoload

# Usage:
#   _combination [-s S] V[:K1:...] Ki1[:Ni1]=Pi1 Ki2[:Ni2]=Pi2 ... Kim[:Nim]=Pim Kj[:Nj] EXPL...
#
#  It is assumed that V is formed as PRE_K1_..._Kn if `:K1:...' is not specified.
#
# Example: telnet
#
#  Assume an user sets the variable `telnet_hosts_ports_users' as:
#
#    telnet_hosts_ports_users=(
#      host0:: host1::user1 host2::user2
#      mail-server:{smtp,pop3}:
#      news-server:nntp:
#      proxy-server:8000:
#    )
#
#  `_telnet completes' hosts as:
#
#    _combination telnet_hosts_ports_users \
#      ${options[-l]:+users=${options[-l]:q}} \
#      hosts "$expl[@]"
#
#  This completes `host1', `host2', `mail-server', `news-server' and
#  `proxy-server' according to the user given with `-l' if it is exists.
#  And if it is failed, `_hosts' is called.
# 
#  `_telnet' completes ports as:
#
#    _combination telnet_hosts_ports_users \
#      ${options[-l]:+users=${options[-l]:q}} \
#      hosts="${line[2]:q}" \
#      ports "$expl[@]"
#
#  This completes `smtp', `pop3', `nntp' and `8000' according to the
#  host argument --- $line[2] and the user option argument if it is
#  exists. And if it is failed, `_ports' is called.
#
#  `_telnet' completes users for an argument of option `-l' as:
#
#    _combination telnet_hosts_ports_users \
#      ${line[2]:+hosts="${line[2]:q}"} \
#      ${line[3]:+ports="${line[3]:q}"} \
#      users "$expl[@]"
#
#  This completes `user1' and `user2' according to the host argument and
#  the port argument if they are exist. And if it is failed, `_users' is
#  called.

local sep var keys pats key num tmp

if [[ "$1" = -s ]]; then
  sep="$2"
  shift 2
else
  sep=:
fi

var=$1
shift

if [[ $var = *:* ]]; then
  keys=( ${(s/:/)var} )
  shift keys
  var="${var%%:*}"
else
  keys=( "${(@s:_:)${var#*_}}" )
fi
pats=( "${(@)keys/*/*}" )

while [[ "$1" = *=* ]]; do
  tmp="${1%%\=*}"
  key="${tmp%:*}"
  num="${${tmp##*:}:-1}"
  pats[$keys[(in:num:)$key]]="${1#*\=}"
  shift
done

key="${1%:*}"
num="${${1##*:}:-1}"
shift

if (( ${(P)+${var}} )); then
  eval "tmp=( \"\${(@M)${var}:#\${(j($sep))~pats}}\" )"
  if (( keys[(in:num:)$key] != 1 )); then
    eval "tmp=( \${tmp#\${(j(${sep}))~\${(@)\${(@)keys[2,(rn:num:)\$key]}/*/*}}$sep} )"
  fi
  tmp=( ${tmp%%$sep*} )

  compadd "$@" - $tmp || { builtin functions _$key >&- && _$key "$@" }
else
  builtin functions _$key >&- && _$key "$@"
fi