1#!/usr/bin/env zsh 2 3function omz { 4 [[ $# -gt 0 ]] || { 5 _omz::help 6 return 1 7 } 8 9 local command="$1" 10 shift 11 12 # Subcommand functions start with _ so that they don't 13 # appear as completion entries when looking for `omz` 14 (( $+functions[_omz::$command] )) || { 15 _omz::help 16 return 1 17 } 18 19 _omz::$command "$@" 20} 21 22function _omz { 23 local -a cmds subcmds 24 cmds=( 25 'changelog:Print the changelog' 26 'help:Usage information' 27 'plugin:Manage plugins' 28 'pr:Manage Oh My Zsh Pull Requests' 29 'reload:Reload the current zsh session' 30 'theme:Manage themes' 31 'update:Update Oh My Zsh' 32 'version:Show the version' 33 ) 34 35 if (( CURRENT == 2 )); then 36 _describe 'command' cmds 37 elif (( CURRENT == 3 )); then 38 case "$words[2]" in 39 changelog) local -a refs 40 refs=("${(@f)$(cd "$ZSH"; command git for-each-ref --format="%(refname:short):%(subject)" refs/heads refs/tags)}") 41 _describe 'command' refs ;; 42 plugin) subcmds=( 43 'disable:Disable plugin(s)' 44 'enable:Enable plugin(s)' 45 'info:Get plugin information' 46 'list:List plugins' 47 'load:Load plugin(s)' 48 ) 49 _describe 'command' subcmds ;; 50 pr) subcmds=('clean:Delete all Pull Request branches' 'test:Test a Pull Request') 51 _describe 'command' subcmds ;; 52 theme) subcmds=('list:List themes' 'set:Set a theme in your .zshrc file' 'use:Load a theme') 53 _describe 'command' subcmds ;; 54 esac 55 elif (( CURRENT == 4 )); then 56 case "${words[2]}::${words[3]}" in 57 plugin::(disable|enable|load)) 58 local -aU valid_plugins 59 60 if [[ "${words[3]}" = disable ]]; then 61 # if command is "disable", only offer already enabled plugins 62 valid_plugins=($plugins) 63 else 64 valid_plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(.N:h:t)) 65 # if command is "enable", remove already enabled plugins 66 [[ "${words[3]}" = enable ]] && valid_plugins=(${valid_plugins:|plugins}) 67 fi 68 69 _describe 'plugin' valid_plugins ;; 70 plugin::info) 71 local -aU plugins 72 plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(.N:h:t)) 73 _describe 'plugin' plugins ;; 74 theme::(set|use)) 75 local -aU themes 76 themes=("$ZSH"/themes/*.zsh-theme(.N:t:r) "$ZSH_CUSTOM"/**/*.zsh-theme(.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::)) 77 _describe 'theme' themes ;; 78 esac 79 elif (( CURRENT > 4 )); then 80 case "${words[2]}::${words[3]}" in 81 plugin::(enable|disable|load)) 82 local -aU valid_plugins 83 84 if [[ "${words[3]}" = disable ]]; then 85 # if command is "disable", only offer already enabled plugins 86 valid_plugins=($plugins) 87 else 88 valid_plugins=("$ZSH"/plugins/*/{_*,*.plugin.zsh}(.N:h:t) "$ZSH_CUSTOM"/plugins/*/{_*,*.plugin.zsh}(.N:h:t)) 89 # if command is "enable", remove already enabled plugins 90 [[ "${words[3]}" = enable ]] && valid_plugins=(${valid_plugins:|plugins}) 91 fi 92 93 # Remove plugins already passed as arguments 94 # NOTE: $(( CURRENT - 1 )) is the last plugin argument completely passed, i.e. that which 95 # has a space after them. This is to avoid removing plugins partially passed, which makes 96 # the completion not add a space after the completed plugin. 97 local -a args 98 args=(${words[4,$(( CURRENT - 1))]}) 99 valid_plugins=(${valid_plugins:|args}) 100 101 _describe 'plugin' valid_plugins ;; 102 esac 103 fi 104 105 return 0 106} 107 108compdef _omz omz 109 110## Utility functions 111 112function _omz::confirm { 113 # If question supplied, ask it before reading the answer 114 # NOTE: uses the logname of the caller function 115 if [[ -n "$1" ]]; then 116 _omz::log prompt "$1" "${${functrace[1]#_}%:*}" 117 fi 118 119 # Read one character 120 read -r -k 1 121 122 # If no newline entered, add a newline 123 if [[ "$REPLY" != $'\n' ]]; then 124 echo 125 fi 126} 127 128function _omz::log { 129 # if promptsubst is set, a message with `` or $() 130 # will be run even if quoted due to `print -P` 131 setopt localoptions nopromptsubst 132 133 # $1 = info|warn|error|debug 134 # $2 = text 135 # $3 = (optional) name of the logger 136 137 local logtype=$1 138 local logname=${3:-${${functrace[1]#_}%:*}} 139 140 # Don't print anything if debug is not active 141 if [[ $logtype = debug && -z $_OMZ_DEBUG ]]; then 142 return 143 fi 144 145 # Choose coloring based on log type 146 case "$logtype" in 147 prompt) print -Pn "%S%F{blue}$logname%f%s: $2" ;; 148 debug) print -P "%F{white}$logname%f: $2" ;; 149 info) print -P "%F{green}$logname%f: $2" ;; 150 warn) print -P "%S%F{yellow}$logname%f%s: $2" ;; 151 error) print -P "%S%F{red}$logname%f%s: $2" ;; 152 esac >&2 153} 154 155## User-facing commands 156 157function _omz::help { 158 cat >&2 <<EOF 159Usage: omz <command> [options] 160 161Available commands: 162 163 help Print this help message 164 changelog Print the changelog 165 plugin <command> Manage plugins 166 pr <command> Manage Oh My Zsh Pull Requests 167 reload Reload the current zsh session 168 theme <command> Manage themes 169 update Update Oh My Zsh 170 version Show the version 171 172EOF 173} 174 175function _omz::changelog { 176 local version=${1:-HEAD} format=${3:-"--text"} 177 178 if ( 179 cd "$ZSH" 180 ! command git show-ref --verify refs/heads/$version && \ 181 ! command git show-ref --verify refs/tags/$version && \ 182 ! command git rev-parse --verify "${version}^{commit}" 183 ) &>/dev/null; then 184 cat >&2 <<EOF 185Usage: omz changelog [version] 186 187NOTE: <version> must be a valid branch, tag or commit. 188EOF 189 return 1 190 fi 191 192 "$ZSH/tools/changelog.sh" "$version" "${2:-}" "$format" 193} 194 195function _omz::plugin { 196 (( $# > 0 && $+functions[_omz::plugin::$1] )) || { 197 cat >&2 <<EOF 198Usage: omz plugin <command> [options] 199 200Available commands: 201 202 disable <plugin> Disable plugin(s) 203 enable <plugin> Enable plugin(s) 204 info <plugin> Get information of a plugin 205 list List all available Oh My Zsh plugins 206 load <plugin> Load plugin(s) 207 208EOF 209 return 1 210 } 211 212 local command="$1" 213 shift 214 215 _omz::plugin::$command "$@" 216} 217 218function _omz::plugin::disable { 219 if [[ -z "$1" ]]; then 220 echo >&2 "Usage: omz plugin disable <plugin> [...]" 221 return 1 222 fi 223 224 # Check that plugin is in $plugins 225 local -a dis_plugins 226 for plugin in "$@"; do 227 if [[ ${plugins[(Ie)$plugin]} -eq 0 ]]; then 228 _omz::log warn "plugin '$plugin' is not enabled." 229 continue 230 fi 231 dis_plugins+=("$plugin") 232 done 233 234 # Exit if there are no enabled plugins to disable 235 if [[ ${#dis_plugins} -eq 0 ]]; then 236 return 1 237 fi 238 239 # Remove plugins substitution awk script 240 local awk_subst_plugins="\ 241 gsub(/\s+(${(j:|:)dis_plugins})/, \"\") # with spaces before 242 gsub(/(${(j:|:)dis_plugins})\s+/, \"\") # with spaces after 243 gsub(/\((${(j:|:)dis_plugins})\)/, \"\") # without spaces (only plugin) 244" 245 # Disable plugins awk script 246 local awk_script=" 247# if plugins=() is in oneline form, substitute disabled plugins and go to next line 248/^\s*plugins=\([^#]+\).*\$/ { 249 $awk_subst_plugins 250 print \$0 251 next 252} 253 254# if plugins=() is in multiline form, enable multi flag and disable plugins if they're there 255/^\s*plugins=\(/ { 256 multi=1 257 $awk_subst_plugins 258 print \$0 259 next 260} 261 262# if multi flag is enabled and we find a valid closing parenthesis, remove plugins and disable multi flag 263multi == 1 && /^[^#]*\)/ { 264 multi=0 265 $awk_subst_plugins 266 print \$0 267 next 268} 269 270multi == 1 && length(\$0) > 0 { 271 $awk_subst_plugins 272 if (length(\$0) > 0) print \$0 273 next 274} 275 276{ print \$0 } 277" 278 279 local zdot="${ZDOTDIR:-$HOME}" 280 awk "$awk_script" "$zdot/.zshrc" > "$zdot/.zshrc.new" \ 281 && command mv -f "$zdot/.zshrc" "$zdot/.zshrc.bck" \ 282 && command mv -f "$zdot/.zshrc.new" "$zdot/.zshrc" 283 284 # Exit if the new .zshrc file wasn't created correctly 285 [[ $? -eq 0 ]] || { 286 local ret=$? 287 _omz::log error "error disabling plugins." 288 return $ret 289 } 290 291 # Exit if the new .zshrc file has syntax errors 292 if ! zsh -n "$zdot/.zshrc"; then 293 _omz::log error "broken syntax in '"${zdot/#$HOME/\~}/.zshrc"'. Rolling back changes..." 294 command mv -f "$zdot/.zshrc" "$zdot/.zshrc.new" 295 command mv -f "$zdot/.zshrc.bck" "$zdot/.zshrc" 296 return 1 297 fi 298 299 # Restart the zsh session if there were no errors 300 _omz::log info "plugins disabled: ${(j:, :)dis_plugins}." 301 302 # Old zsh versions don't have ZSH_ARGZERO 303 local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" 304 # Check whether to run a login shell 305 [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh" 306} 307 308function _omz::plugin::enable { 309 if [[ -z "$1" ]]; then 310 echo >&2 "Usage: omz plugin enable <plugin> [...]" 311 return 1 312 fi 313 314 # Check that plugin is not in $plugins 315 local -a add_plugins 316 for plugin in "$@"; do 317 if [[ ${plugins[(Ie)$plugin]} -ne 0 ]]; then 318 _omz::log warn "plugin '$plugin' is already enabled." 319 continue 320 fi 321 add_plugins+=("$plugin") 322 done 323 324 # Exit if there are no plugins to enable 325 if [[ ${#add_plugins} -eq 0 ]]; then 326 return 1 327 fi 328 329 # Enable plugins awk script 330 local awk_script=" 331# if plugins=() is in oneline form, substitute ) with new plugins and go to the next line 332/^\s*plugins=\([^#]+\).*\$/ { 333 sub(/\)/, \" $add_plugins&\") 334 print \$0 335 next 336} 337 338# if plugins=() is in multiline form, enable multi flag 339/^\s*plugins=\(/ { 340 multi=1 341} 342 343# if multi flag is enabled and we find a valid closing parenthesis, 344# add new plugins and disable multi flag 345multi == 1 && /^[^#]*\)/ { 346 multi=0 347 sub(/\)/, \" $add_plugins&\") 348 print \$0 349 next 350} 351 352{ print \$0 } 353" 354 355 local zdot="${ZDOTDIR:-$HOME}" 356 awk "$awk_script" "$zdot/.zshrc" > "$zdot/.zshrc.new" \ 357 && command mv -f "$zdot/.zshrc" "$zdot/.zshrc.bck" \ 358 && command mv -f "$zdot/.zshrc.new" "$zdot/.zshrc" 359 360 # Exit if the new .zshrc file wasn't created correctly 361 [[ $? -eq 0 ]] || { 362 local ret=$? 363 _omz::log error "error enabling plugins." 364 return $ret 365 } 366 367 # Exit if the new .zshrc file has syntax errors 368 if ! zsh -n "$zdot/.zshrc"; then 369 _omz::log error "broken syntax in '"${zdot/#$HOME/\~}/.zshrc"'. Rolling back changes..." 370 command mv -f "$zdot/.zshrc" "$zdot/.zshrc.new" 371 command mv -f "$zdot/.zshrc.bck" "$zdot/.zshrc" 372 return 1 373 fi 374 375 # Restart the zsh session if there were no errors 376 _omz::log info "plugins enabled: ${(j:, :)add_plugins}." 377 378 # Old zsh versions don't have ZSH_ARGZERO 379 local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" 380 # Check whether to run a login shell 381 [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh" 382} 383 384function _omz::plugin::info { 385 if [[ -z "$1" ]]; then 386 echo >&2 "Usage: omz plugin info <plugin>" 387 return 1 388 fi 389 390 local readme 391 for readme in "$ZSH_CUSTOM/plugins/$1/README.md" "$ZSH/plugins/$1/README.md"; do 392 if [[ -f "$readme" ]]; then 393 (( ${+commands[less]} )) && less "$readme" || cat "$readme" 394 return 0 395 fi 396 done 397 398 if [[ -d "$ZSH_CUSTOM/plugins/$1" || -d "$ZSH/plugins/$1" ]]; then 399 _omz::log error "the '$1' plugin doesn't have a README file" 400 else 401 _omz::log error "'$1' plugin not found" 402 fi 403 404 return 1 405} 406 407function _omz::plugin::list { 408 local -a custom_plugins builtin_plugins 409 custom_plugins=("$ZSH_CUSTOM"/plugins/*(-/N:t)) 410 builtin_plugins=("$ZSH"/plugins/*(-/N:t)) 411 412 # If the command is being piped, print all found line by line 413 if [[ ! -t 1 ]]; then 414 print -l ${(q-)custom_plugins} ${(q-)builtin_plugins} 415 return 416 fi 417 418 if (( ${#custom_plugins} )); then 419 print -P "%U%BCustom plugins%b%u:" 420 print -l ${(q-)custom_plugins} | column -x 421 fi 422 423 if (( ${#builtin_plugins} )); then 424 (( ${#custom_plugins} )) && echo # add a line of separation 425 426 print -P "%U%BBuilt-in plugins%b%u:" 427 print -l ${(q-)builtin_plugins} | column -x 428 fi 429} 430 431function _omz::plugin::load { 432 if [[ -z "$1" ]]; then 433 echo >&2 "Usage: omz plugin load <plugin> [...]" 434 return 1 435 fi 436 437 local plugin base has_completion=0 438 for plugin in "$@"; do 439 if [[ -d "$ZSH_CUSTOM/plugins/$plugin" ]]; then 440 base="$ZSH_CUSTOM/plugins/$plugin" 441 elif [[ -d "$ZSH/plugins/$plugin" ]]; then 442 base="$ZSH/plugins/$plugin" 443 else 444 _omz::log warn "plugin '$plugin' not found" 445 continue 446 fi 447 448 # Check if its a valid plugin 449 if [[ ! -f "$base/_$plugin" && ! -f "$base/$plugin.plugin.zsh" ]]; then 450 _omz::log warn "'$plugin' is not a valid plugin" 451 continue 452 # It it is a valid plugin, add its directory to $fpath unless it is already there 453 elif (( ! ${fpath[(Ie)$base]} )); then 454 fpath=("$base" $fpath) 455 fi 456 457 # Check if it has completion to reload compinit 458 local -a comp_files 459 comp_files=($base/_*(N)) 460 has_completion=$(( $#comp_files > 0 )) 461 462 # Load the plugin 463 if [[ -f "$base/$plugin.plugin.zsh" ]]; then 464 source "$base/$plugin.plugin.zsh" 465 fi 466 done 467 468 # If we have completion, we need to reload the completion 469 # We pass -D to avoid generating a new dump file, which would overwrite our 470 # current one for the next session (and we don't want that because we're not 471 # actually enabling the plugins for the next session). 472 # Note that we still have to pass -d "$_comp_dumpfile", so that compinit 473 # doesn't use the default zcompdump location (${ZDOTDIR:-$HOME}/.zcompdump). 474 if (( has_completion )); then 475 compinit -D -d "$_comp_dumpfile" 476 fi 477} 478 479function _omz::pr { 480 (( $# > 0 && $+functions[_omz::pr::$1] )) || { 481 cat >&2 <<EOF 482Usage: omz pr <command> [options] 483 484Available commands: 485 486 clean Delete all PR branches (ohmyzsh/pull-*) 487 test <PR_number_or_URL> Fetch PR #NUMBER and rebase against master 488 489EOF 490 return 1 491 } 492 493 local command="$1" 494 shift 495 496 _omz::pr::$command "$@" 497} 498 499function _omz::pr::clean { 500 ( 501 set -e 502 builtin cd -q "$ZSH" 503 504 # Check if there are PR branches 505 local fmt branches 506 fmt="%(color:bold blue)%(align:18,right)%(refname:short)%(end)%(color:reset) %(color:dim bold red)%(objectname:short)%(color:reset) %(color:yellow)%(contents:subject)" 507 branches="$(command git for-each-ref --sort=-committerdate --color --format="$fmt" "refs/heads/ohmyzsh/pull-*")" 508 509 # Exit if there are no PR branches 510 if [[ -z "$branches" ]]; then 511 _omz::log info "there are no Pull Request branches to remove." 512 return 513 fi 514 515 # Print found PR branches 516 echo "$branches\n" 517 # Confirm before removing the branches 518 _omz::confirm "do you want remove these Pull Request branches? [Y/n] " 519 # Only proceed if the answer is a valid yes option 520 [[ "$REPLY" != [yY$'\n'] ]] && return 521 522 _omz::log info "removing all Oh My Zsh Pull Request branches..." 523 command git branch --list 'ohmyzsh/pull-*' | while read branch; do 524 command git branch -D "$branch" 525 done 526 ) 527} 528 529function _omz::pr::test { 530 # Allow $1 to be a URL to the pull request 531 if [[ "$1" = https://* ]]; then 532 1="${1:t}" 533 fi 534 535 # Check the input 536 if ! [[ -n "$1" && "$1" =~ ^[[:digit:]]+$ ]]; then 537 echo >&2 "Usage: omz pr test <PR_NUMBER_or_URL>" 538 return 1 539 fi 540 541 # Save current git HEAD 542 local branch 543 branch=$(builtin cd -q "$ZSH"; git symbolic-ref --short HEAD) || { 544 _omz::log error "error when getting the current git branch. Aborting..." 545 return 1 546 } 547 548 549 # Fetch PR onto ohmyzsh/pull-<PR_NUMBER> branch and rebase against master 550 # If any of these operations fail, undo the changes made 551 ( 552 set -e 553 builtin cd -q "$ZSH" 554 555 # Get the ohmyzsh git remote 556 command git remote -v | while read remote url _; do 557 case "$url" in 558 https://github.com/ohmyzsh/ohmyzsh(|.git)) found=1; break ;; 559 git@github.com:ohmyzsh/ohmyzsh(|.git)) found=1; break ;; 560 esac 561 done 562 563 (( $found )) || { 564 _omz::log error "could not found the ohmyzsh git remote. Aborting..." 565 return 1 566 } 567 568 # Fetch pull request head 569 _omz::log info "fetching PR #$1 to ohmyzsh/pull-$1..." 570 command git fetch -f "$remote" refs/pull/$1/head:ohmyzsh/pull-$1 || { 571 _omz::log error "error when trying to fetch PR #$1." 572 return 1 573 } 574 575 # Rebase pull request branch against the current master 576 _omz::log info "rebasing PR #$1..." 577 command git rebase master ohmyzsh/pull-$1 || { 578 command git rebase --abort &>/dev/null 579 _omz::log warn "could not rebase PR #$1 on top of master." 580 _omz::log warn "you might not see the latest stable changes." 581 _omz::log info "run \`zsh\` to test the changes." 582 return 1 583 } 584 585 _omz::log info "fetch of PR #${1} successful." 586 ) 587 588 # If there was an error, abort running zsh to test the PR 589 [[ $? -eq 0 ]] || return 1 590 591 # Run zsh to test the changes 592 _omz::log info "running \`zsh\` to test the changes. Run \`exit\` to go back." 593 command zsh -l 594 595 # After testing, go back to the previous HEAD if the user wants 596 _omz::confirm "do you want to go back to the previous branch? [Y/n] " 597 # Only proceed if the answer is a valid yes option 598 [[ "$REPLY" != [yY$'\n'] ]] && return 599 600 ( 601 set -e 602 builtin cd -q "$ZSH" 603 604 command git checkout "$branch" -- || { 605 _omz::log error "could not go back to the previous branch ('$branch')." 606 return 1 607 } 608 ) 609} 610 611function _omz::reload { 612 # Delete current completion cache 613 command rm -f $_comp_dumpfile $ZSH_COMPDUMP 614 615 # Old zsh versions don't have ZSH_ARGZERO 616 local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" 617 # Check whether to run a login shell 618 [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh" 619} 620 621function _omz::theme { 622 (( $# > 0 && $+functions[_omz::theme::$1] )) || { 623 cat >&2 <<EOF 624Usage: omz theme <command> [options] 625 626Available commands: 627 628 list List all available Oh My Zsh themes 629 set <theme> Set a theme in your .zshrc file 630 use <theme> Load a theme 631 632EOF 633 return 1 634 } 635 636 local command="$1" 637 shift 638 639 _omz::theme::$command "$@" 640} 641 642function _omz::theme::list { 643 local -a custom_themes builtin_themes 644 custom_themes=("$ZSH_CUSTOM"/**/*.zsh-theme(-.N:r:gs:"$ZSH_CUSTOM"/themes/:::gs:"$ZSH_CUSTOM"/:::)) 645 builtin_themes=("$ZSH"/themes/*.zsh-theme(-.N:t:r)) 646 647 # If the command is being piped, print all found line by line 648 if [[ ! -t 1 ]]; then 649 print -l ${(q-)custom_themes} ${(q-)builtin_themes} 650 return 651 fi 652 653 # Print theme in use 654 if [[ -n "$ZSH_THEME" ]]; then 655 print -Pn "%U%BCurrent theme%b%u: " 656 [[ $ZSH_THEME = random ]] && echo "$RANDOM_THEME (via random)" || echo "$ZSH_THEME" 657 echo 658 fi 659 660 # Print custom themes if there are any 661 if (( ${#custom_themes} )); then 662 print -P "%U%BCustom themes%b%u:" 663 print -l ${(q-)custom_themes} | column -x 664 echo 665 fi 666 667 # Print built-in themes 668 print -P "%U%BBuilt-in themes%b%u:" 669 print -l ${(q-)builtin_themes} | column -x 670} 671 672function _omz::theme::set { 673 if [[ -z "$1" ]]; then 674 echo >&2 "Usage: omz theme set <theme>" 675 return 1 676 fi 677 678 # Check that theme exists 679 if [[ ! -f "$ZSH_CUSTOM/$1.zsh-theme" ]] \ 680 && [[ ! -f "$ZSH_CUSTOM/themes/$1.zsh-theme" ]] \ 681 && [[ ! -f "$ZSH/themes/$1.zsh-theme" ]]; then 682 _omz::log error "%B$1%b theme not found" 683 return 1 684 fi 685 686 # Enable theme in .zshrc 687 local awk_script=' 688!set && /^\s*ZSH_THEME=[^#]+.*$/ { 689 set=1 690 sub(/^\s*ZSH_THEME=[^#]+.*$/, "ZSH_THEME=\"'$1'\" # set by `omz`") 691 print $0 692 next 693} 694 695{ print $0 } 696 697END { 698 # If no ZSH_THEME= line was found, return an error 699 if (!set) exit 1 700} 701' 702 703 local zdot="${ZDOTDIR:-$HOME}" 704 awk "$awk_script" "$zdot/.zshrc" > "$zdot/.zshrc.new" \ 705 || { 706 # Prepend ZSH_THEME= line to .zshrc if it doesn't exist 707 cat <<EOF 708ZSH_THEME="$1" # set by \`omz\` 709 710EOF 711 cat "$zdot/.zshrc" 712 } > "$zdot/.zshrc.new" \ 713 && command mv -f "$zdot/.zshrc" "$zdot/.zshrc.bck" \ 714 && command mv -f "$zdot/.zshrc.new" "$zdot/.zshrc" 715 716 # Exit if the new .zshrc file wasn't created correctly 717 [[ $? -eq 0 ]] || { 718 local ret=$? 719 _omz::log error "error setting theme." 720 return $ret 721 } 722 723 # Exit if the new .zshrc file has syntax errors 724 if ! zsh -n "$zdot/.zshrc"; then 725 _omz::log error "broken syntax in '"${zdot/#$HOME/\~}/.zshrc"'. Rolling back changes..." 726 command mv -f "$zdot/.zshrc" "$zdot/.zshrc.new" 727 command mv -f "$zdot/.zshrc.bck" "$zdot/.zshrc" 728 return 1 729 fi 730 731 # Restart the zsh session if there were no errors 732 _omz::log info "'$1' theme set correctly." 733 734 # Old zsh versions don't have ZSH_ARGZERO 735 local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" 736 # Check whether to run a login shell 737 [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh" 738} 739 740function _omz::theme::use { 741 if [[ -z "$1" ]]; then 742 echo >&2 "Usage: omz theme use <theme>" 743 return 1 744 fi 745 746 # Respect compatibility with old lookup order 747 if [[ -f "$ZSH_CUSTOM/$1.zsh-theme" ]]; then 748 source "$ZSH_CUSTOM/$1.zsh-theme" 749 elif [[ -f "$ZSH_CUSTOM/themes/$1.zsh-theme" ]]; then 750 source "$ZSH_CUSTOM/themes/$1.zsh-theme" 751 elif [[ -f "$ZSH/themes/$1.zsh-theme" ]]; then 752 source "$ZSH/themes/$1.zsh-theme" 753 else 754 _omz::log error "%B$1%b theme not found" 755 return 1 756 fi 757 758 # Update theme settings 759 ZSH_THEME="$1" 760 [[ $1 = random ]] || unset RANDOM_THEME 761} 762 763function _omz::update { 764 local last_commit=$(cd "$ZSH"; git rev-parse HEAD) 765 766 # Run update script 767 if [[ "$1" != --unattended ]]; then 768 ZSH="$ZSH" zsh -f "$ZSH/tools/upgrade.sh" --interactive || return $? 769 else 770 ZSH="$ZSH" zsh -f "$ZSH/tools/upgrade.sh" || return $? 771 fi 772 773 # Update last updated file 774 zmodload zsh/datetime 775 echo "LAST_EPOCH=$(( EPOCHSECONDS / 60 / 60 / 24 ))" >! "${ZSH_CACHE_DIR}/.zsh-update" 776 # Remove update lock if it exists 777 command rm -rf "$ZSH/log/update.lock" 778 779 # Restart the zsh session if there were changes 780 if [[ "$1" != --unattended && "$(cd "$ZSH"; git rev-parse HEAD)" != "$last_commit" ]]; then 781 # Old zsh versions don't have ZSH_ARGZERO 782 local zsh="${ZSH_ARGZERO:-${functrace[-1]%:*}}" 783 # Check whether to run a login shell 784 [[ "$zsh" = -* || -o login ]] && exec -l "${zsh#-}" || exec "$zsh" 785 fi 786} 787 788function _omz::version { 789 ( 790 cd "$ZSH" 791 792 # Get the version name: 793 # 1) try tag-like version 794 # 2) try name-rev 795 # 3) try branch name 796 local version 797 version=$(command git describe --tags HEAD 2>/dev/null) \ 798 || version=$(command git name-rev --no-undefined --name-only --exclude="remotes/*" HEAD 2>/dev/null) \ 799 || version=$(command git symbolic-ref --quiet --short HEAD 2>/dev/null) 800 801 # Get short hash for the current HEAD 802 local commit=$(command git rev-parse --short HEAD 2>/dev/null) 803 804 # Show version and commit hash 805 printf "%s (%s)\n" "$version" "$commit" 806 ) 807} 808