Commit 0c257ebe4a9289925701e6755ad0cc421f988f8b

Authored by Shrikant Sharat
1 parent 40deb795bd

For #29. Intial working implementation with tests.

The `-theme` command is now little more than an extension to the `-bundle`
command. The difference is that this command sets `--btype=theme`, which is what
indicates that this bundle is a theme.

As such, the `-theme` command accepts all the documented options taken by
`-bundle`.

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