Commit 8bba7ab7075aa03bf2714d6ea349403c6b8c45d4

Authored by Shrikant Sharat
1 parent 973558eee2

Use the new argument parsing function in -bundle.

Showing 1 changed file with 4 additions and 31 deletions Inline Diff

1 #!/bin/zsh 1 #!/bin/zsh
2 2
3 # Each line in this string has the following entries separated by a space 3 # Each line in this string has the following entries separated by a space
4 # character. 4 # character.
5 # <repo-url>, <plugin-location>, <bundle-type>, <has-local-clone> 5 # <repo-url>, <plugin-location>, <bundle-type>, <has-local-clone>
6 # FIXME: Is not kept local by zsh! 6 # FIXME: Is not kept local by zsh!
7 local _ANTIGEN_BUNDLE_RECORD="" 7 local _ANTIGEN_BUNDLE_RECORD=""
8 8
9 # Syntaxes 9 # Syntaxes
10 # antigen-bundle <url> [<loc>=/] 10 # antigen-bundle <url> [<loc>=/]
11 # Keyword only arguments: 11 # Keyword only arguments:
12 # branch - The branch of the repo to use for this bundle. 12 # branch - The branch of the repo to use for this bundle.
13 antigen-bundle () { 13 antigen-bundle () {
14 14
15 # Bundle spec arguments' default values. 15 # Bundle spec arguments' default values.
16 local url="$ANTIGEN_DEFAULT_REPO_URL" 16 local url="$ANTIGEN_DEFAULT_REPO_URL"
17 local loc=/ 17 local loc=/
18 local branch= 18 local branch=
19 local no_local_clone=false 19 local no_local_clone=false
20 local btype=plugin 20 local btype=plugin
21 21
22 # Set spec values based on the positional arguments. 22 # Parse the given arguments. (Will overwrite the above values).
23 local position_args 23 eval "$(-antigen-parse-args \
24 position_args=(url loc) 24 'url?,loc?;branch:?,no-local-clone?,btype:?' \
25 local i=1 25 "$@")"
26 while ! [[ -z $1 || $1 == --* ]]; do
27 local arg_name="${position_args[$i]}"
28 local arg_value="$1"
29 eval "local $arg_name='$arg_value'"
30 shift
31 i=$(($i + 1))
32 done
33
34 # Set spec values from keyword arguments, if any. The remaining arguments
35 # are all assumed to be keyword arguments.
36 while [[ $1 == --* ]]; do
37 # Remove the `--` at the start.
38 local arg="${1#--}"
39
40 if [[ $arg != *=* ]]; then
41 arg="$arg=true"
42 fi
43
44 # Get the name of the arg and replace the `-`'s to `_`'s.
45 local arg_name="${${arg%\=*}//-/_}"
46
47 # Get the value of the arg.
48 local arg_value="${arg#*\=}"
49
50 eval "local $arg_name='$arg_value'"
51 shift
52 done
53 26
54 # Check if url is just the plugin name. Super short syntax. 27 # Check if url is just the plugin name. Super short syntax.
55 if [[ "$url" != */* ]]; then 28 if [[ "$url" != */* ]]; then
56 loc="plugins/$url" 29 loc="plugins/$url"
57 url="$ANTIGEN_DEFAULT_REPO_URL" 30 url="$ANTIGEN_DEFAULT_REPO_URL"
58 fi 31 fi
59 32
60 # Resolve the url. 33 # Resolve the url.
61 url="$(-antigen-resolve-bundle-url "$url")" 34 url="$(-antigen-resolve-bundle-url "$url")"
62 35
63 # Add the branch information to the url. 36 # Add the branch information to the url.
64 if [[ ! -z $branch ]]; then 37 if [[ ! -z $branch ]]; then
65 url="$url|$branch" 38 url="$url|$branch"
66 fi 39 fi
67 40
68 # The `make_local_clone` variable better represents whether there should be 41 # The `make_local_clone` variable better represents whether there should be
69 # a local clone made. For cloning to be avoided, firstly, the `$url` should 42 # a local clone made. For cloning to be avoided, firstly, the `$url` should
70 # be an absolute local path and `$branch` should be empty. In addition to 43 # be an absolute local path and `$branch` should be empty. In addition to
71 # these two conditions, either the `--no-local-clone` option should be 44 # these two conditions, either the `--no-local-clone` option should be
72 # given, or `$url` should not a git repo. 45 # given, or `$url` should not a git repo.
73 local make_local_clone=true 46 local make_local_clone=true
74 if [[ $url == /* && -z $branch && 47 if [[ $url == /* && -z $branch &&
75 ( $no_local_clone == true || ! -d $url/.git ) ]]; then 48 ( $no_local_clone == true || ! -d $url/.git ) ]]; then
76 make_local_clone=false 49 make_local_clone=false
77 fi 50 fi
78 51
79 # Add it to the record. 52 # Add it to the record.
80 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD\n$url $loc $btype" 53 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD\n$url $loc $btype"
81 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD $make_local_clone" 54 _ANTIGEN_BUNDLE_RECORD="$_ANTIGEN_BUNDLE_RECORD $make_local_clone"
82 55
83 # Ensure a clone exists for this repo, if needed. 56 # Ensure a clone exists for this repo, if needed.
84 if $make_local_clone; then 57 if $make_local_clone; then
85 -antigen-ensure-repo "$url" 58 -antigen-ensure-repo "$url"
86 fi 59 fi
87 60
88 # Load the plugin. 61 # Load the plugin.
89 -antigen-load "$url" "$loc" "$btype" "$make_local_clone" 62 -antigen-load "$url" "$loc" "$btype" "$make_local_clone"
90 63
91 } 64 }
92 65
93 -antigen-resolve-bundle-url () { 66 -antigen-resolve-bundle-url () {
94 # Given an acceptable short/full form of a bundle's repo url, this function 67 # Given an acceptable short/full form of a bundle's repo url, this function
95 # echoes the full form of the repo's clone url. 68 # echoes the full form of the repo's clone url.
96 69
97 local url="$1" 70 local url="$1"
98 71
99 # Expand short github url syntax: `username/reponame`. 72 # Expand short github url syntax: `username/reponame`.
100 if [[ $url != git://* && 73 if [[ $url != git://* &&
101 $url != https://* && 74 $url != https://* &&
102 $url != /* && 75 $url != /* &&
103 $url != git@github.com:*/* 76 $url != git@github.com:*/*
104 ]]; then 77 ]]; then
105 url="https://github.com/${url%.git}.git" 78 url="https://github.com/${url%.git}.git"
106 fi 79 fi
107 80
108 echo "$url" 81 echo "$url"
109 } 82 }
110 83
111 antigen-bundles () { 84 antigen-bundles () {
112 # Bulk add many bundles at one go. Empty lines and lines starting with a `#` 85 # Bulk add many bundles at one go. Empty lines and lines starting with a `#`
113 # are ignored. Everything else is given to `antigen-bundle` as is, no 86 # are ignored. Everything else is given to `antigen-bundle` as is, no
114 # quoting rules applied. 87 # quoting rules applied.
115 88
116 local line 89 local line
117 90
118 grep -v '^\s*$\|^#' | while read line; do 91 grep -v '^\s*$\|^#' | while read line; do
119 # Using `eval` so that we can use the shell-style quoting in each line 92 # Using `eval` so that we can use the shell-style quoting in each line
120 # piped to `antigen-bundles`. 93 # piped to `antigen-bundles`.
121 eval "antigen-bundle $line" 94 eval "antigen-bundle $line"
122 done 95 done
123 } 96 }
124 97
125 antigen-update () { 98 antigen-update () {
126 # Update your bundles, i.e., `git pull` in all the plugin repos. 99 # Update your bundles, i.e., `git pull` in all the plugin repos.
127 -antigen-echo-record | 100 -antigen-echo-record |
128 awk '{print $1}' | 101 awk '{print $1}' |
129 sort -u | 102 sort -u |
130 while read url; do 103 while read url; do
131 echo "**** Pulling $url" 104 echo "**** Pulling $url"
132 -antigen-ensure-repo --update --verbose "$url" 105 -antigen-ensure-repo --update --verbose "$url"
133 echo 106 echo
134 done 107 done
135 } 108 }
136 109
137 -antigen-get-clone-dir () { 110 -antigen-get-clone-dir () {
138 # Takes a repo url and gives out the path that this url needs to be cloned 111 # Takes a repo url and gives out the path that this url needs to be cloned
139 # to. Doesn't actually clone anything. 112 # to. Doesn't actually clone anything.
140 # TODO: Memoize? 113 # TODO: Memoize?
141 114
142 # The url given. 115 # The url given.
143 local url="$1" 116 local url="$1"
144 117
145 # Echo the full path to the clone directory. 118 # Echo the full path to the clone directory.
146 echo -n $ADOTDIR/repos/ 119 echo -n $ADOTDIR/repos/
147 echo "$url" | sed \ 120 echo "$url" | sed \
148 -e 's./.-SLASH-.g' \ 121 -e 's./.-SLASH-.g' \
149 -e 's.:.-COLON-.g' \ 122 -e 's.:.-COLON-.g' \
150 -e 's.|.-PIPE-.g' 123 -e 's.|.-PIPE-.g'
151 } 124 }
152 125
153 -antigen-get-clone-url () { 126 -antigen-get-clone-url () {
154 # Takes a repo's clone dir and gives out the repo's original url that was 127 # Takes a repo's clone dir and gives out the repo's original url that was
155 # used to create the given directory path. 128 # used to create the given directory path.
156 # TODO: Memoize? 129 # TODO: Memoize?
157 echo "$1" | sed \ 130 echo "$1" | sed \
158 -e "s:^$ADOTDIR/repos/::" \ 131 -e "s:^$ADOTDIR/repos/::" \
159 -e 's.-SLASH-./.g' \ 132 -e 's.-SLASH-./.g' \
160 -e 's.-COLON-.:.g' \ 133 -e 's.-COLON-.:.g' \
161 -e 's.-PIPE-.|.g' 134 -e 's.-PIPE-.|.g'
162 } 135 }
163 136
164 -antigen-ensure-repo () { 137 -antigen-ensure-repo () {
165 138
166 # Ensure that a clone exists for the given repo url and branch. If the first 139 # Ensure that a clone exists for the given repo url and branch. If the first
167 # argument is `--update` and if a clone already exists for the given repo 140 # argument is `--update` and if a clone already exists for the given repo
168 # and branch, it is pull-ed, i.e., updated. 141 # and branch, it is pull-ed, i.e., updated.
169 142
170 # Argument defaults. 143 # Argument defaults.
171 # Check if we have to update. 144 # Check if we have to update.
172 local update=false 145 local update=false
173 # Verbose output. 146 # Verbose output.
174 local verbose=false 147 local verbose=false
175 148
176 # Load any boolean arguments specified. 149 # Load any boolean arguments specified.
177 while [[ $1 == --* ]]; do 150 while [[ $1 == --* ]]; do
178 eval "local '${1#--}=true'" 151 eval "local '${1#--}=true'"
179 shift 152 shift
180 done 153 done
181 154
182 # Get the clone's directory as per the given repo url and branch. 155 # Get the clone's directory as per the given repo url and branch.
183 local url="$1" 156 local url="$1"
184 local clone_dir="$(-antigen-get-clone-dir $url)" 157 local clone_dir="$(-antigen-get-clone-dir $url)"
185 158
186 # A temporary function wrapping the `git` command with repeated arguments. 159 # A temporary function wrapping the `git` command with repeated arguments.
187 --plugin-git () { 160 --plugin-git () {
188 eval git --git-dir=$clone_dir/.git --work-tree=$clone_dir "$@" 161 eval git --git-dir=$clone_dir/.git --work-tree=$clone_dir "$@"
189 } 162 }
190 163
191 # Clone if it doesn't already exist. 164 # Clone if it doesn't already exist.
192 if [[ ! -d $clone_dir ]]; then 165 if [[ ! -d $clone_dir ]]; then
193 git clone "${url%|*}" "$clone_dir" 166 git clone "${url%|*}" "$clone_dir"
194 elif $update; then 167 elif $update; then
195 # Save current revision. 168 # Save current revision.
196 local old_rev="$(--plugin-git rev-parse HEAD)" 169 local old_rev="$(--plugin-git rev-parse HEAD)"
197 # Pull changes if update requested. 170 # Pull changes if update requested.
198 --plugin-git pull 171 --plugin-git pull
199 # Get the new revision. 172 # Get the new revision.
200 local new_rev="$(--plugin-git rev-parse HEAD)" 173 local new_rev="$(--plugin-git rev-parse HEAD)"
201 fi 174 fi
202 175
203 # If its a specific branch that we want, checkout that branch. 176 # If its a specific branch that we want, checkout that branch.
204 if [[ $url == *\|* ]]; then 177 if [[ $url == *\|* ]]; then
205 local current_branch=${$(--plugin-git symbolic-ref HEAD)##refs/heads/} 178 local current_branch=${$(--plugin-git symbolic-ref HEAD)##refs/heads/}
206 local requested_branch="${url#*|}" 179 local requested_branch="${url#*|}"
207 # Only do the checkout when we are not already on the branch. 180 # Only do the checkout when we are not already on the branch.
208 [[ $requested_branch != $current_branch ]] && 181 [[ $requested_branch != $current_branch ]] &&
209 --plugin-git checkout $requested_branch 182 --plugin-git checkout $requested_branch
210 fi 183 fi
211 184
212 if ! [[ -z $old_rev || $old_rev == $new_rev ]]; then 185 if ! [[ -z $old_rev || $old_rev == $new_rev ]]; then
213 echo Updated from ${old_rev:0:7} to ${new_rev:0:7}. 186 echo Updated from ${old_rev:0:7} to ${new_rev:0:7}.
214 if $verbose; then 187 if $verbose; then
215 --plugin-git log --oneline --reverse --no-merges --stat '@{1}..' 188 --plugin-git log --oneline --reverse --no-merges --stat '@{1}..'
216 fi 189 fi
217 fi 190 fi
218 191
219 # Remove the temporary git wrapper function. 192 # Remove the temporary git wrapper function.
220 unfunction -- --plugin-git 193 unfunction -- --plugin-git
221 194
222 } 195 }
223 196
224 -antigen-load () { 197 -antigen-load () {
225 198
226 local url="$1" 199 local url="$1"
227 local loc="$2" 200 local loc="$2"
228 local btype="$3" 201 local btype="$3"
229 local make_local_clone="$4" 202 local make_local_clone="$4"
230 203
231 # The full location where the plugin is located. 204 # The full location where the plugin is located.
232 local location 205 local location
233 if $make_local_clone; then 206 if $make_local_clone; then
234 location="$(-antigen-get-clone-dir "$url")/$loc" 207 location="$(-antigen-get-clone-dir "$url")/$loc"
235 else 208 else
236 location="$url" 209 location="$url"
237 fi 210 fi
238 211
239 if [[ $btype == theme ]]; then 212 if [[ $btype == theme ]]; then
240 213
241 # Of course, if its a theme, the location would point to the script 214 # Of course, if its a theme, the location would point to the script
242 # file. 215 # file.
243 source "$location" 216 source "$location"
244 217
245 else 218 else
246 219
247 # Source the plugin script. 220 # Source the plugin script.
248 # FIXME: I don't know. Looks very very ugly. Needs a better 221 # FIXME: I don't know. Looks very very ugly. Needs a better
249 # implementation once tests are ready. 222 # implementation once tests are ready.
250 local script_loc="$(ls "$location" | grep -m1 '\.plugin\.zsh$')" 223 local script_loc="$(ls "$location" | grep -m1 '\.plugin\.zsh$')"
251 224
252 if [[ -f $script_loc ]]; then 225 if [[ -f $script_loc ]]; then
253 # If we have a `*.plugin.zsh`, source it. 226 # If we have a `*.plugin.zsh`, source it.
254 source "$script_loc" 227 source "$script_loc"
255 228
256 elif [[ ! -z "$(ls "$location" | grep -m1 '\.zsh$')" ]]; then 229 elif [[ ! -z "$(ls "$location" | grep -m1 '\.zsh$')" ]]; then
257 # If there is no `*.plugin.zsh` file, source *all* the `*.zsh` 230 # If there is no `*.plugin.zsh` file, source *all* the `*.zsh`
258 # files. 231 # files.
259 for script ($location/*.zsh(N)) source "$script" 232 for script ($location/*.zsh(N)) source "$script"
260 233
261 elif [[ ! -z "$(ls "$location" | grep -m1 '\.sh$')" ]]; then 234 elif [[ ! -z "$(ls "$location" | grep -m1 '\.sh$')" ]]; then
262 # If there are no `*.zsh` files either, we look for and source any 235 # If there are no `*.zsh` files either, we look for and source any
263 # `*.sh` files instead. 236 # `*.sh` files instead.
264 for script ($location/*.sh(N)) source "$script" 237 for script ($location/*.sh(N)) source "$script"
265 238
266 fi 239 fi
267 240
268 # Add to $fpath, for completion(s). 241 # Add to $fpath, for completion(s).
269 fpath=($location $fpath) 242 fpath=($location $fpath)
270 243
271 fi 244 fi
272 245
273 } 246 }
274 247
275 antigen-cleanup () { 248 antigen-cleanup () {
276 249
277 # Cleanup unused repositories. 250 # Cleanup unused repositories.
278 251
279 local force=false 252 local force=false
280 if [[ $1 == --force ]]; then 253 if [[ $1 == --force ]]; then
281 force=true 254 force=true
282 fi 255 fi
283 256
284 if [[ ! -d "$ADOTDIR/repos" || -z "$(ls "$ADOTDIR/repos/")" ]]; then 257 if [[ ! -d "$ADOTDIR/repos" || -z "$(ls "$ADOTDIR/repos/")" ]]; then
285 echo "You don't have any bundles." 258 echo "You don't have any bundles."
286 return 0 259 return 0
287 fi 260 fi
288 261
289 # Find directores in ADOTDIR/repos, that are not in the bundles record. 262 # Find directores in ADOTDIR/repos, that are not in the bundles record.
290 local unused_clones="$(comm -13 \ 263 local unused_clones="$(comm -13 \
291 <(-antigen-echo-record | 264 <(-antigen-echo-record |
292 awk '$4 == "true" {print $1}' | 265 awk '$4 == "true" {print $1}' |
293 while read line; do 266 while read line; do
294 -antigen-get-clone-dir "$line" 267 -antigen-get-clone-dir "$line"
295 done | 268 done |
296 sort -u) \ 269 sort -u) \
297 <(ls -d "$ADOTDIR/repos/"* | sort -u))" 270 <(ls -d "$ADOTDIR/repos/"* | sort -u))"
298 271
299 if [[ -z $unused_clones ]]; then 272 if [[ -z $unused_clones ]]; then
300 echo "You don't have any unidentified bundles." 273 echo "You don't have any unidentified bundles."
301 return 0 274 return 0
302 fi 275 fi
303 276
304 echo 'You have clones for the following repos, but are not used.' 277 echo 'You have clones for the following repos, but are not used.'
305 echo "$unused_clones" | 278 echo "$unused_clones" |
306 while read line; do 279 while read line; do
307 -antigen-get-clone-url "$line" 280 -antigen-get-clone-url "$line"
308 done | 281 done |
309 sed -e 's/^/ /' -e 's/|/, branch /' 282 sed -e 's/^/ /' -e 's/|/, branch /'
310 283
311 if $force || (echo -n '\nDelete them all? [y/N] '; read -q); then 284 if $force || (echo -n '\nDelete them all? [y/N] '; read -q); then
312 echo 285 echo
313 echo 286 echo
314 echo "$unused_clones" | while read line; do 287 echo "$unused_clones" | while read line; do
315 echo -n "Deleting clone for $(-antigen-get-clone-url "$line")..." 288 echo -n "Deleting clone for $(-antigen-get-clone-url "$line")..."
316 rm -rf "$line" 289 rm -rf "$line"
317 echo ' done.' 290 echo ' done.'
318 done 291 done
319 else 292 else
320 echo 293 echo
321 echo Nothing deleted. 294 echo Nothing deleted.
322 fi 295 fi
323 } 296 }
324 297
325 antigen-lib () { 298 antigen-lib () {
326 antigen-bundle --loc=lib 299 antigen-bundle --loc=lib
327 } 300 }
328 301
329 antigen-theme () { 302 antigen-theme () {
330 local name="${1:-robbyrussell}" 303 local name="${1:-robbyrussell}"
331 antigen-bundle --loc=themes/$name.zsh-theme --btype=theme 304 antigen-bundle --loc=themes/$name.zsh-theme --btype=theme
332 } 305 }
333 306
334 antigen-apply () { 307 antigen-apply () {
335 # Initialize completion. 308 # Initialize completion.
336 # TODO: Only load completions if there are any changes to the bundle 309 # TODO: Only load completions if there are any changes to the bundle
337 # repositories. 310 # repositories.
338 compinit -i 311 compinit -i
339 } 312 }
340 313
341 antigen-list () { 314 antigen-list () {
342 # List all currently installed bundles. 315 # List all currently installed bundles.
343 if [[ -z "$_ANTIGEN_BUNDLE_RECORD" ]]; then 316 if [[ -z "$_ANTIGEN_BUNDLE_RECORD" ]]; then
344 echo "You don't have any bundles." >&2 317 echo "You don't have any bundles." >&2
345 return 1 318 return 1
346 else 319 else
347 -antigen-echo-record | sort -u 320 -antigen-echo-record | sort -u
348 fi 321 fi
349 } 322 }
350 323
351 antigen-help () { 324 antigen-help () {
352 cat <<EOF 325 cat <<EOF
353 Antigen is a plugin management system for zsh. It makes it easy to grab awesome 326 Antigen is a plugin management system for zsh. It makes it easy to grab awesome
354 shell scripts and utilities, put up on github. For further details and complete 327 shell scripts and utilities, put up on github. For further details and complete
355 documentation, visit the project's page at 'http://antigen.sharats.me'. 328 documentation, visit the project's page at 'http://antigen.sharats.me'.
356 EOF 329 EOF
357 } 330 }
358 331
359 # A syntax sugar to avoid the `-` when calling antigen commands. With this 332 # A syntax sugar to avoid the `-` when calling antigen commands. With this
360 # function, you can write `antigen-bundle` as `antigen bundle` and so on. 333 # function, you can write `antigen-bundle` as `antigen bundle` and so on.
361 antigen () { 334 antigen () {
362 local cmd="$1" 335 local cmd="$1"
363 shift 336 shift
364 "antigen-$cmd" "$@" 337 "antigen-$cmd" "$@"
365 } 338 }
366 339
367 -antigen-parse-args () { 340 -antigen-parse-args () {
368 # An argument parsing functionality to parse arguments the *antigen* way :). 341 # An argument parsing functionality to parse arguments the *antigen* way :).
369 # Takes one first argument (called spec), which dictates how to parse and 342 # Takes one first argument (called spec), which dictates how to parse and
370 # the rest of the arguments are parsed. Outputs a piece of valid shell code 343 # the rest of the arguments are parsed. Outputs a piece of valid shell code
371 # that can be passed to `eval` inside a function which creates the arguments 344 # that can be passed to `eval` inside a function which creates the arguments
372 # and their values as local variables. Suggested use is to set the defaults 345 # and their values as local variables. Suggested use is to set the defaults
373 # to all arguments first and then eval the output of this function. 346 # to all arguments first and then eval the output of this function.
374 347
375 # Spec: Only long argument supported. No support for parsing short options. 348 # Spec: Only long argument supported. No support for parsing short options.
376 # The spec must have two sections, separated by a `;`. 349 # The spec must have two sections, separated by a `;`.
377 # '<positional-arguments>;<keyword-only-arguments>' 350 # '<positional-arguments>;<keyword-only-arguments>'
378 # Positional arguments are passed as just values, like `command a b`. 351 # Positional arguments are passed as just values, like `command a b`.
379 # Keyword arguments are passed as a `--name=value` pair, like `command 352 # Keyword arguments are passed as a `--name=value` pair, like `command
380 # --arg1=a --arg2=b`. 353 # --arg1=a --arg2=b`.
381 354
382 # Each argument in the spec is separated by a `,`. Each keyword argument can 355 # Each argument in the spec is separated by a `,`. Each keyword argument can
383 # end in a `:` to specifiy that this argument wants a value, otherwise it 356 # end in a `:` to specifiy that this argument wants a value, otherwise it
384 # doesn't take a value. (The value in the output when the keyword argument 357 # doesn't take a value. (The value in the output when the keyword argument
385 # doesn't have a `:` is `true`). 358 # doesn't have a `:` is `true`).
386 359
387 # Arguments in either section can end with a `?` (should come after `:`, if 360 # Arguments in either section can end with a `?` (should come after `:`, if
388 # both are present), means optional. FIXME: Not yet implemented. 361 # both are present), means optional. FIXME: Not yet implemented.
389 362
390 # See the test file, tests/arg-parser.t for (working) examples. 363 # See the test file, tests/arg-parser.t for (working) examples.
391 364
392 local spec="$1" 365 local spec="$1"
393 shift 366 shift
394 367
395 local code='' 368 local code=''
396 369
397 --add-var () { 370 --add-var () {
398 test -z "$code" || code="$code\n" 371 test -z "$code" || code="$code\n"
399 code="${code}local $1='$2'" 372 code="${code}local $1='$2'"
400 } 373 }
401 374
402 local positional_args="$(echo "$spec" | cut -d\; -f1)" 375 local positional_args="$(echo "$spec" | cut -d\; -f1)"
403 local positional_args_count="$(echo $positional_args | 376 local positional_args_count="$(echo $positional_args |
404 awk -F, '{print NF}')" 377 awk -F, '{print NF}')"
405 378
406 # Set spec values based on the positional arguments. 379 # Set spec values based on the positional arguments.
407 local i=1 380 local i=1
408 while ! [[ -z $1 || $1 == --* ]]; do 381 while ! [[ -z $1 || $1 == --* ]]; do
409 382
410 if (( $i > $positional_args_count )); then 383 if (( $i > $positional_args_count )); then
411 echo "Only $positional_args_count positional arguments allowed." >&2 384 echo "Only $positional_args_count positional arguments allowed." >&2
412 echo "Found at least one more: '$1'" >&2 385 echo "Found at least one more: '$1'" >&2
413 return 386 return
414 fi 387 fi
415 388
416 local name_spec="$(echo "$positional_args" | cut -d, -f$i)" 389 local name_spec="$(echo "$positional_args" | cut -d, -f$i)"
417 local name="${${name_spec%\?}%:}" 390 local name="${${name_spec%\?}%:}"
418 local value="$1" 391 local value="$1"
419 392
420 --add-var $name "$value" 393 --add-var $name "$value"
421 394
422 shift 395 shift
423 i=$(($i + 1)) 396 i=$(($i + 1))
424 done 397 done
425 398
426 local keyword_args="$( 399 local keyword_args="$(
427 echo "$positional_args" | tr , '\n' | sed -r 's/(\??)$/:\1/' 400 echo "$positional_args" | tr , '\n' | sed -r 's/(\??)$/:\1/'
428 echo "$spec" | cut -d\; -f2 | tr , '\n' 401 echo "$spec" | cut -d\; -f2 | tr , '\n'
429 )" 402 )"
430 local keyword_args_count="$(echo $keyword_args | awk -F, '{print NF}')" 403 local keyword_args_count="$(echo $keyword_args | awk -F, '{print NF}')"
431 404
432 # Set spec values from keyword arguments, if any. The remaining arguments 405 # Set spec values from keyword arguments, if any. The remaining arguments
433 # are all assumed to be keyword arguments. 406 # are all assumed to be keyword arguments.
434 while [[ $1 == --* ]]; do 407 while [[ $1 == --* ]]; do
435 # Remove the `--` at the start. 408 # Remove the `--` at the start.
436 local arg="${1#--}" 409 local arg="${1#--}"
437 410
438 # Get the argument name and value. 411 # Get the argument name and value.
439 if [[ $arg != *=* ]]; then 412 if [[ $arg != *=* ]]; then
440 local name="$arg" 413 local name="$arg"
441 local value='' 414 local value=''
442 else 415 else
443 local name="${arg%\=*}" 416 local name="${arg%\=*}"
444 local value="${arg#*=}" 417 local value="${arg#*=}"
445 fi 418 fi
446 419
447 # The specification for this argument, used for validations. 420 # The specification for this argument, used for validations.
448 local arg_line="$(echo "$keyword_args" | grep -m1 "^$name:\??\?")" 421 local arg_line="$(echo "$keyword_args" | grep -m1 "^$name:\??\?")"
449 422
450 # Validate argument and value. 423 # Validate argument and value.
451 if [[ -z $arg_line ]]; then 424 if [[ -z $arg_line ]]; then
452 # This argument is not known to us. 425 # This argument is not known to us.
453 echo "Unknown argument '$name'." >&2 426 echo "Unknown argument '$name'." >&2
454 return 427 return
455 428
456 elif (echo "$arg_line" | grep -qm1 ':') && [[ -z $value ]]; then 429 elif (echo "$arg_line" | grep -qm1 ':') && [[ -z $value ]]; then
457 # This argument needs a value, but is not provided. 430 # This argument needs a value, but is not provided.
458 echo "Required argument for '$name' not provided." >&2 431 echo "Required argument for '$name' not provided." >&2
459 return 432 return
460 433
461 elif (echo "$arg_line" | grep -vqm1 ':') && [[ ! -z $value ]]; then 434 elif (echo "$arg_line" | grep -vqm1 ':') && [[ ! -z $value ]]; then
462 # This argument doesn't need a value, but is provided. 435 # This argument doesn't need a value, but is provided.
463 echo "No argument required for '$name', but provided '$value'." >&2 436 echo "No argument required for '$name', but provided '$value'." >&2
464 return 437 return
465 438
466 fi 439 fi
467 440
468 if [[ -z $value ]]; then 441 if [[ -z $value ]]; then
469 value=true 442 value=true
470 fi 443 fi
471 444
472 --add-var "${name//-/_}" "$value" 445 --add-var "${name//-/_}" "$value"
473 shift 446 shift
474 done 447 done
475 448
476 echo "$code" 449 echo "$code"
477 450
478 unfunction -- --add-var 451 unfunction -- --add-var
479 452
480 } 453 }
481 454
482 # Echo the bundle specs as in the record. The first line is not echoed since it 455 # Echo the bundle specs as in the record. The first line is not echoed since it
483 # is a blank line. 456 # is a blank line.
484 -antigen-echo-record () { 457 -antigen-echo-record () {
485 echo "$_ANTIGEN_BUNDLE_RECORD" | sed -n '1!p' 458 echo "$_ANTIGEN_BUNDLE_RECORD" | sed -n '1!p'
486 } 459 }
487 460
488 -antigen-env-setup () { 461 -antigen-env-setup () {
489 # Pre-startup initializations. 462 # Pre-startup initializations.
490 -set-default ANTIGEN_DEFAULT_REPO_URL \ 463 -set-default ANTIGEN_DEFAULT_REPO_URL \
491 https://github.com/robbyrussell/oh-my-zsh.git 464 https://github.com/robbyrussell/oh-my-zsh.git
492 -set-default ADOTDIR $HOME/.antigen 465 -set-default ADOTDIR $HOME/.antigen
493 466
494 # Load the compinit module. 467 # Load the compinit module.
495 autoload -U compinit 468 autoload -U compinit
496 469
497 # Without the following, `compdef` function is not defined. 470 # Without the following, `compdef` function is not defined.
498 compinit -i 471 compinit -i
499 } 472 }
500 473
501 # Same as `export $1=$2`, but will only happen if the name specified by `$1` is 474 # Same as `export $1=$2`, but will only happen if the name specified by `$1` is
502 # not already set. 475 # not already set.
503 -set-default () { 476 -set-default () {
504 local arg_name="$1" 477 local arg_name="$1"
505 local arg_value="$2" 478 local arg_value="$2"
506 eval "test -z \"\$$arg_name\" && export $arg_name='$arg_value'" 479 eval "test -z \"\$$arg_name\" && export $arg_name='$arg_value'"
507 } 480 }
508 481
509 -antigen-env-setup 482 -antigen-env-setup
510 483