Commit 7a2ca5936176a8f060dcaad73ef97338bcddadbe

Authored by Shrikant Sharat
1 parent 8bba7ab707

Allow whitespace in the arguments spec.

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