diff --git a/README.md b/README.md index adbc579..e0fb93e 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,11 @@ Returns 0 if an init script exists. You can set the environment variable ZGEN_RESET_ON_CHANGE. These files will be checked and if a change is detected zgen reset is called. ZGEN_RESET_ON_CHANGE=(${HOME}/.zshrc ${HOME}/.zshrc.local) +### Notes +Be aware that `zgen` tries to handle [`compinit`][compinit] for you to allow for the fastest possible initialization times. However, this functionality will be disabled if you've already called `compinit` yourself before sourcing `zgen.zsh`. (Alternatively, you can disable it yourself by disabling `$ZGEN_AUTOLOAD_COMPINIT`.) + + [compinit]: "Zsh manual 20.2.1: Use of compinit" + ### Example .zshrc ```zsh diff --git a/zgen.zsh b/zgen.zsh index 7338cb0..4ac62eb 100644 --- a/zgen.zsh +++ b/zgen.zsh @@ -1,8 +1,12 @@ #!/bin/zsh -autoload -U regexp-replace - +# vim: set ft=zsh fenc=utf-8 noai ts=8 et sts=4 sw=0 tw=80 nowrap : local ZGEN_SOURCE="$(cd "$(dirname "${0}")" && pwd -P)" +-zgputs() { printf %s\\n "$@" ;} +-zgpute() { printf %s\\n "-- zgen: $*" >&2 ;} + +-zginit() { -zgputs "$*" >> "${ZGEN_INIT}" ;} + if [[ -z "${ZGEN_DIR}" ]]; then ZGEN_DIR="${HOME}/.zgen" @@ -12,6 +16,18 @@ if [[ -z "${ZGEN_INIT}" ]]; then ZGEN_INIT="${ZGEN_DIR}/init.zsh" fi +# The user can explicitly disable Zgen attempting to invoke `compinit`, or it +# will be automatically disabled if `compinit` appears to have already been +# invoked. +if [[ -z "${ZGEN_AUTOLOAD_COMPINIT}" && -z "${(t)_comps}" ]]; then + ZGEN_AUTOLOAD_COMPINIT=1 +fi + +if [[ -n "${ZGEN_CUSTOM_COMPDUMP}" ]]; then + ZGEN_COMPINIT_DIR_FLAG="-d ${(q-)ZGEN_CUSTOM_COMPDUMP}" + ZGEN_COMPINIT_FLAGS="${ZGEN_COMPINIT_DIR_FLAG} ${ZGEN_COMPINIT_FLAGS}" +fi + if [[ -z "${ZGEN_LOADED}" ]]; then ZGEN_LOADED=() fi @@ -60,15 +76,15 @@ if [[ -z "${ZGEN_PREZTO_BRANCH}" ]]; then ZGEN_PREZTO_BRANCH=master fi +autoload -U regexp-replace -zgen-encode-url () { # Remove characters from a url that don't work well in a filename. # Inspired by -anti-get-clone-dir() method from antigen. - autoload -U regexp-replace local url="${1}" regexp-replace url '/' '-SLASH-' regexp-replace url ':' '-COLON-' regexp-replace url '\|' '-PIPE-' - echo $url + -zgputs "$url" } -zgen-get-clone-dir() { @@ -76,7 +92,7 @@ fi local branch="${2:-master}" if [[ -e "${repo}/.git" ]]; then - echo "${ZGEN_DIR}/local/$(basename ${repo})-${branch}" + -zgputs "${ZGEN_DIR}/local/$(basename ${repo})-${branch}" else # Repo directory will be location/reponame local reponame="$(basename ${repo})" @@ -84,7 +100,7 @@ fi # work well in a filename. local location="$(-zgen-encode-url $(dirname ${repo}))" repo="${location}/${reponame}" - echo "${ZGEN_DIR}/${repo}-${branch}" + -zgputs "${ZGEN_DIR}/${repo}-${branch}" fi } @@ -92,7 +108,7 @@ fi local repo="${1}" if [[ -e "${repo}/.git" ]]; then - echo "${repo}" + -zgputs "${repo}" else # Sourced from antigen url resolution logic. # https://github.com/zsh-users/antigen/blob/master/antigen.zsh @@ -105,7 +121,7 @@ fi ]]; then repo="https://github.com/${repo%.git}.git" fi - echo "${repo}" + -zgputs "${repo}" fi } @@ -133,16 +149,14 @@ zgen-clone() { -zgen-source() { local file="${1}" - source "${file}" - - # Add to ZGEN_LOADED array if not present if [[ ! "${ZGEN_LOADED[@]}" =~ "${file}" ]]; then ZGEN_LOADED+=("${file}") - fi + source "${file}" - completion_path="$(dirname ${file})" + completion_path="$(dirname ${file})" - -zgen-add-to-fpath "${completion_path}" + -zgen-add-to-fpath "${completion_path}" + fi } -zgen-prezto-option(){ @@ -190,7 +204,7 @@ zgen-init() { } zgen-reset() { - echo "zgen: Deleting ${ZGEN_INIT}" + -zgpute 'Deleting `'"${ZGEN_INIT}"'` ...' if [[ -f "${ZGEN_INIT}" ]]; then rm "${ZGEN_INIT}" fi @@ -198,7 +212,7 @@ zgen-reset() { zgen-update() { for repo in "${ZGEN_DIR}"/*/*; do - echo "Updating ${repo}" + -zgpute "Updating '${repo}' ..." (cd "${repo}" \ && git pull \ && git submodule update --recursive) @@ -207,107 +221,127 @@ zgen-update() { } zgen-save() { - echo "zgen: Creating ${ZGEN_INIT}" + -zgpute 'Creating `'"${ZGEN_INIT}"'` ...' - echo "#" >! "${ZGEN_INIT}" - echo "# Generated by zgen." >> "${ZGEN_INIT}" - echo "# This file will be overwritten the next time you run zgen save" >> "${ZGEN_INIT}" - echo >> "${ZGEN_INIT}" - echo "ZSH=$(-zgen-get-zsh)" >> "${ZGEN_INIT}" + -zgputs "# {{{" >! "${ZGEN_INIT}" + -zginit "# Generated by zgen." + -zginit "# This file will be overwritten the next time you run zgen save!" + -zginit "" + -zginit "ZSH=$(-zgen-get-zsh)" if [[ ${ZGEN_USE_PREZTO} == 1 ]]; then - echo >> "${ZGEN_INIT}" - echo "# init prezto" >> "${ZGEN_INIT}" + -zginit "" + -zginit "# ### Prezto initialization" for option in "${ZGEN_PREZTO_OPTIONS[@]}"; do - echo "${option}" >> "${ZGEN_INIT}" + -zginit "${option}" done fi - echo >> "${ZGEN_INIT}" - echo "#" >> "${ZGEN_INIT}" + -zginit "" + -zginit "# ### General modules" for file in "${ZGEN_LOADED[@]}"; do - echo "source \"${(q)file}\"" >> "${ZGEN_INIT}" + -zginit 'source "'"${(q)file}"\" done - # Set up fpath - echo >> "${ZGEN_INIT}" - echo "#" >> "${ZGEN_INIT}" - echo "# Add our plugins and completions to fpath">> "${ZGEN_INIT}" - echo "#" >> "${ZGEN_INIT}" - echo "fpath=(${(q)ZGEN_COMPLETIONS[@]} \${fpath})" >> "${ZGEN_INIT}" - - # check for file changes - if [[ ! -z ${ZGEN_RESET_ON_CHANGE} ]]; then - echo >> "${ZGEN_INIT}" - echo "# check for file changes" >> "${ZGEN_INIT}" - for file in ${ZGEN_RESET_ON_CHANGE}; do - CHANGESHA=`shasum -a 256 ${file}` - echo "if [[ \"\`shasum -a 256 ${file}\`\" != \"$CHANGESHA\" ]]; then" >> "${ZGEN_INIT}" - echo " echo Changed file ${file}, resetting zgen" >> "${ZGEN_INIT}" - echo " zgen reset" >> "${ZGEN_INIT}" - echo -n "el" >> "${ZGEN_INIT}" - done - echo "se " >> "${ZGEN_INIT}" - echo " ;" >> "${ZGEN_INIT}" - echo "fi" >> "${ZGEN_INIT}" + # Set up fpath, load completions + # NOTE: This *intentionally* doesn't use ${ZGEN_COMPINIT_FLAGS}; the only + # available flags are meaningless in the presence of `-C`. + -zginit "" + -zginit "# ### Plugins & Completions" + -zginit 'fpath=('"${(@q)ZGEN_COMPLETIONS}"' ${fpath})' + if [[ ${ZGEN_AUTOLOAD_COMPINIT} == 1 ]]; then + -zginit "" + -zginit 'autoload -Uz compinit && \' + -zginit ' compinit -C '"${ZGEN_COMPINIT_DIR_FLAG}" + fi + + # Check for file changes + if [[ ! -z "${ZGEN_RESET_ON_CHANGE}" ]]; then + -zginit "" + -zginit "# ### Recompilation triggers" + + local ages="$(stat -Lc "%Y" 2>/dev/null $ZGEN_RESET_ON_CHANGE || \ + stat -Lf "%m" 2>/dev/null $ZGEN_RESET_ON_CHANGE)" + local shas="$(shasum -a 256 ${ZGEN_RESET_ON_CHANGE})" + + -zginit "read -rd '' ages </dev/null $ZGEN_RESET_ON_CHANGE || \' + -zginit ' stat -Lf "%m" $ZGEN_RESET_ON_CHANGE)" != "$ages" \' + -zginit ' && "$(shasum -a 256 $ZGEN_RESET_ON_CHANGE)" != "$shas" ]]; then' + -zginit ' printf %s\\n '\''-- zgen: Files in $ZGEN_RESET_ON_CHANGE changed; resetting `init.zsh`...'\' + -zginit ' zgen reset' + -zginit 'fi' fi # load prezto modules if [[ ${ZGEN_USE_PREZTO} == 1 ]]; then - echo >> "${ZGEN_INIT}" - echo "# init prezto" >> "${ZGEN_INIT}" - echo -n "pmodload " >> "${ZGEN_INIT}" + -zginit "" + -zginit "# ### Prezto modules" + printf %s\\n "pmodload" >> "${ZGEN_INIT}" for module in "${ZGEN_PREZTO_LOAD[@]}"; do - echo -n "${module} " >> "${ZGEN_INIT}" + printf %s\\n " ${module}" >> "${ZGEN_INIT}" done - echo >> "${ZGEN_INIT}" fi - zgen-apply --verbose + -zginit "" + -zginit "# }}}" + + zgen-apply } zgen-apply() { - fpath=(${(q)ZGEN_COMPLETIONS[@]} ${fpath}) - [[ "$1" == --verbose ]] && echo "zgen: Creating ${ZGEN_DIR}/zcompdump" - compinit -d "${ZGEN_DIR}/zcompdump" + fpath=(${(q-)ZGEN_COMPLETIONS[@]} ${fpath}) + + if [[ ${ZGEN_AUTOLOAD_COMPINIT} == 1 ]]; then + -zgpute "Initializing completions ..." + + autoload -Uz compinit && \ + compinit $ZGEN_COMPINIT_FLAGS + fi } zgen-completions() { - echo "zgen: 'completions' is deprecated, please use 'load' instead" + -zgpute '`zgen completions` is deprecated, please use `zgen load` instead' zgen-load "${@}" } -zgen-path-contains() { - setopt localoptions nonomatch nocshnullglob nonullglob; - [ -e "$1"/*"$2"(.,@[1]) ] + setopt localoptions nonomatch nocshnullglob nonullglob; + [ -e "$1"/*"$2"(.,@[1]) ] } -zgen-get-zsh(){ if [[ ${ZGEN_USE_PREZTO} == 1 ]]; then - echo "$(-zgen-get-clone-dir "$ZGEN_PREZTO_REPO" "$ZGEN_PREZTO_BRANCH")" + -zgputs "$(-zgen-get-clone-dir "$ZGEN_PREZTO_REPO" "$ZGEN_PREZTO_BRANCH")" else - echo "$(-zgen-get-clone-dir "$ZGEN_OH_MY_ZSH_REPO" "$ZGEN_OH_MY_ZSH_BRANCH")" + -zgputs "$(-zgen-get-clone-dir "$ZGEN_OH_MY_ZSH_REPO" "$ZGEN_OH_MY_ZSH_BRANCH")" fi } zgen-load() { if [[ "$#" == 0 ]]; then - echo "zgen: 'load' requires at least one parameter" - echo "usage: zgen load [location] [branch]" + -zgpute '`load` requires at least one parameter:' + -zgpute '`zgen load [location] [branch]`' elif [[ "$#" == 1 && ("${1[1]}" == '/' || "${1[1]}" == '.' ) ]]; then - local location="${1}" + local location="${1}" else - local repo="${1}" - local file="${2}" - local branch="${3:-master}" - local dir="$(-zgen-get-clone-dir ${repo} ${branch})" - local location="${dir}/${file}" - location=${location%/} - - # clone repo if not present - if [[ ! -d "${dir}" ]]; then - zgen-clone "${repo}" "${branch}" - fi + local repo="${1}" + local file="${2}" + local branch="${3:-master}" + local dir="$(-zgen-get-clone-dir ${repo} ${branch})" + local location="${dir}/${file}" + location=${location%/} + + # clone repo if not present + if [[ ! -d "${dir}" ]]; then + zgen-clone "${repo}" "${branch}" + fi fi # source the file @@ -346,9 +380,9 @@ zgen-load() { else if [[ -d ${dir:-$location} ]]; then - echo "zgen: Failed to load ${dir:-$location} -- ${file}" + -zgpute "Failed to load ${dir:-$location} -- ${file}" else - echo "zgen: Failed to load ${dir:-$location}" + -zgpute "Failed to load ${dir:-$location}" fi fi } @@ -377,16 +411,18 @@ zgen-list() { if [[ -f "${ZGEN_INIT}" ]]; then cat "${ZGEN_INIT}" else - echo "Zgen init.zsh missing, please use zgen save and then restart your shell." + -zgpute '`init.zsh` missing, please use `zgen save` and then restart your shell.' + return 1 fi } zgen-selfupdate() { if [[ -e "${ZGEN_SOURCE}/.git" ]]; then (cd "${ZGEN_SOURCE}" \ - && git pull) + && git pull) \ + && zgen reset else - echo "zgen is not running from a git repository, so it is not possible to selfupdate" + -zgpute "Not running from a git repository; cannot automatically update." return 1 fi } @@ -418,7 +454,7 @@ zgen-prezto() { elif [[ $# == 1 ]]; then local module=${file} if [[ -z ${file} ]]; then - echo "Please specify which module to load using 'zgen prezto '" + -zgpute 'Please specify which module to load using `zgen prezto `' return 1 fi -zgen-prezto-load "'$module'" @@ -432,30 +468,32 @@ zgen-prezto() { } zgen-pmodule() { - local repo="${1}" - local branch="${2:-master}" + local repo="${1}" + local branch="${2:-master}" - local dir="$(-zgen-get-clone-dir ${repo} ${branch})" + local dir="$(-zgen-get-clone-dir ${repo} ${branch})" - # clone repo if not present - if [[ ! -d "${dir}" ]]; then - zgen-clone "${repo}" "${branch}" - fi + # clone repo if not present + if [[ ! -d "${dir}" ]]; then + zgen-clone "${repo}" "${branch}" + fi - local module=$(basename ${repo}) + local module=$(basename ${repo}) - local preztodir="${ZDOTDIR:-$HOME}/.zprezto/modules/${module}" - if [[ ! -h ${preztodir} ]]; then - ln -s $dir ${preztodir} - fi + local preztodir="${ZDOTDIR:-$HOME}/.zprezto/modules/${module}" + if [[ ! -h ${preztodir} ]]; then + ln -s $dir ${preztodir} + fi - -zgen-prezto-load "'${module}'" + -zgen-prezto-load "'${module}'" } zgen() { local cmd="${1}" if [[ -z "${cmd}" ]]; then - echo "usage: zgen [clone|completions|list|load|oh-my-zsh|pmodule|prezto|reset|save|selfupdate|update]" + -zgputs 'usage: `zgen [command | instruction] [options]`' + -zgputs " commands: list, saved, reset, clone, update, selfupdate" + -zgputs " instructions: load, oh-my-zsh, pmodule, prezto, save, apply" return 1 fi @@ -464,16 +502,11 @@ zgen() { if functions "zgen-${cmd}" > /dev/null ; then "zgen-${cmd}" "${@}" else - echo "zgen: command not found: ${cmd}" + -zgpute 'Command not found: `'"${cmd}"\` + return 1 fi } ZSH=$(-zgen-get-zsh) zgen-init fpath=($ZGEN_SOURCE $fpath) - -ZGEN_AUTOLOAD_COMPINIT=${ZGEN_AUTOLOAD_COMPINIT:-true} -if $ZGEN_AUTOLOAD_COMPINIT; then - autoload -U compinit - compinit -d "${ZGEN_DIR}/zcompdump" -fi