diff --git a/README.md b/README.md index 9e56b48..e6499d1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Zsh IMproved FrameWork
- +
@@ -53,50 +53,40 @@ read about the [available modules] and tweak your `.zshrc` file. If you have a different shell framework installed (like oh-my-zsh or prezto), *uninstall those first to prevent conflicts*. -Settings --------- +Usage +----- -### Enabled modules +### zmodule -Use the following zstyle to select the modules you would like enabled: +Add `zmodule` calls to your `.zimrc` file to define the modules to be loaded. +The modules are loaded in the same order they are defined. Add: - zstyle ':zim' modules 'first-module' 'second-module' 'third-module' + zmodule [-n|--name ] [options] -You can provide as many module names as you want. Modules are sourced in the -order given. +where <url> is the required repository URL or path. The following formats +are equivalent: *name*, zimfw/*name*, https://github.com/zimfw/name.git -By default, a module is installed from the Zim repository with the same name. -For example, the `utility` module is installed from -https://github.com/zimfw/utility.git if no additional module configuration is provided. +By default, the module name is the last component in the <url>. Use the +`-n`|`--name` <module_name> option to set a custom module name. -### Module customization +#### Repository options -To configure a module, use the following format, where the style name is the -module name: +* `-b`|`--branch` <branch_name>: Use specified branch when installing and updating the module. Overrides the tag option. Default: `master` +* `-t`|`--tag` <tag_name>: Use specified tag when installing and updating the module. Overrides the branch option. +* `-z`|`--frozen`: Don't install or update the module - zstyle ':zim:module' ['frozen' yes] ['url' ] ['branch' |'tag' ] +#### Startup options -| Key | Description | Default value | -| --- | ----------- | ------------- | -| frozen | If set to yes, then module will not be cleaned, installed or updated. It can still be freely enabled or disabled with the modules style. | no | -| url | Repository URL or path. The following formats are equivalent: *module*, zimfw/*module*, https://github.com/zimfw/module.git | *module* | -| branch | Repository branch. | master | -| tag | Repository tag. Overrides branch, if one was specified. | | +* `-f`|`--fpath` <path>: Add specified path to `fpath`. The path is relative to the module root directory. Default: `functions`, if the subdirectory exists +* `-a`|`--autoload` <function_name>: Autoload specified function. Default: all valid names inside all the module specified `fpath` paths +* `-s`|`--source` <file_path>: Source specified file. The file path is relative to the module root directory. Default: the file with largest size matching `{init.zsh|module_name.{zsh|plugin.zsh|zsh-theme|sh}}`, if any exists +* `-d`|`--disabled`: Don't use or clean the module -Choose the module name wisely. The first file found in the module root directory, -in the following order, will be sourced: -init.zsh, *module*.zsh, *module*.plugin.zsh, *module*.zsh.theme, *module*.sh +### zimfw -For example, [mafredi/zsh-async](https://github.com/mafredri/zsh-async) must be -configured as a module called `async`: +To install new defined modules, run: - zstyle ':zim:module' async 'url' 'mafredri/zsh-async' - -because it has an async.zsh initialization file. Then to be enabled, `async` must -be added to the modules style. - -Updating --------- + zimfw install To update your modules, run: @@ -114,8 +104,8 @@ Uninstalling The best way to remove Zim is to manually delete `~/.zim`, `~/.zimrc`, and remove the initialization lines from your `~/.zshrc` and `~/.zlogin`. -[history-substring-search]: https://i.eriner.me/zim_history-substring-search.gif -[syntax-highlighting]: https://i.eriner.me/zim_syntax-highlighting.gif +[history-substring-search]: https://zimfw.github.io/images/zim_history-substring-search.gif +[syntax-highlighting]: https://zimfw.github.io/images/zim_syntax-highlighting.gif [blazing speed]: https://github.com/zimfw/zimfw/wiki/Speed [available modules]: https://github.com/zimfw/zimfw/wiki/Modules [themes wiki page]: https://github.com/zimfw/zimfw/wiki/Themes diff --git a/src/stage1/20_guard.zsh.erb b/src/stage1/20_guard.zsh.erb index b368d0e..d46518d 100644 --- a/src/stage1/20_guard.zsh.erb +++ b/src/stage1/20_guard.zsh.erb @@ -1,4 +1,4 @@ autoload -Uz is-at-least && if ! is-at-least <%= min_zsh_version %>; then - print -u2 "init: error starting Zim: You're using Zsh version ${ZSH_VERSION} and versions < <%= min_zsh_version %> are not supported. Update your Zsh." + print -u2 -R "${0}: Error starting Zim. You're using Zsh version ${ZSH_VERSION} and versions < <%= min_zsh_version %> are not supported. Update your Zsh." return 1 fi diff --git a/src/stage1/30_init.zsh.erb b/src/stage1/30_init.zsh.erb index 4f791a0..0e62c46 100644 --- a/src/stage1/30_init.zsh.erb +++ b/src/stage1/30_init.zsh.erb @@ -1,46 +1,2 @@ # Define Zim location -: ${ZIM_HOME=${0:h}} - -# Source user configuration -[[ -f <%= home %>/.zimrc ]] && source <%= home %>/.zimrc - -# Set input mode before loading modules -if zstyle -t ':zim:input' mode 'vi'; then - bindkey -v -else - bindkey -e -fi - -# Autoload enabled modules' functions -() { - local zfunction - local -a zmodules - zstyle -a ':zim' modules 'zmodules' - - setopt LOCAL_OPTIONS EXTENDED_GLOB - fpath=(${ZIM_HOME}/modules/${^zmodules}/functions(/FN) ${fpath}) - for zfunction in ${ZIM_HOME}/modules/${^zmodules}/functions/<%= functions_glob %>(-.N:t); do - autoload -Uz ${zfunction} - done -} - -# Source enabled modules' init scripts -() { - local zmodule zdir zfile - local -a zmodules - zstyle -a ':zim' modules 'zmodules' - - for zmodule in ${zmodules}; do - zdir=${ZIM_HOME}/modules/${zmodule} - if [[ ! -d ${zdir} ]]; then - print -u2 "init: module ${zmodule} not installed" - else - for zfile in ${zdir}/{init.zsh,${zmodule}.{zsh,plugin.zsh,zsh-theme,sh}}; do - if [[ -f ${zfile} ]]; then - source ${zfile} - break - fi - done - fi - done -} +: ${ZIM_HOME=${0:A:h}} diff --git a/src/stage1/50_zimfw_compile.zsh.erb b/src/stage1/50_zimfw_compile.zsh.erb index c2982a1..523d4e4 100644 --- a/src/stage1/50_zimfw_compile.zsh.erb +++ b/src/stage1/50_zimfw_compile.zsh.erb @@ -1,13 +1,9 @@ _zimfw_compile() { setopt LOCAL_OPTIONS EXTENDED_GLOB autoload -U zrecompile - - local zdir zfile - local -a zmodules - zstyle -a ':zim' modules 'zmodules' + local zdumpfile zdir zfile # Compile the completion cache; significant speedup - local zdumpfile zstyle -s ':zim:completion' dumpfile 'zdumpfile' || zdumpfile="<%= home %>/.zcompdump" if [[ -f ${zdumpfile} ]]; then zrecompile -p ${1} ${zdumpfile} || return 1 @@ -16,19 +12,19 @@ _zimfw_compile() { # Compile .zshrc zrecompile -p ${1} <%= home %>/.zshrc || return 1 - # Compile enabled modules' autoloaded functions - for zdir in ${ZIM_HOME}/modules/${^zmodules}/functions(/FN); do - zrecompile -p ${1} ${zdir}.zwc ${zdir}/<%= functions_glob %>(-.N) || return 1 + # Compile autoloaded functions + for zdir in ${fpath}; do + [[ ${zdir} == (.|..) || ${zdir} == (.|..)/* ]] && continue + if [[ -w ${zdir:h} ]]; then + zrecompile -p ${1} ${zdir}.zwc ${zdir}/^(*.*)(N-.) || return 1 + fi done - # Compile enabled modules' scripts - for zfile in ${ZIM_HOME}/modules/${^zmodules}/(^*test*/)#*.zsh{,-theme}(.NLk+1); do + # Compile scripts + for zfile in ${ZIM_HOME}/(^*test*/)#*.zsh{,-theme}(N-.); do zrecompile -p ${1} ${zfile} || return 1 done - # Compile this script - zrecompile -p ${1} ${ZIM_HOME}/<%= script_filename %> || return 1 - if [[ ${1} != -q ]]; then print -P '%F{green}✓%f Done with compile.' fi diff --git a/src/stage1/80_zimfw.zsh.erb b/src/stage1/80_zimfw.zsh.erb index f3647ba..64ea658 100644 --- a/src/stage1/80_zimfw.zsh.erb +++ b/src/stage1/80_zimfw.zsh.erb @@ -1,9 +1,4 @@ -zimfw() { - case ${1} in - compile|login-init) _zimfw_compile ${2} ;; - *) - source ${ZIM_HOME}/<%= script_filename %> <%= second_stage_guard %> - zimfw "${@}" - ;; - esac -} +if [[ ${1} == (compile|login-init) && ${2} == (|-q) ]]; then + _zimfw_compile ${2} + return +fi diff --git a/src/stage2/30_zimfw_build.zsh.erb b/src/stage2/30_zimfw_build.zsh.erb new file mode 100644 index 0000000..0b93951 --- /dev/null +++ b/src/stage2/30_zimfw_build.zsh.erb @@ -0,0 +1,26 @@ +_zimfw_build() { + () { + local -r ztarget=${ZIM_HOME}/init.zsh + if command cmp -s ${ztarget} ${1}; then + if (( ! _zquiet )); then + print -PR "%F{green}✓%f %B${ztarget}:%b Already up to date" + fi + else + if [[ -e ${ztarget} ]]; then + command mv -f ${ztarget}{,.old} || return 1 + fi + command mv -f ${1} ${ztarget} && \ + if (( ! _zquiet )); then + print -PR "%F{green}✓%f %B${ztarget}:%b Updated. Restart your terminal for changes to take effect." + fi + fi + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with build.' + fi + } =( + print -R "zimfw() { source ${ZIM_HOME}/<%= script_filename %> \"\${@}\" }" + (( ${#_zfpaths} )) && print -R 'fpath=('${_zfpaths:P}' ${fpath})' + (( ${#_zfunctions} )) && print -R 'autoload -Uz '${_zfunctions} + print -Rn ${(F):-source ${^_zscripts:P}} + ) +} diff --git a/src/stage2/30_zimfw_modules.zsh.erb b/src/stage2/30_zimfw_modules.zsh.erb deleted file mode 100644 index 60611ac..0000000 --- a/src/stage2/30_zimfw_modules.zsh.erb +++ /dev/null @@ -1,27 +0,0 @@ -_zimfw_modules() { - local zmodule zurl ztype zrev - local -a zmodules - local -A zoptions - zstyle -a ':zim' modules 'zmodules' - for zmodule in ${zmodules}; do - zstyle -a ':zim:module' ${zmodule} 'zoptions' - [[ ${zoptions[frozen]} == yes ]] && continue - zurl=${zoptions[url]:-${zmodule}} - if [[ ${zurl} != /* && ${zurl} != *@*:* ]]; then - # Count number of slashes - case ${#zurl//[^\/]/} in - 0) zurl="https://github.com/zimfw/${zurl}.git" ;; - 1) zurl="https://github.com/${zurl}.git" ;; - esac - fi - if [[ -n ${zoptions[tag]} ]]; then - ztype=tag - zrev=${zoptions[tag]} - else - ztype=branch - zrev=${zoptions[branch]:-master} - fi - # Cannot have an empty space at the EOL because this is read by xargs -L1 - print "'${ZIM_HOME}/modules/${zmodule}' '${zurl}' '${ztype}' '${zrev}'${1:+ ${1}}" - done -} diff --git a/src/stage2/30_zmodule.zsh.erb b/src/stage2/30_zmodule.zsh.erb new file mode 100644 index 0000000..51506bf --- /dev/null +++ b/src/stage2/30_zmodule.zsh.erb @@ -0,0 +1,119 @@ +zmodule() { + local -r zusage=" +Usage: %B${0}%b [%B-n%b|%B--name%b ] [options] + +Repository options: + %B-b%b|%B--branch%b Use specified branch when installing and updating the module + %B-t%b|%B--tag%b Use specified tag when installing and updating the module + %B-z%b|%B--frozen%b Don't install or update the module + +Startup options: + %B-f%b|%B--fpath%b Add specified path to fpath + %B-a%b|%B--autoload%b Autoload specified function + %B-s%b|%B--source%b Source specified file + %B-d%b|%B--disabled%b Don't use or clean the module +" + if [[ ${${funcfiletrace[1]%:*}:t} != .zimrc ]]; then + print -u2 -PR "%F{red}${0}: Must be called from <%= home %>/.zimrc%f"$'\n'${zusage} + return 1 + fi + if (( ! # )); then + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}: Missing zmodule url%f" + _zfailed=1 + return 1 + fi + setopt LOCAL_OPTIONS EXTENDED_GLOB + local zmodule=${1:t} zurl=${1} + local ztype=branch zrev=master + local -i zdisabled=0 zfrozen=0 + local -a zfpaths zfunctions zscripts + local zarg + if [[ ${zurl} =~ ^[^:/]+: ]]; then + zmodule=${zmodule%.git} + elif [[ ${zurl} != /* ]]; then + # Count number of slashes + case ${#zurl//[^\/]/} in + 0) zurl="https://github.com/zimfw/${zurl}.git" ;; + 1) zurl="https://github.com/${zurl}.git" ;; + esac + fi + shift + if [[ ${1} == (-n|--name) ]]; then + if (( # < 2 )); then + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}:%B${zmodule}:%b Missing argument for zmodule option ${1}%f" + _zfailed=1 + return 1 + fi + shift + zmodule=${1} + shift + fi + local -r zdir=${ZIM_HOME}/modules/${zmodule} + while (( # > 0 )); do + case ${1} in + -b|--branch|-t|--tag|-f|--fpath|-a|--autoload|-s|--source) + if (( # < 2 )); then + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}:%B${zmodule}:%b Missing argument for zmodule option ${1}%f" + _zfailed=1 + return 1 + fi + ;; + esac + case ${1} in + -b|--branch) + shift + ztype=branch + zrev=${1} + ;; + -t|--tag) + shift + ztype=tag + zrev=${1} + ;; + -z|--frozen) zfrozen=1 ;; + -f|--fpath) + shift + zarg=${1} + [[ ${zarg} != /* ]] && zarg=${zdir}/${zarg} + zfpaths+=(${zarg}) + ;; + -a|--autoload) + shift + zfunctions+=(${1}) + ;; + -s|--source) + shift + zarg=${1} + [[ ${zarg} != /* ]] && zarg=${zdir}/${zarg} + zscripts+=(${zarg}) + ;; + -d|--disabled) zdisabled=1 ;; + *) + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}:%B${zmodule}:%b Unknown zmodule option ${1}%f" + _zfailed=1 + return 1 + ;; + esac + shift + done + if (( zdisabled )); then + _zdisableds+=(${zmodule}) + else + (( ! ${#zfpaths} )) && zfpaths+=(${zdir}/functions(NF)) + if (( ! ${#zfunctions} )); then + # _* functions are autoloaded by compinit + # prompt_*_setup functions are autoloaded by promptinit + zfunctions+=(${^zfpaths}/^(*.*|_*|prompt_*_setup)(N-.:t)) + fi + if (( ! ${#zscripts} )); then + zscripts+=(${zdir}/(init.zsh|${zmodule:t}.(zsh|plugin.zsh|zsh-theme|sh))(NOL[1])) + fi + _zfpaths+=(${zfpaths}) + _zfunctions+=(${zfunctions}) + _zscripts+=(${zscripts}) + _zmodules+=(${zmodule}) + fi + if (( ! zfrozen )); then + _zmodules_xargs+=${zmodule}$'\0'${zdir}$'\0'${zurl}$'\0'${ztype}$'\0'${zrev}$'\0'${_zquiet}$'\0' + fi +} diff --git a/src/stage2/31_zimfw_source_zimrc.zsh.erb b/src/stage2/31_zimfw_source_zimrc.zsh.erb new file mode 100644 index 0000000..7232db2 --- /dev/null +++ b/src/stage2/31_zimfw_source_zimrc.zsh.erb @@ -0,0 +1,7 @@ +_zimfw_source_zimrc() { + local -i _zfailed=0 + if ! source <%= home %>/.zimrc || (( _zfailed )); then + print -u2 -PR "%F{red}✗ Failed to source <%= home %>/.zimrc%f" + return 1 + fi +} diff --git a/src/stage2/49_zimfw_clean_modules.zsh.erb b/src/stage2/49_zimfw_clean_modules.zsh.erb index 21b0c6b..a90c8c5 100644 --- a/src/stage2/49_zimfw_clean_modules.zsh.erb +++ b/src/stage2/49_zimfw_clean_modules.zsh.erb @@ -1,21 +1,14 @@ _zimfw_clean_modules() { - local zdir zmodule - local -a zmodules - local -A zoptions - # Source .zimrc to refresh zmodules - [[ -f <%= home %>/.zimrc ]] && source <%= home %>/.zimrc - zstyle -a ':zim' modules 'zmodules' - for zdir in ${ZIM_HOME}/modules/*(/N); do + local zopt zdir zmodule + (( ! _zquiet )) && zopt='-v' + for zdir in ${ZIM_HOME}/modules/*(N/); do zmodule=${zdir:t} - # If zmodules does not contain the zmodule - if (( ! ${zmodules[(I)${zmodule}]} )); then - zstyle -a ':zim:module' ${zmodule} 'zoptions' - [[ ${zoptions[frozen]} == yes ]] && continue - command rm -rf ${zdir} || return 1 - [[ ${1} != -q ]] && print ${zdir} + # If _zmodules and _zdisableds do not contain the zmodule + if (( ! ${_zmodules[(I)${zmodule}]} && ! ${_zdisableds[(I)${zmodule}]} )); then + command rm -rf ${zopt} ${zdir} || return 1 fi done - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f Done with clean-modules." + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with clean-modules.' fi } diff --git a/src/stage2/50_zimfw_clean_compiled.zsh.erb b/src/stage2/50_zimfw_clean_compiled.zsh.erb index 622fafc..84dcdf6 100644 --- a/src/stage2/50_zimfw_clean_compiled.zsh.erb +++ b/src/stage2/50_zimfw_clean_compiled.zsh.erb @@ -1,13 +1,18 @@ _zimfw_clean_compiled() { - setopt LOCAL_OPTIONS PIPE_FAIL - local find_opt rm_opt - if [[ ${1} != -q ]]; then - find_opt='-print' - rm_opt='-v' + local zopt_find zopt_rm zdir + if (( ! _zquiet )); then + zopt_find='-print' + zopt_rm='-v' fi - command find ${ZIM_HOME} \( -name '*.zwc' -o -name '*.zwc.old' \) -delete ${find_opt} || return 1 - command rm -f ${rm_opt} <%= home %>/.zshrc.zwc{,.old} || return 1 - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f Done with clean-compiled. Run %Bzimfw compile%b to re-compile." + for zdir in ${fpath}; do + [[ ${zdir} == (.|..) || ${zdir} == (.|..)/* ]] && continue + if [[ -w ${zdir:h} ]]; then + command rm -f ${zopt_rm} ${zdir}.zwc{,.old} || return 1 + fi + done + command find ${ZIM_HOME} \( -name '*.zwc' -o -name '*.zwc.old' \) -delete ${zopt_find} || return 1 + command rm -f ${zopt_rm} <%= home %>/.zshrc.zwc{,.old} || return 1 + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with clean-compiled. Run %Bzimfw compile%b to re-compile.' fi } diff --git a/src/stage2/50_zimfw_clean_dumpfile.zsh.erb b/src/stage2/50_zimfw_clean_dumpfile.zsh.erb index a34f77f..12c2fba 100644 --- a/src/stage2/50_zimfw_clean_dumpfile.zsh.erb +++ b/src/stage2/50_zimfw_clean_dumpfile.zsh.erb @@ -1,10 +1,9 @@ _zimfw_clean_dumpfile() { - setopt LOCAL_OPTIONS PIPE_FAIL - local zdumpfile zout zopt + local zdumpfile zopt zstyle -s ':zim:completion' dumpfile 'zdumpfile' || zdumpfile="<%= home %>/.zcompdump" - [[ ${1} != -q ]] && zopt='-v' + (( ! _zquiet )) && zopt='-v' command rm -f ${zopt} ${zdumpfile}{,.zwc{,.old}} || return 1 - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f Done with clean-dumpfile. Restart your terminal to dump an updated configuration." + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with clean-dumpfile. Restart your terminal to dump an updated configuration.' fi } diff --git a/src/stage2/50_zimfw_info.zsh.erb b/src/stage2/50_zimfw_info.zsh.erb index e52fd3f..6a8bf34 100644 --- a/src/stage2/50_zimfw_info.zsh.erb +++ b/src/stage2/50_zimfw_info.zsh.erb @@ -1,5 +1,5 @@ _zimfw_info() { print 'Zim version: <%= version %> (previous commit is <%= `git rev-parse --short HEAD | tr -d '\r\n'` %>)' - print "Zsh version: ${ZSH_VERSION}" - print "System info: $(command uname -a)" + print -R "Zsh version: ${ZSH_VERSION}" + print -R "System info: $(command uname -a)" } diff --git a/src/stage2/50_zimfw_upgrade.zsh.erb b/src/stage2/50_zimfw_upgrade.zsh.erb index f2a6d7b..4b1611c 100644 --- a/src/stage2/50_zimfw_upgrade.zsh.erb +++ b/src/stage2/50_zimfw_upgrade.zsh.erb @@ -1,20 +1,26 @@ _zimfw_upgrade() { - local zscript=${ZIM_HOME}/<%= script_filename %> - local zurl=https://raw.githubusercontent.com/zimfw/zimfw/develop/<%= script_filename %> - if (( ${+commands[wget]} )); then - command wget -nv ${1} -O ${zscript}.new ${zurl} || return 1 - else - command curl -fsSL -o ${zscript}.new ${zurl} || return 1 - fi - if command cmp -s ${zscript}{,.new}; then - command rm ${zscript}.new && \ - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f <%= script_filename %>: Already up to date." - fi - else - command mv ${zscript}{,.old} && command mv ${zscript}{.new,} && \ - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f <%= script_filename %>: upgraded. Restart your terminal for changes to take effect." - fi - fi + local -r zscript=${ZIM_HOME}/<%= script_filename %> + local -r zurl=https://raw.githubusercontent.com/zimfw/zimfw/develop/<%= script_filename %> + { + if (( ${+commands[wget]} )); then + command wget -nv ${1} -O ${zscript}.new ${zurl} || return 1 + else + command curl -fsSL -o ${zscript}.new ${zurl} || return 1 + fi + if command cmp -s ${zscript}{,.new}; then + if (( ! _zquiet )); then + print -P '%F{green}✓%f %B<%= script_filename %>:%b Already up to date' + fi + else + command mv -f ${zscript}{,.old} && command mv -f ${zscript}{.new,} && \ + if (( ! _zquiet )); then + print -P '%F{green}✓%f %B<%= script_filename %>:%b Upgraded. Restart your terminal for changes to take effect.' + fi + fi + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with upgrade.' + fi + } always { + command rm -f ${zscript}.new + } } diff --git a/src/stage2/80_zimfw.zsh.erb b/src/stage2/80_zimfw.zsh.erb index 4b163d9..0b08c98 100644 --- a/src/stage2/80_zimfw.zsh.erb +++ b/src/stage2/80_zimfw.zsh.erb @@ -1,25 +1,38 @@ -unfunction zimfw zimfw() { - local zusage="usage: ${0} [-q] -actions: - clean Clean all (see below). - clean-modules Clean unused modules. - clean-compiled Clean Zsh compiled files. - clean-dumpfile Clean completion dump file. - compile Compile Zsh files. - info Print Zim and system info. - install Install new modules. - update Update current modules. - upgrade Upgrade Zim. -options: - -q Quiet, only outputs errors." + local -r zusage=" +Usage: %B${0}%b [%B-q%b] - if [[ ${#} -ne 1 && ${2} != -q ]]; then - print -u2 ${zusage} - return 1 +Actions: + %Bbuild%b Build init script + %Bclean%b Clean all (see below) + %Bclean-modules%b Clean unused modules + %Bclean-compiled%b Clean Zsh compiled files + %Bclean-dumpfile%b Clean completion dump file + %Bcompile%b Compile Zsh files + %Binfo%b Print Zim and system info + %Binstall%b Install new modules + %Bupdate%b Update current modules + %Bupgrade%b Upgrade Zim + +Options: + %B-q%b Quiet, only outputs errors +" + local ztool _zmodules_xargs + local -a _zdisableds _zmodules _zfpaths _zfunctions _zscripts + local -i _zquiet=0 + if (( # > 2 )); then + print -u2 -PR "%F{red}${0}: Too many options%f"$'\n'${zusage} + return 1 + elif (( # > 1 )); then + case ${2} in + -q) _zquiet=1 ;; + *) + print -u2 -PR "%F{red}${0}: Unknown option ${2}%f"$'\n'${zusage} + return 1 + ;; + esac fi - local ztool case ${1} in install) ztool="<%= render_escaped("src/tools/install.zsh.erb") %>" @@ -30,27 +43,29 @@ options: esac case ${1} in + build) _zimfw_source_zimrc && _zimfw_build && _zimfw_compile ${2} ;; clean) - _zimfw_clean_modules ${2} && \ - _zimfw_clean_compiled ${2} && \ - _zimfw_clean_dumpfile ${2} + _zimfw_source_zimrc && \ + _zimfw_clean_modules && \ + _zimfw_clean_compiled && \ + _zimfw_clean_dumpfile ;; - clean-modules) _zimfw_clean_modules ${2} ;; - clean-compiled) _zimfw_clean_compiled ${2} ;; - clean-dumpfile) _zimfw_clean_dumpfile ${2} ;; - compile|login-init) _zimfw_compile ${2} ;; - info) _zimfw_info ${2} ;; + clean-modules) _zimfw_source_zimrc && _zimfw_clean_modules ;; + clean-compiled) _zimfw_clean_compiled ;; + clean-dumpfile) _zimfw_clean_dumpfile ;; + compile|login-init) _zimfw_source_zimrc && _zimfw_compile ${2} ;; + info) _zimfw_info ;; install|update) - # Source .zimrc to refresh zmodules - [[ -f <%= home %>/.zimrc ]] && source <%= home %>/.zimrc - _zimfw_modules ${2} | xargs -L1 -P10 zsh -c ${ztool} ${1} && \ - if [[ ${2} != -q ]]; then - print -P "%F{green}✓%f Done with ${1}. Restart your terminal for any changes to take effect." - fi + _zimfw_source_zimrc || return 1 + print -Rn ${_zmodules_xargs} | xargs -0 -n6 -P10 zsh -c ${ztool} ${1} && \ + if (( ! _zquiet )); then + print -PR "%F{green}✓%f Done with ${1}. Restart your terminal for any changes to take effect." + fi && \ + _zimfw_build && _zimfw_compile ${2} ;; - upgrade) _zimfw_upgrade ${2} ;; + upgrade) _zimfw_upgrade ;; *) - print -u2 ${zusage} + print -u2 -PR "%F{red}${0}: Unknown action ${1}%f"$'\n'${zusage} return 1 ;; esac diff --git a/src/tools/install.zsh.erb b/src/tools/install.zsh.erb index dff4a3c..e915d2a 100644 --- a/src/tools/install.zsh.erb +++ b/src/tools/install.zsh.erb @@ -1,20 +1,20 @@ # This runs in a new shell -DIR=${1} -URL=${2} -REV=${4} -OPT=${5} -MODULE=${DIR:t} -CLEAR_LINE="\033[2K\r" +readonly MODULE=${1} +readonly DIR=${2} +readonly URL=${3} +readonly REV=${5} +readonly -i QUIET=${6} +readonly CLEAR_LINE=$'\E[2K\r' if [[ -e ${DIR} ]]; then # Already exists return 0 fi -[[ ${OPT} != -q ]] && print -n "${CLEAR_LINE}Installing ${MODULE} …" +(( ! QUIET )) && print -Rn ${CLEAR_LINE}"Installing ${MODULE} …" if ERR=$(command git clone -b ${REV} -q --recursive ${URL} ${DIR} 2>&1); then - if [[ ${OPT} != -q ]]; then - print -P "${CLEAR_LINE}%F{green}✓%f ${MODULE}: Installed" + if (( ! QUIET )); then + print -PR ${CLEAR_LINE}"%F{green}✓%f %B${MODULE}:%b Installed" fi else - print -P "${CLEAR_LINE}%F{red}✗ ${MODULE}: Error%f\n${ERR}" + print -u2 -PR ${CLEAR_LINE}"%F{red}✗ %B${MODULE}:%b Error during git clone%f"$'\n'${(F):- ${(f)^ERR}} return 1 fi diff --git a/src/tools/update.zsh.erb b/src/tools/update.zsh.erb index 7bb023f..14a3e3a 100644 --- a/src/tools/update.zsh.erb +++ b/src/tools/update.zsh.erb @@ -1,14 +1,14 @@ # This runs in a new shell -DIR=${1} -URL=${2} -TYPE=${3} -REV=${4} -OPT=${5} -MODULE=${DIR:t} -CLEAR_LINE="\033[2K\r" -[[ ${OPT} != -q ]] && print -n "${CLEAR_LINE}Updating ${MODULE} …" -if ! cd ${DIR} 2>/dev/null; then - print -P "${CLEAR_LINE}%F{red}✗ ${MODULE}: Not installed%f" +readonly MODULE=${1} +readonly DIR=${2} +readonly URL=${3} +readonly TYPE=${4} +readonly REV=${5} +readonly -i QUIET=${6} +readonly CLEAR_LINE=$'\E[2K\r' +(( ! QUIET )) && print -Rn ${CLEAR_LINE}"Updating ${MODULE} …" +if ! builtin cd ${DIR} 2>/dev/null; then + print -u2 -PR ${CLEAR_LINE}"%F{red}✗ %B${MODULE}:%b Not installed%f" return 1 fi if [[ ${PWD} != $(command git rev-parse --show-toplevel 2>/dev/null) ]]; then @@ -16,32 +16,32 @@ if [[ ${PWD} != $(command git rev-parse --show-toplevel 2>/dev/null) ]]; then return 0 fi if [[ ${URL} != $(command git config --get remote.origin.url) ]]; then - print -P "${CLEAR_LINE}%F{red}✗ ${MODULE}: URL does not match. Expected ${URL}. Will not try to update.%f" + print -u2 -PR ${CLEAR_LINE}"%F{red}✗ %B${MODULE}:%b URL does not match. Expected ${URL}. Will not try to update.%f" return 1 fi if [[ ${TYPE} == tag ]]; then if [[ ${REV} == $(command git describe --tags --exact-match 2>/dev/null) ]]; then - [[ ${OPT} != -q ]] && print -P "${CLEAR_LINE}%F{green}✓%f ${MODULE}: Already up to date" + (( ! QUIET )) && print -PR ${CLEAR_LINE}"%F{green}✓%f %B${MODULE}:%b Already up to date" return 0 fi fi if ! ERR=$(command git fetch -pq origin ${REV} 2>&1); then - print -P "${CLEAR_LINE}%F{red}✗ ${MODULE}: Error (1)%f\n${ERR}" + print -u2 -PR ${CLEAR_LINE}"%F{red}✗ %B${MODULE}:%b Error during git fetch%f"$'\n'${(F):- ${(f)^ERR}} return 1 fi if [[ ${TYPE} == branch ]]; then - LOG_REV="${REV}@{u}" + LOG_REV=${REV}@{u} else LOG_REV=${REV} fi LOG=$(command git log --graph --color --format='%C(yellow)%h%C(reset) %s %C(cyan)(%cr)%C(reset)' ..${LOG_REV} 2>/dev/null) if ! ERR=$(command git checkout -q ${REV} -- 2>&1); then - print -P "${CLEAR_LINE}%F{red}✗ ${MODULE}: Error (2)%f\n${ERR}" + print -u2 -PR ${CLEAR_LINE}"%F{red}✗ %B${MODULE}:%b Error during git checkout%f"$'\n'${(F):- ${(f)^ERR}} return 1 fi if [[ ${TYPE} == branch ]]; then if ! OUT=$(command git merge --ff-only --no-progress -n 2>&1); then - print -P "${CLEAR_LINE}%F{red}✗ ${MODULE}: Error (3)%f\n${OUT}" + print -u2 -PR ${CLEAR_LINE}"%F{red}✗ %B${MODULE}:%b Error during git merge%f"$'\n'${(F):- ${(f)^OUT}} return 1 fi # keep just first line of OUT @@ -49,16 +49,12 @@ if [[ ${TYPE} == branch ]]; then else OUT="Updating to ${TYPE} ${REV}" fi -if [[ -n ${LOG} ]]; then - LOG_LINES=(' '${(f)^LOG}) - OUT="${OUT} -${(F)LOG_LINES}" -fi if ERR=$(command git submodule update --init --recursive -q 2>&1); then - if [[ ${OPT} != -q ]]; then - print -R "$(print -P "${CLEAR_LINE}%F{green}✓%f") ${MODULE}: ${OUT}" + if (( ! QUIET )); then + [[ -n ${LOG} ]] && OUT=${OUT}$'\n'${(F):- ${(f)^LOG}} + print -PR ${CLEAR_LINE}"%F{green}✓%f %B${MODULE}:%b ${OUT}" fi else - print -P "${CLEAR_LINE}%F{red}✗ ${MODULE}: Error (4)%f\n${ERR}" + print -u2 -PR ${CLEAR_LINE}"%F{red}✗ %B${MODULE}:%b Error during git submodule update%f"$'\n'${(F):- ${(f)^ERR}} return 1 fi diff --git a/src/zimfw.zsh.erb b/src/zimfw.zsh.erb index bd8d969..981ecd3 100644 --- a/src/zimfw.zsh.erb +++ b/src/zimfw.zsh.erb @@ -1,13 +1,11 @@ <%# coding: UTF-8 %><% class Zim - attr_reader :functions_glob, :home, :min_zsh_version, :script_filename, :second_stage_guard, :version + attr_reader :home, :min_zsh_version, :script_filename, :second_stage_guard, :version def initialize - @functions_glob = "^(_*|*.*|prompt_*_setup)" @home = "${ZDOTDIR:-${HOME}}" @min_zsh_version = "5.2" @script_filename = "zimfw.zsh" - @second_stage_guard = 2 @version = "1.0.0-SNAPSHOT" end @@ -20,21 +18,13 @@ class Zim end def render_escaped(filename) - render(filename).gsub(/(\$[^']|")/, "\\\\\\1") + render(filename).gsub(/(\$[^']|"|`)/, "\\\\\\1") end end zim = Zim.new %># AUTOMATICALLY GENERATED FILE. EDIT ONLY THE SOURCE FILES AND THEN COMPILE. # DO NOT DIRECTLY EDIT THIS FILE! -if (( ! # )); then - -# Stage 1 of sourcing this script -<%= zim.render_all("src/stage1/*.erb") %># Stage 1 done - -elif [[ ${1} == <%= zim.second_stage_guard %> ]]; then - -# Stage 2 of sourcing this script. Should only be done internally by zimfw. -<%= zim.render_all("src/stage2/*.erb") %># Stage 2 done - -fi +<%= zim.render_all("src/stage1/*.erb") %> +<%= zim.render_all("src/stage2/*.erb") %> +zimfw "${@}" diff --git a/zimfw.zsh b/zimfw.zsh index 68483e0..5afee7e 100644 --- a/zimfw.zsh +++ b/zimfw.zsh @@ -1,71 +1,20 @@ # AUTOMATICALLY GENERATED FILE. EDIT ONLY THE SOURCE FILES AND THEN COMPILE. # DO NOT DIRECTLY EDIT THIS FILE! -if (( ! # )); then - -# Stage 1 of sourcing this script autoload -Uz is-at-least && if ! is-at-least 5.2; then - print -u2 "init: error starting Zim: You're using Zsh version ${ZSH_VERSION} and versions < 5.2 are not supported. Update your Zsh." + print -u2 -R "${0}: Error starting Zim. You're using Zsh version ${ZSH_VERSION} and versions < 5.2 are not supported. Update your Zsh." return 1 fi # Define Zim location -: ${ZIM_HOME=${0:h}} - -# Source user configuration -[[ -f ${ZDOTDIR:-${HOME}}/.zimrc ]] && source ${ZDOTDIR:-${HOME}}/.zimrc - -# Set input mode before loading modules -if zstyle -t ':zim:input' mode 'vi'; then - bindkey -v -else - bindkey -e -fi - -# Autoload enabled modules' functions -() { - local zfunction - local -a zmodules - zstyle -a ':zim' modules 'zmodules' - - setopt LOCAL_OPTIONS EXTENDED_GLOB - fpath=(${ZIM_HOME}/modules/${^zmodules}/functions(/FN) ${fpath}) - for zfunction in ${ZIM_HOME}/modules/${^zmodules}/functions/^(_*|*.*|prompt_*_setup)(-.N:t); do - autoload -Uz ${zfunction} - done -} - -# Source enabled modules' init scripts -() { - local zmodule zdir zfile - local -a zmodules - zstyle -a ':zim' modules 'zmodules' - - for zmodule in ${zmodules}; do - zdir=${ZIM_HOME}/modules/${zmodule} - if [[ ! -d ${zdir} ]]; then - print -u2 "init: module ${zmodule} not installed" - else - for zfile in ${zdir}/{init.zsh,${zmodule}.{zsh,plugin.zsh,zsh-theme,sh}}; do - if [[ -f ${zfile} ]]; then - source ${zfile} - break - fi - done - fi - done -} +: ${ZIM_HOME=${0:A:h}} _zimfw_compile() { setopt LOCAL_OPTIONS EXTENDED_GLOB autoload -U zrecompile - - local zdir zfile - local -a zmodules - zstyle -a ':zim' modules 'zmodules' + local zdumpfile zdir zfile # Compile the completion cache; significant speedup - local zdumpfile zstyle -s ':zim:completion' dumpfile 'zdumpfile' || zdumpfile="${ZDOTDIR:-${HOME}}/.zcompdump" if [[ -f ${zdumpfile} ]]; then zrecompile -p ${1} ${zdumpfile} || return 1 @@ -74,198 +23,332 @@ _zimfw_compile() { # Compile .zshrc zrecompile -p ${1} ${ZDOTDIR:-${HOME}}/.zshrc || return 1 - # Compile enabled modules' autoloaded functions - for zdir in ${ZIM_HOME}/modules/${^zmodules}/functions(/FN); do - zrecompile -p ${1} ${zdir}.zwc ${zdir}/^(_*|*.*|prompt_*_setup)(-.N) || return 1 + # Compile autoloaded functions + for zdir in ${fpath}; do + [[ ${zdir} == (.|..) || ${zdir} == (.|..)/* ]] && continue + if [[ -w ${zdir:h} ]]; then + zrecompile -p ${1} ${zdir}.zwc ${zdir}/^(*.*)(N-.) || return 1 + fi done - # Compile enabled modules' scripts - for zfile in ${ZIM_HOME}/modules/${^zmodules}/(^*test*/)#*.zsh{,-theme}(.NLk+1); do + # Compile scripts + for zfile in ${ZIM_HOME}/(^*test*/)#*.zsh{,-theme}(N-.); do zrecompile -p ${1} ${zfile} || return 1 done - # Compile this script - zrecompile -p ${1} ${ZIM_HOME}/zimfw.zsh || return 1 - if [[ ${1} != -q ]]; then print -P '%F{green}✓%f Done with compile.' fi } -zimfw() { - case ${1} in - compile|login-init) _zimfw_compile ${2} ;; - *) - source ${ZIM_HOME}/zimfw.zsh 2 - zimfw "${@}" - ;; - esac -} -# Stage 1 done +if [[ ${1} == (compile|login-init) && ${2} == (|-q) ]]; then + _zimfw_compile ${2} + return +fi -elif [[ ${1} == 2 ]]; then - -# Stage 2 of sourcing this script. Should only be done internally by zimfw. -_zimfw_modules() { - local zmodule zurl ztype zrev - local -a zmodules - local -A zoptions - zstyle -a ':zim' modules 'zmodules' - for zmodule in ${zmodules}; do - zstyle -a ':zim:module' ${zmodule} 'zoptions' - [[ ${zoptions[frozen]} == yes ]] && continue - zurl=${zoptions[url]:-${zmodule}} - if [[ ${zurl} != /* && ${zurl} != *@*:* ]]; then - # Count number of slashes - case ${#zurl//[^\/]/} in - 0) zurl="https://github.com/zimfw/${zurl}.git" ;; - 1) zurl="https://github.com/${zurl}.git" ;; - esac - fi - if [[ -n ${zoptions[tag]} ]]; then - ztype=tag - zrev=${zoptions[tag]} +_zimfw_build() { + () { + local -r ztarget=${ZIM_HOME}/init.zsh + if command cmp -s ${ztarget} ${1}; then + if (( ! _zquiet )); then + print -PR "%F{green}✓%f %B${ztarget}:%b Already up to date" + fi else - ztype=branch - zrev=${zoptions[branch]:-master} + if [[ -e ${ztarget} ]]; then + command mv -f ${ztarget}{,.old} || return 1 + fi + command mv -f ${1} ${ztarget} && \ + if (( ! _zquiet )); then + print -PR "%F{green}✓%f %B${ztarget}:%b Updated. Restart your terminal for changes to take effect." + fi fi - # Cannot have an empty space at the EOL because this is read by xargs -L1 - print "'${ZIM_HOME}/modules/${zmodule}' '${zurl}' '${ztype}' '${zrev}'${1:+ ${1}}" + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with build.' + fi + } =( + print -R "zimfw() { source ${ZIM_HOME}/zimfw.zsh \"\${@}\" }" + (( ${#_zfpaths} )) && print -R 'fpath=('${_zfpaths:P}' ${fpath})' + (( ${#_zfunctions} )) && print -R 'autoload -Uz '${_zfunctions} + print -Rn ${(F):-source ${^_zscripts:P}} + ) +} + +zmodule() { + local -r zusage=" +Usage: %B${0}%b [%B-n%b|%B--name%b ] [options] + +Repository options: + %B-b%b|%B--branch%b Use specified branch when installing and updating the module + %B-t%b|%B--tag%b Use specified tag when installing and updating the module + %B-z%b|%B--frozen%b Don't install or update the module + +Startup options: + %B-f%b|%B--fpath%b Add specified path to fpath + %B-a%b|%B--autoload%b Autoload specified function + %B-s%b|%B--source%b Source specified file + %B-d%b|%B--disabled%b Don't use or clean the module +" + if [[ ${${funcfiletrace[1]%:*}:t} != .zimrc ]]; then + print -u2 -PR "%F{red}${0}: Must be called from ${ZDOTDIR:-${HOME}}/.zimrc%f"$'\n'${zusage} + return 1 + fi + if (( ! # )); then + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}: Missing zmodule url%f" + _zfailed=1 + return 1 + fi + setopt LOCAL_OPTIONS EXTENDED_GLOB + local zmodule=${1:t} zurl=${1} + local ztype=branch zrev=master + local -i zdisabled=0 zfrozen=0 + local -a zfpaths zfunctions zscripts + local zarg + if [[ ${zurl} =~ ^[^:/]+: ]]; then + zmodule=${zmodule%.git} + elif [[ ${zurl} != /* ]]; then + # Count number of slashes + case ${#zurl//[^\/]/} in + 0) zurl="https://github.com/zimfw/${zurl}.git" ;; + 1) zurl="https://github.com/${zurl}.git" ;; + esac + fi + shift + if [[ ${1} == (-n|--name) ]]; then + if (( # < 2 )); then + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}:%B${zmodule}:%b Missing argument for zmodule option ${1}%f" + _zfailed=1 + return 1 + fi + shift + zmodule=${1} + shift + fi + local -r zdir=${ZIM_HOME}/modules/${zmodule} + while (( # > 0 )); do + case ${1} in + -b|--branch|-t|--tag|-f|--fpath|-a|--autoload|-s|--source) + if (( # < 2 )); then + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}:%B${zmodule}:%b Missing argument for zmodule option ${1}%f" + _zfailed=1 + return 1 + fi + ;; + esac + case ${1} in + -b|--branch) + shift + ztype=branch + zrev=${1} + ;; + -t|--tag) + shift + ztype=tag + zrev=${1} + ;; + -z|--frozen) zfrozen=1 ;; + -f|--fpath) + shift + zarg=${1} + [[ ${zarg} != /* ]] && zarg=${zdir}/${zarg} + zfpaths+=(${zarg}) + ;; + -a|--autoload) + shift + zfunctions+=(${1}) + ;; + -s|--source) + shift + zarg=${1} + [[ ${zarg} != /* ]] && zarg=${zdir}/${zarg} + zscripts+=(${zarg}) + ;; + -d|--disabled) zdisabled=1 ;; + *) + print -u2 -PR "%F{red}✗ ${funcfiletrace[1]}:%B${zmodule}:%b Unknown zmodule option ${1}%f" + _zfailed=1 + return 1 + ;; + esac + shift done + if (( zdisabled )); then + _zdisableds+=(${zmodule}) + else + (( ! ${#zfpaths} )) && zfpaths+=(${zdir}/functions(NF)) + if (( ! ${#zfunctions} )); then + # _* functions are autoloaded by compinit + # prompt_*_setup functions are autoloaded by promptinit + zfunctions+=(${^zfpaths}/^(*.*|_*|prompt_*_setup)(N-.:t)) + fi + if (( ! ${#zscripts} )); then + zscripts+=(${zdir}/(init.zsh|${zmodule:t}.(zsh|plugin.zsh|zsh-theme|sh))(NOL[1])) + fi + _zfpaths+=(${zfpaths}) + _zfunctions+=(${zfunctions}) + _zscripts+=(${zscripts}) + _zmodules+=(${zmodule}) + fi + if (( ! zfrozen )); then + _zmodules_xargs+=${zmodule}$'\0'${zdir}$'\0'${zurl}$'\0'${ztype}$'\0'${zrev}$'\0'${_zquiet}$'\0' + fi +} + +_zimfw_source_zimrc() { + local -i _zfailed=0 + if ! source ${ZDOTDIR:-${HOME}}/.zimrc || (( _zfailed )); then + print -u2 -PR "%F{red}✗ Failed to source ${ZDOTDIR:-${HOME}}/.zimrc%f" + return 1 + fi } _zimfw_clean_modules() { - local zdir zmodule - local -a zmodules - local -A zoptions - # Source .zimrc to refresh zmodules - [[ -f ${ZDOTDIR:-${HOME}}/.zimrc ]] && source ${ZDOTDIR:-${HOME}}/.zimrc - zstyle -a ':zim' modules 'zmodules' - for zdir in ${ZIM_HOME}/modules/*(/N); do + local zopt zdir zmodule + (( ! _zquiet )) && zopt='-v' + for zdir in ${ZIM_HOME}/modules/*(N/); do zmodule=${zdir:t} - # If zmodules does not contain the zmodule - if (( ! ${zmodules[(I)${zmodule}]} )); then - zstyle -a ':zim:module' ${zmodule} 'zoptions' - [[ ${zoptions[frozen]} == yes ]] && continue - command rm -rf ${zdir} || return 1 - [[ ${1} != -q ]] && print ${zdir} + # If _zmodules and _zdisableds do not contain the zmodule + if (( ! ${_zmodules[(I)${zmodule}]} && ! ${_zdisableds[(I)${zmodule}]} )); then + command rm -rf ${zopt} ${zdir} || return 1 fi done - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f Done with clean-modules." + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with clean-modules.' fi } _zimfw_clean_compiled() { - setopt LOCAL_OPTIONS PIPE_FAIL - local find_opt rm_opt - if [[ ${1} != -q ]]; then - find_opt='-print' - rm_opt='-v' + local zopt_find zopt_rm zdir + if (( ! _zquiet )); then + zopt_find='-print' + zopt_rm='-v' fi - command find ${ZIM_HOME} \( -name '*.zwc' -o -name '*.zwc.old' \) -delete ${find_opt} || return 1 - command rm -f ${rm_opt} ${ZDOTDIR:-${HOME}}/.zshrc.zwc{,.old} || return 1 - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f Done with clean-compiled. Run %Bzimfw compile%b to re-compile." + for zdir in ${fpath}; do + [[ ${zdir} == (.|..) || ${zdir} == (.|..)/* ]] && continue + if [[ -w ${zdir:h} ]]; then + command rm -f ${zopt_rm} ${zdir}.zwc{,.old} || return 1 + fi + done + command find ${ZIM_HOME} \( -name '*.zwc' -o -name '*.zwc.old' \) -delete ${zopt_find} || return 1 + command rm -f ${zopt_rm} ${ZDOTDIR:-${HOME}}/.zshrc.zwc{,.old} || return 1 + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with clean-compiled. Run %Bzimfw compile%b to re-compile.' fi } _zimfw_clean_dumpfile() { - setopt LOCAL_OPTIONS PIPE_FAIL - local zdumpfile zout zopt + local zdumpfile zopt zstyle -s ':zim:completion' dumpfile 'zdumpfile' || zdumpfile="${ZDOTDIR:-${HOME}}/.zcompdump" - [[ ${1} != -q ]] && zopt='-v' + (( ! _zquiet )) && zopt='-v' command rm -f ${zopt} ${zdumpfile}{,.zwc{,.old}} || return 1 - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f Done with clean-dumpfile. Restart your terminal to dump an updated configuration." + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with clean-dumpfile. Restart your terminal to dump an updated configuration.' fi } _zimfw_info() { - print 'Zim version: 1.0.0-SNAPSHOT (previous commit is 601941f)' - print "Zsh version: ${ZSH_VERSION}" - print "System info: $(command uname -a)" + print 'Zim version: 1.0.0-SNAPSHOT (previous commit is e81c1d1)' + print -R "Zsh version: ${ZSH_VERSION}" + print -R "System info: $(command uname -a)" } _zimfw_upgrade() { - local zscript=${ZIM_HOME}/zimfw.zsh - local zurl=https://raw.githubusercontent.com/zimfw/zimfw/develop/zimfw.zsh - if (( ${+commands[wget]} )); then - command wget -nv ${1} -O ${zscript}.new ${zurl} || return 1 - else - command curl -fsSL -o ${zscript}.new ${zurl} || return 1 - fi - if command cmp -s ${zscript}{,.new}; then - command rm ${zscript}.new && \ - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f zimfw.zsh: Already up to date." - fi - else - command mv ${zscript}{,.old} && command mv ${zscript}{.new,} && \ - if [[ ${1} != -q ]]; then - print -P "%F{green}✓%f zimfw.zsh: upgraded. Restart your terminal for changes to take effect." - fi - fi + local -r zscript=${ZIM_HOME}/zimfw.zsh + local -r zurl=https://raw.githubusercontent.com/zimfw/zimfw/develop/zimfw.zsh + { + if (( ${+commands[wget]} )); then + command wget -nv ${1} -O ${zscript}.new ${zurl} || return 1 + else + command curl -fsSL -o ${zscript}.new ${zurl} || return 1 + fi + if command cmp -s ${zscript}{,.new}; then + if (( ! _zquiet )); then + print -P '%F{green}✓%f %Bzimfw.zsh:%b Already up to date' + fi + else + command mv -f ${zscript}{,.old} && command mv -f ${zscript}{.new,} && \ + if (( ! _zquiet )); then + print -P '%F{green}✓%f %Bzimfw.zsh:%b Upgraded. Restart your terminal for changes to take effect.' + fi + fi + if (( ! _zquiet )); then + print -P '%F{green}✓%f Done with upgrade.' + fi + } always { + command rm -f ${zscript}.new + } } -unfunction zimfw zimfw() { - local zusage="usage: ${0} [-q] -actions: - clean Clean all (see below). - clean-modules Clean unused modules. - clean-compiled Clean Zsh compiled files. - clean-dumpfile Clean completion dump file. - compile Compile Zsh files. - info Print Zim and system info. - install Install new modules. - update Update current modules. - upgrade Upgrade Zim. -options: - -q Quiet, only outputs errors." + local -r zusage=" +Usage: %B${0}%b [%B-q%b] - if [[ ${#} -ne 1 && ${2} != -q ]]; then - print -u2 ${zusage} - return 1 +Actions: + %Bbuild%b Build init script + %Bclean%b Clean all (see below) + %Bclean-modules%b Clean unused modules + %Bclean-compiled%b Clean Zsh compiled files + %Bclean-dumpfile%b Clean completion dump file + %Bcompile%b Compile Zsh files + %Binfo%b Print Zim and system info + %Binstall%b Install new modules + %Bupdate%b Update current modules + %Bupgrade%b Upgrade Zim + +Options: + %B-q%b Quiet, only outputs errors +" + local ztool _zmodules_xargs + local -a _zdisableds _zmodules _zfpaths _zfunctions _zscripts + local -i _zquiet=0 + if (( # > 2 )); then + print -u2 -PR "%F{red}${0}: Too many options%f"$'\n'${zusage} + return 1 + elif (( # > 1 )); then + case ${2} in + -q) _zquiet=1 ;; + *) + print -u2 -PR "%F{red}${0}: Unknown option ${2}%f"$'\n'${zusage} + return 1 + ;; + esac fi - local ztool case ${1} in install) ztool="# This runs in a new shell -DIR=\${1} -URL=\${2} -REV=\${4} -OPT=\${5} -MODULE=\${DIR:t} -CLEAR_LINE=\"\033[2K\r\" +readonly MODULE=\${1} +readonly DIR=\${2} +readonly URL=\${3} +readonly REV=\${5} +readonly -i QUIET=\${6} +readonly CLEAR_LINE=$'\E[2K\r' if [[ -e \${DIR} ]]; then # Already exists return 0 fi -[[ \${OPT} != -q ]] && print -n \"\${CLEAR_LINE}Installing \${MODULE} …\" +(( ! QUIET )) && print -Rn \${CLEAR_LINE}\"Installing \${MODULE} …\" if ERR=\$(command git clone -b \${REV} -q --recursive \${URL} \${DIR} 2>&1); then - if [[ \${OPT} != -q ]]; then - print -P \"\${CLEAR_LINE}%F{green}✓%f \${MODULE}: Installed\" + if (( ! QUIET )); then + print -PR \${CLEAR_LINE}\"%F{green}✓%f %B\${MODULE}:%b Installed\" fi else - print -P \"\${CLEAR_LINE}%F{red}✗ \${MODULE}: Error%f\n\${ERR}\" + print -u2 -PR \${CLEAR_LINE}\"%F{red}✗ %B\${MODULE}:%b Error during git clone%f\"$'\n'\${(F):- \${(f)^ERR}} return 1 fi " ;; update) ztool="# This runs in a new shell -DIR=\${1} -URL=\${2} -TYPE=\${3} -REV=\${4} -OPT=\${5} -MODULE=\${DIR:t} -CLEAR_LINE=\"\033[2K\r\" -[[ \${OPT} != -q ]] && print -n \"\${CLEAR_LINE}Updating \${MODULE} …\" -if ! cd \${DIR} 2>/dev/null; then - print -P \"\${CLEAR_LINE}%F{red}✗ \${MODULE}: Not installed%f\" +readonly MODULE=\${1} +readonly DIR=\${2} +readonly URL=\${3} +readonly TYPE=\${4} +readonly REV=\${5} +readonly -i QUIET=\${6} +readonly CLEAR_LINE=$'\E[2K\r' +(( ! QUIET )) && print -Rn \${CLEAR_LINE}\"Updating \${MODULE} …\" +if ! builtin cd \${DIR} 2>/dev/null; then + print -u2 -PR \${CLEAR_LINE}\"%F{red}✗ %B\${MODULE}:%b Not installed%f\" return 1 fi if [[ \${PWD} != \$(command git rev-parse --show-toplevel 2>/dev/null) ]]; then @@ -273,32 +356,32 @@ if [[ \${PWD} != \$(command git rev-parse --show-toplevel 2>/dev/null) ]]; then return 0 fi if [[ \${URL} != \$(command git config --get remote.origin.url) ]]; then - print -P \"\${CLEAR_LINE}%F{red}✗ \${MODULE}: URL does not match. Expected \${URL}. Will not try to update.%f\" + print -u2 -PR \${CLEAR_LINE}\"%F{red}✗ %B\${MODULE}:%b URL does not match. Expected \${URL}. Will not try to update.%f\" return 1 fi if [[ \${TYPE} == tag ]]; then if [[ \${REV} == \$(command git describe --tags --exact-match 2>/dev/null) ]]; then - [[ \${OPT} != -q ]] && print -P \"\${CLEAR_LINE}%F{green}✓%f \${MODULE}: Already up to date\" + (( ! QUIET )) && print -PR \${CLEAR_LINE}\"%F{green}✓%f %B\${MODULE}:%b Already up to date\" return 0 fi fi if ! ERR=\$(command git fetch -pq origin \${REV} 2>&1); then - print -P \"\${CLEAR_LINE}%F{red}✗ \${MODULE}: Error (1)%f\n\${ERR}\" + print -u2 -PR \${CLEAR_LINE}\"%F{red}✗ %B\${MODULE}:%b Error during git fetch%f\"$'\n'\${(F):- \${(f)^ERR}} return 1 fi if [[ \${TYPE} == branch ]]; then - LOG_REV=\"\${REV}@{u}\" + LOG_REV=\${REV}@{u} else LOG_REV=\${REV} fi LOG=\$(command git log --graph --color --format='%C(yellow)%h%C(reset) %s %C(cyan)(%cr)%C(reset)' ..\${LOG_REV} 2>/dev/null) if ! ERR=\$(command git checkout -q \${REV} -- 2>&1); then - print -P \"\${CLEAR_LINE}%F{red}✗ \${MODULE}: Error (2)%f\n\${ERR}\" + print -u2 -PR \${CLEAR_LINE}\"%F{red}✗ %B\${MODULE}:%b Error during git checkout%f\"$'\n'\${(F):- \${(f)^ERR}} return 1 fi if [[ \${TYPE} == branch ]]; then if ! OUT=\$(command git merge --ff-only --no-progress -n 2>&1); then - print -P \"\${CLEAR_LINE}%F{red}✗ \${MODULE}: Error (3)%f\n\${OUT}\" + print -u2 -PR \${CLEAR_LINE}\"%F{red}✗ %B\${MODULE}:%b Error during git merge%f\"$'\n'\${(F):- \${(f)^OUT}} return 1 fi # keep just first line of OUT @@ -306,17 +389,13 @@ if [[ \${TYPE} == branch ]]; then else OUT=\"Updating to \${TYPE} \${REV}\" fi -if [[ -n \${LOG} ]]; then - LOG_LINES=(' '\${(f)^LOG}) - OUT=\"\${OUT} -\${(F)LOG_LINES}\" -fi if ERR=\$(command git submodule update --init --recursive -q 2>&1); then - if [[ \${OPT} != -q ]]; then - print -R \"\$(print -P \"\${CLEAR_LINE}%F{green}✓%f\") \${MODULE}: \${OUT}\" + if (( ! QUIET )); then + [[ -n \${LOG} ]] && OUT=\${OUT}$'\n'\${(F):- \${(f)^LOG}} + print -PR \${CLEAR_LINE}\"%F{green}✓%f %B\${MODULE}:%b \${OUT}\" fi else - print -P \"\${CLEAR_LINE}%F{red}✗ \${MODULE}: Error (4)%f\n\${ERR}\" + print -u2 -PR \${CLEAR_LINE}\"%F{red}✗ %B\${MODULE}:%b Error during git submodule update%f\"$'\n'\${(F):- \${(f)^ERR}} return 1 fi " @@ -324,31 +403,32 @@ fi esac case ${1} in + build) _zimfw_source_zimrc && _zimfw_build && _zimfw_compile ${2} ;; clean) - _zimfw_clean_modules ${2} && \ - _zimfw_clean_compiled ${2} && \ - _zimfw_clean_dumpfile ${2} + _zimfw_source_zimrc && \ + _zimfw_clean_modules && \ + _zimfw_clean_compiled && \ + _zimfw_clean_dumpfile ;; - clean-modules) _zimfw_clean_modules ${2} ;; - clean-compiled) _zimfw_clean_compiled ${2} ;; - clean-dumpfile) _zimfw_clean_dumpfile ${2} ;; - compile|login-init) _zimfw_compile ${2} ;; - info) _zimfw_info ${2} ;; + clean-modules) _zimfw_source_zimrc && _zimfw_clean_modules ;; + clean-compiled) _zimfw_clean_compiled ;; + clean-dumpfile) _zimfw_clean_dumpfile ;; + compile|login-init) _zimfw_source_zimrc && _zimfw_compile ${2} ;; + info) _zimfw_info ;; install|update) - # Source .zimrc to refresh zmodules - [[ -f ${ZDOTDIR:-${HOME}}/.zimrc ]] && source ${ZDOTDIR:-${HOME}}/.zimrc - _zimfw_modules ${2} | xargs -L1 -P10 zsh -c ${ztool} ${1} && \ - if [[ ${2} != -q ]]; then - print -P "%F{green}✓%f Done with ${1}. Restart your terminal for any changes to take effect." - fi + _zimfw_source_zimrc || return 1 + print -Rn ${_zmodules_xargs} | xargs -0 -n6 -P10 zsh -c ${ztool} ${1} && \ + if (( ! _zquiet )); then + print -PR "%F{green}✓%f Done with ${1}. Restart your terminal for any changes to take effect." + fi && \ + _zimfw_build && _zimfw_compile ${2} ;; - upgrade) _zimfw_upgrade ${2} ;; + upgrade) _zimfw_upgrade ;; *) - print -u2 ${zusage} + print -u2 -PR "%F{red}${0}: Unknown action ${1}%f"$'\n'${zusage} return 1 ;; esac } -# Stage 2 done -fi +zimfw "${@}"