Commit 222271a0b886e047915acccf3a556eaa43248f7b

Authored by Shrikant Sharat
1 parent 9d1b71736a

Memoization is not possible in a sane way.

The memoized results of these functions cannot be saved in a global hash map,
becuase these functions are always run in a subshell. Changes to variables in
the subshell do not reflect in the main shell instance. We'd have to resort to
use the `$REPLY` ways returning the result from these functions, if they were to
be memoized. But that way of doing things sucks. Totally unreadable. So, just
not memoizing.

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