From 05b8e0cdf2f938da4024273df65d71d34f87a90f Mon Sep 17 00:00:00 2001 From: Eric Nielsen <4120606+ericbn@users.noreply.github.com> Date: Mon, 26 Sep 2022 20:33:49 -0500 Subject: [PATCH] Add `--root` option to `zmodule` which makes it straighforward to use repositories that contain multiple modules, like sorin-ionescu/prezto or ohmyzsh/ohmyzsh. --- src/stage2/30_zmodule.zsh.erb | 152 +++++++++------- src/stage2/31_zimfw_source_zimrc.zsh.erb | 8 + src/stage2/34_zimfw_list_unuseds.zsh.erb | 10 +- src/stage2/50_zimfw_compile.zsh.erb | 14 +- src/stage2/69_zimfw_run_list.zsh.erb | 28 ++- src/stage2/80_zimfw.zsh.erb | 4 +- zimfw.zsh | 218 ++++++++++++++--------- 7 files changed, 265 insertions(+), 169 deletions(-) diff --git a/src/stage2/30_zmodule.zsh.erb b/src/stage2/30_zmodule.zsh.erb index a66867e..55a372c 100644 --- a/src/stage2/30_zmodule.zsh.erb +++ b/src/stage2/30_zmodule.zsh.erb @@ -1,16 +1,20 @@ zmodule() { - local -r zusage="Usage: %B${0}%b [%B-n%b|%B--name%b ] [options] + local -r zusage="Usage: %B${0}%b [%B-n%b|%B--name%b ] [%B-r%b|%B--root%b ] [options] Add %Bzmodule%b calls to your %B${ZDOTDIR:-${HOME}}/.zimrc%b file to define the modules to be initialized. -The modules are initialized in the same order they are defined. +The initialization will be done in the same order it's defined. Module absolute path or repository URL. The following URL formats are equivalent: %Bfoo%b, %Bzimfw/foo%b, %Bhttps://github.com/zimfw/foo.git%b. - %B-n%b|%B--name%b Set a custom module name. Default: the last component in . - Use slashes inside the name to organize the module into subdirec- - tories. + If an absolute path is given, the module is considered externally + installed, and won't be installed or updated by zimfw. + %B-n%b|%B--name%b Set a custom module name. Use slashes inside the name to organize + the module into subdirectories. The module will be installed at + %B${ZIM_HOME}/%b. + Default: the last component in . + %B-r%b|%B--root%b Relative path to the module root. Default: none. -Repository options: +Per-module options: %B-b%b|%B--branch%b Use specified branch when installing and updating the module. Overrides the tag option. Default: the repository default branch. %B-t%b|%B--tag%b Use specified tag when installing and updating the module. Over- @@ -24,25 +28,36 @@ Repository options: changes are lost on updates. Git submodules are not supported. %B--no-submodules%b Don't install or update git submodules. %B-z%b|%B--frozen%b Don't install or update the module. + + The per-module options above are carried over multiple zmodule calls for the same module. + Modules are uniquely identified by their name. + +Per-module-root options: %B--on-pull%b Execute command after installing or updating the module. The com- mand is executed in the module root directory. -Initialization options: - %B-f%b|%B--fpath%b Add specified path to fpath. The path is relative to the module - root directory. Default: %Bfunctions%b, if the subdirectory exists. - %B-a%b|%B--autoload%b Autoload specified function. Default: all valid names inside the - %Bfunctions%b subdirectory, if any. - %B-s%b|%B--source%b Source specified file. The file path is relative to the module - root directory. Default: %Binit.zsh%b, if the %Bfunctions%b subdirectory - also exists, or the largest of the files with name matching - %B{init.zsh,module_name.{zsh,plugin.zsh,zsh-theme,sh}}%b, if any. - %B-c%b|%B--cmd%b Execute specified command. Occurrences of the %B{}%b placeholder in - the command are substituted by the module root directory path. - I.e., %B-s 'foo.zsh'%b and %B-c 'source {}/foo.zsh'%b are equivalent. - %B-d%b|%B--disabled%b Don't initialize or uninstall the module. + %B-d%b|%B--disabled%b Don't initialize the module root or uninstall the module. - Setting any initialization option above will disable all the default values from the other - initialization options, so only your provided values are used. I.e. these values are either - all automatic, or all manual." + The per-module-root options above are carried over multiple zmodule calls for the same mod- + ule root. + +Per-call initialization options: + %B-f%b|%B--fpath%b Will add specified path to fpath. The path is relative to the + module root directory. Default: %Bfunctions%b, if the subdirectory + exists and is non-empty. + %B-a%b|%B--autoload%b Will autoload specified function. Default: all valid names inside + the %Bfunctions%b subdirectory, if any. + %B-s%b|%B--source%b Will source specified file. The path is relative to the module + root directory. Default: %Binit.zsh%b, if a non-empty %Bfunctions%b sub- + directory exists, else the largest of the files matching the glob + %B(init.zsh|%b%B.(zsh|plugin.zsh|zsh-theme|sh))%b, if any. + %B-c%b|%B--cmd%b Will execute specified command. Occurrences of the %B{}%b placeholder + in the command are substituted by the module root directory path. + I.e., %B-s 'foo.zsh'%b and %B-c 'source {}/foo.zsh'%b are equivalent. + + Setting any per-call initialization option above will disable the default values from the + other per-call initialization options, so only your provided values will be used. I.e. these + values are either all automatic, or all manual in each zmodule call. To use default values + and also provided values, use separate zmodule calls." if [[ ${${funcfiletrace[1]%:*}:t} != .zimrc ]]; then print -u2 -PlR "%F{red}${0}: Must be called from %B<%= home %>/.zimrc%b%f" '' ${zusage} return 2 @@ -52,7 +67,7 @@ Initialization options: _zfailed=1 return 2 fi - local zurl=${1} zname=${1:t} zarg + local zurl=${1} zname=${1:t} zroot zarg local -a zfpaths zfunctions zcmds if [[ ${zurl} =~ ^[^:/]+: ]]; then zname=${zname%.git} @@ -64,14 +79,22 @@ Initialization options: esac fi shift - while [[ ${1} == (-n|--name) ]]; do + while [[ ${1} == (-n|--name|-r|--root) ]]; do if (( # < 2 )); then print -u2 -PlR "%F{red}<%= error %>${funcfiletrace[1]}:%B${zname}:%b Missing argument for zmodule option %B${1}%b%f" '' ${zusage} _zfailed=1 return 2 fi - shift - zname=${${1%%/##}##/##} + case ${1} in + -n|--name) + shift + zname=${${1%%/##}##/##} + ;; + -r|--root) + shift + zroot=${${1%%/##}##/##} + ;; + esac shift done if [[ ${zurl} == /* ]]; then @@ -80,7 +103,14 @@ Initialization options: else _zdirs[${zname}]=${ZIM_HOME}/modules/${zname} fi + if [[ ${+_zurls[${zname}]} -ne 0 && ${_zurls[${zname}]} != ${zurl} ]]; then + print -u2 -PlR "%F{red}<%= error %>${funcfiletrace[1]}:%B${zname}:%b Module already defined with a different URL. Expected %B${_zurls[${zname}]}%b%f" '' ${zusage} + _zfailed=1 + return 2 + fi _zurls[${zname}]=${zurl} + local -r zroot_dir=${_zdirs[${zname}]}${zroot:+/${zroot}} + _zroot_dirs+=(${zroot_dir}) # Set default values if (( ! ${+_ztools[${zname}]} )); then zstyle -s ':zim:zmodule' use "_ztools[${zname}]" || _ztools[${zname}]=git @@ -122,12 +152,14 @@ Initialization options: -z|--frozen) _zfrozens[${zname}]=1 ;; --on-pull) shift - _zonpulls[${zname}]="${_zonpulls[${zname}]+${_zonpulls[${zname}]}; }${1}" + zarg=${1} + if [[ -n ${zroot} ]] zarg="(builtin cd -q ${zroot}; ${zarg})" + _zonpulls[${zname}]="${_zonpulls[${zname}]+${_zonpulls[${zname}]}; }${zarg}" ;; -f|--fpath) shift zarg=${1} - if [[ ${zarg} != /* ]] zarg=${_zdirs[${zname}]}/${zarg} + if [[ ${zarg} != /* ]] zarg=${zroot_dir}/${zarg} zfpaths+=(${zarg}) ;; -a|--autoload) @@ -137,14 +169,14 @@ Initialization options: -s|--source) shift zarg=${1} - if [[ ${zarg} != /* ]] zarg=${_zdirs[${zname}]}/${zarg} + if [[ ${zarg} != /* ]] zarg=${zroot_dir}/${zarg} zcmds+=("source ${zarg:A}") ;; -c|--cmd) shift - zcmds+=(${1//{}/${_zdirs[${zname}]:A}}) + zcmds+=(${1//{}/${zroot_dir:A}}) ;; - -d|--disabled) _zdisableds[${zname}]=1 ;; + -d|--disabled) _zdisabled_root_dirs+=(${zroot_dir}) ;; *) print -u2 -PlR "%F{red}<%= error %>${funcfiletrace[1]}:%B${zname}:%b Unknown zmodule option %B${1}%b%f" '' ${zusage} _zfailed=1 @@ -157,37 +189,33 @@ Initialization options: _znames+=(${zname}) fi if (( _zflags & 2 )); then - if (( _zdisableds[${zname}] )); then - _zdisabled_dirs+=(${_zdirs[${zname}]}) - else - if [[ ! -e ${_zdirs[${zname}]} ]]; then - print -u2 -PR "%F{red}<%= error %>${funcfiletrace[1]}:%B${zname}: ${_zdirs[${zname}]}%b not found%f" - _zfailed=1 - return 1 - fi - if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then - zfpaths=(${_zdirs[${zname}]}/functions(NF)) - # _* functions are autoloaded by compinit - # prompt_*_setup functions are autoloaded by promptinit - zfunctions=(${^zfpaths}/^(*~|*.zwc(|.old)|_*|prompt_*_setup)(N-.:t)) - local -ra prezto_scripts=(${_zdirs[${zname}]}/init.zsh(N)) - if (( ${#zfpaths} && ${#prezto_scripts} )); then - # this follows the prezto module format, no need to check for other scripts - zcmds=('source '${^prezto_scripts:A}) - else - # get script with largest size (descending `O`rder by `L`ength, and return only `[1]` first) - local -ra zscripts=(${_zdirs[${zname}]}/(init.zsh|${zname:t}.(zsh|plugin.zsh|zsh-theme|sh))(NOL[1])) - zcmds=('source '${^zscripts:A}) - fi - fi - if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then - _zimfw_print -u2 -PlR "%F{yellow}<%= warn %>${funcfiletrace[1]}:%B${zname}:%b Nothing found to be initialized. Customize the module name or initialization with %Bzmodule%b options.%f" '' ${zusage} - fi - # Prefix is added to all _zfpaths, _zfunctions and _zcmds to distinguish the originating names - local -r zpre=${zname}$'\0' - _zfpaths+=(${zpre}${^zfpaths}) - _zfunctions+=(${zpre}${^zfunctions}) - _zcmds+=(${zpre}${^zcmds}) + if [[ ! -e ${zroot_dir} ]]; then + print -u2 -PR "%F{red}<%= error %>${funcfiletrace[1]}:%B${zname}: ${zroot_dir}%b not found%f" + _zfailed=1 + return 1 fi + if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then + zfpaths=(${zroot_dir}/functions(NF)) + # _* functions are autoloaded by compinit + # prompt_*_setup functions are autoloaded by promptinit + zfunctions=(${^zfpaths}/^(*~|*.zwc(|.old)|_*|prompt_*_setup)(N-.:t)) + local -ra prezto_scripts=(${zroot_dir}/init.zsh(N)) + if (( ${#zfpaths} && ${#prezto_scripts} )); then + # this follows the prezto module format, no need to check for other scripts + zcmds=('source '${^prezto_scripts:A}) + else + # get script with largest size (descending `O`rder by `L`ength, and return only `[1]` first) + local -ra zscripts=(${zroot_dir}/(init.zsh|${zroot_dir:t}.(zsh|plugin.zsh|zsh-theme|sh))(NOL[1])) + zcmds=('source '${^zscripts:A}) + fi + fi + if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then + _zimfw_print -u2 -PlR "%F{yellow}<%= warn %>${funcfiletrace[1]}:%B${zname}:%b Nothing found to be initialized. Customize the module name or initialization with %Bzmodule%b options.%f" '' ${zusage} + fi + # Prefix is added to all _zfpaths, _zfunctions and _zcmds to distinguish the originating root dir + local -r zpre=${zroot_dir}$'\0' + _zfpaths+=(${zpre}${^zfpaths}) + _zfunctions+=(${zpre}${^zfunctions}) + _zcmds+=(${zpre}${^zcmds}) fi } diff --git a/src/stage2/31_zimfw_source_zimrc.zsh.erb b/src/stage2/31_zimfw_source_zimrc.zsh.erb index 1b7ca2d..c9c33b0 100644 --- a/src/stage2/31_zimfw_source_zimrc.zsh.erb +++ b/src/stage2/31_zimfw_source_zimrc.zsh.erb @@ -9,4 +9,12 @@ _zimfw_source_zimrc() { print -u2 -PR "%F{red}<%= failed %>No modules defined in %B${ztarget}%b%f" return 1 fi + # Remove all from _zfpaths, _zfunctions and _zcmds with disabled root dirs prefixes + local zroot_dir zpre + for zroot_dir in ${_zdisabled_root_dirs}; do + zpre=${zroot_dir}$'\0' + _zfpaths=(${_zfpaths:#${zpre}*}) + _zfunctions=(${_zfunctions:#${zpre}*}) + _zcmds=(${_zcmds:#${zpre}*}) + done } diff --git a/src/stage2/34_zimfw_list_unuseds.zsh.erb b/src/stage2/34_zimfw_list_unuseds.zsh.erb index 53d33a7..0af79e3 100644 --- a/src/stage2/34_zimfw_list_unuseds.zsh.erb +++ b/src/stage2/34_zimfw_list_unuseds.zsh.erb @@ -1,18 +1,18 @@ _zimfw_list_unuseds() { local -i i=1 - local -a zinstalled=(${ZIM_HOME}/modules/*(N/)) - local -ar zdirs=(${(v)_zdirs}) + local zinstalled=(${ZIM_HOME}/modules/*(N/)) + local -r zdirs=(${(v)_zdirs}) # Search into subdirectories while (( i <= ${#zinstalled} )); do - if (( ${zdirs[(I)${zinstalled[i]}/*]} || ${_zdisabled_dirs[(I)${zinstalled[i]}/*]} )); then + if (( ${zdirs[(I)${zinstalled[i]}/*]} )); then zinstalled+=(${zinstalled[i]}/*(N/)) zinstalled[i]=() else (( i++ )) fi done - # Unused = all installed dirs not in zdirs and _zdisabled_dirs - _zunused_dirs=(${${zinstalled:|zdirs}:|_zdisabled_dirs}) + # Unused = all installed dirs not in zdirs + _zunused_dirs=(${zinstalled:|zdirs}) local zunused for zunused (${_zunused_dirs}) _zimfw_print -PR "%B${zunused:t}:%b ${zunused}${1}" } diff --git a/src/stage2/50_zimfw_compile.zsh.erb b/src/stage2/50_zimfw_compile.zsh.erb index f518be8..37ef84f 100644 --- a/src/stage2/50_zimfw_compile.zsh.erb +++ b/src/stage2/50_zimfw_compile.zsh.erb @@ -1,12 +1,12 @@ _zimfw_compile() { - # Array with unique dirs. ${ZIM_HOME} or any subdirectory should only occur once. - local -Ur zscriptdirs=(${ZIM_HOME} ${${(v)_zdirs##${ZIM_HOME}/*}:A}) # Compile Zim scripts - local zfile - for zfile in ${^zscriptdirs}/(^*test*/)#*.zsh(|-theme)(N-.); do - if [[ ! ${zfile}.zwc -nt ${zfile} ]]; then - zcompile -R ${zfile} && _zimfw_print -PR "<%= okay %>%B${zfile}.zwc:%b Compiled" - fi + local zroot_dir zfile + for zroot_dir in ${_zroot_dirs:|_zdisabled_root_dirs}; do + for zfile in ${zroot_dir}/(^*test*/)#*.zsh(|-theme)(N-.); do + if [[ ! ${zfile}.zwc -nt ${zfile} ]]; then + zcompile -UR ${zfile} && _zimfw_print -PR "<%= okay %>%B${zfile}.zwc:%b Compiled" + fi + done done _zimfw_print -P '<%= done %>Done with compile.' } diff --git a/src/stage2/69_zimfw_run_list.zsh.erb b/src/stage2/69_zimfw_run_list.zsh.erb index 656442f..c1ef073 100644 --- a/src/stage2/69_zimfw_run_list.zsh.erb +++ b/src/stage2/69_zimfw_run_list.zsh.erb @@ -1,9 +1,10 @@ _zimfw_run_list() { local -r zname=${1} - print -PnR "%B${zname}:%b ${_zdirs[${zname}]}" - if [[ -z ${_zurls[${zname}]} ]] print -Pn ' (external)' - if (( ${_zfrozens[${zname}]} )) print -Pn ' (frozen)' - if (( ${_zdisableds[${zname}]} )) print -Pn ' (disabled)' + local -r zdir=${_zdirs[${zname}]} + print -PnR "%B${zname}:%b ${zdir}" + if [[ -z ${_zurls[${zname}]} ]] print -n ' (external)' + if (( ${_zfrozens[${zname}]} )) print -n ' (frozen)' + if (( ${_zdisabled_root_dirs[(I)${zdir}]} )) print -n ' (disabled)' print if (( _zprintlevel > 1 )); then if [[ ${_zfrozens[${zname}]} -eq 0 && -n ${_zurls[${zname}]} ]]; then @@ -14,13 +15,24 @@ _zimfw_run_list() { print -nR "${_ztypes[${zname}]} ${_zrevs[${zname}]}" fi print -nR ", using ${_ztools[${zname}]}" - if (( ! _zsubmodules[${zname}] )) print -nR ', no git submodules' + if (( ! _zsubmodules[${zname}] )) print -n ', no git submodules' print if [[ -n ${_zonpulls[${zname}]} ]] print -R " On-pull: ${_zonpulls[${zname}]}" fi - # Match and remove the current module prefix from _zfpaths, _zfunctions and _zcmds - local -r zpre=${zname}$'\0' - local -r zfpaths=(${${(M)_zfpaths:#${zpre}*}#${zpre}}) zfunctions=(${${(M)_zfunctions:#${zpre}*}#${zpre}}) zcmds=(${${(M)_zcmds:#${zpre}*}#${zpre}}) + # Match the current module dir prefix from _zroot_dirs + local -r zroot_dirs=(${(M)_zroot_dirs:#${zdir}/*}) + if (( ${#zroot_dirs} )); then + print ' Additional root:' + local zroot_dir + for zroot_dir in ${zroot_dirs}; do + print -nR " ${zroot_dir}" + if (( ${_zdisabled_root_dirs[(I)${zroot_dir}]} )) print -n ' (disabled)' + print + done + fi + # Match and remove the prefix from _zfpaths, _zfunctions and _zcmds + local -r zpre="${zdir}(|/*)"$'\0' + local -r zfpaths=(${${(M)_zfpaths:#${~zpre}*}#${~zpre}}) zfunctions=(${${(M)_zfunctions:#${~zpre}*}#${~zpre}}) zcmds=(${${(M)_zcmds:#${~zpre}*}#${~zpre}}) if (( ${#zfpaths} )) print -R ' fpath: '${zfpaths} if (( ${#zfunctions} )) print -R ' autoload: '${zfunctions} if (( ${#zcmds} )) print -R ' cmd: '${(j:; :)zcmds} diff --git a/src/stage2/80_zimfw.zsh.erb b/src/stage2/80_zimfw.zsh.erb index 7894946..5ca7727 100644 --- a/src/stage2/80_zimfw.zsh.erb +++ b/src/stage2/80_zimfw.zsh.erb @@ -26,8 +26,8 @@ Actions: Options: %B-q%b Quiet (yes to prompts, and only outputs errors) %B-v%b Verbose (outputs more details)" - local -Ua _znames _zdisabled_dirs - local -A _zfrozens _zdisableds _ztools _zdirs _zurls _ztypes _zrevs _zsubmodules _zonpulls + local -Ua _znames _zroot_dirs _zdisabled_root_dirs + local -A _zfrozens _ztools _zdirs _zurls _ztypes _zrevs _zsubmodules _zonpulls local -a _zfpaths _zfunctions _zcmds _zunused_dirs local -i _zprintlevel=1 if (( # > 2 )); then diff --git a/zimfw.zsh b/zimfw.zsh index eefbb12..130aa71 100644 --- a/zimfw.zsh +++ b/zimfw.zsh @@ -85,18 +85,22 @@ _zimfw_build() { } zmodule() { - local -r zusage="Usage: %B${0}%b [%B-n%b|%B--name%b ] [options] + local -r zusage="Usage: %B${0}%b [%B-n%b|%B--name%b ] [%B-r%b|%B--root%b ] [options] Add %Bzmodule%b calls to your %B${ZDOTDIR:-${HOME}}/.zimrc%b file to define the modules to be initialized. -The modules are initialized in the same order they are defined. +The initialization will be done in the same order it's defined. Module absolute path or repository URL. The following URL formats are equivalent: %Bfoo%b, %Bzimfw/foo%b, %Bhttps://github.com/zimfw/foo.git%b. - %B-n%b|%B--name%b Set a custom module name. Default: the last component in . - Use slashes inside the name to organize the module into subdirec- - tories. + If an absolute path is given, the module is considered externally + installed, and won't be installed or updated by zimfw. + %B-n%b|%B--name%b Set a custom module name. Use slashes inside the name to organize + the module into subdirectories. The module will be installed at + %B${ZIM_HOME}/%b. + Default: the last component in . + %B-r%b|%B--root%b Relative path to the module root. Default: none. -Repository options: +Per-module options: %B-b%b|%B--branch%b Use specified branch when installing and updating the module. Overrides the tag option. Default: the repository default branch. %B-t%b|%B--tag%b Use specified tag when installing and updating the module. Over- @@ -110,25 +114,36 @@ Repository options: changes are lost on updates. Git submodules are not supported. %B--no-submodules%b Don't install or update git submodules. %B-z%b|%B--frozen%b Don't install or update the module. + + The per-module options above are carried over multiple zmodule calls for the same module. + Modules are uniquely identified by their name. + +Per-module-root options: %B--on-pull%b Execute command after installing or updating the module. The com- mand is executed in the module root directory. -Initialization options: - %B-f%b|%B--fpath%b Add specified path to fpath. The path is relative to the module - root directory. Default: %Bfunctions%b, if the subdirectory exists. - %B-a%b|%B--autoload%b Autoload specified function. Default: all valid names inside the - %Bfunctions%b subdirectory, if any. - %B-s%b|%B--source%b Source specified file. The file path is relative to the module - root directory. Default: %Binit.zsh%b, if the %Bfunctions%b subdirectory - also exists, or the largest of the files with name matching - %B{init.zsh,module_name.{zsh,plugin.zsh,zsh-theme,sh}}%b, if any. - %B-c%b|%B--cmd%b Execute specified command. Occurrences of the %B{}%b placeholder in - the command are substituted by the module root directory path. - I.e., %B-s 'foo.zsh'%b and %B-c 'source {}/foo.zsh'%b are equivalent. - %B-d%b|%B--disabled%b Don't initialize or uninstall the module. + %B-d%b|%B--disabled%b Don't initialize the module root or uninstall the module. - Setting any initialization option above will disable all the default values from the other - initialization options, so only your provided values are used. I.e. these values are either - all automatic, or all manual." + The per-module-root options above are carried over multiple zmodule calls for the same mod- + ule root. + +Per-call initialization options: + %B-f%b|%B--fpath%b Will add specified path to fpath. The path is relative to the + module root directory. Default: %Bfunctions%b, if the subdirectory + exists and is non-empty. + %B-a%b|%B--autoload%b Will autoload specified function. Default: all valid names inside + the %Bfunctions%b subdirectory, if any. + %B-s%b|%B--source%b Will source specified file. The path is relative to the module + root directory. Default: %Binit.zsh%b, if a non-empty %Bfunctions%b sub- + directory exists, else the largest of the files matching the glob + %B(init.zsh|%b%B.(zsh|plugin.zsh|zsh-theme|sh))%b, if any. + %B-c%b|%B--cmd%b Will execute specified command. Occurrences of the %B{}%b placeholder + in the command are substituted by the module root directory path. + I.e., %B-s 'foo.zsh'%b and %B-c 'source {}/foo.zsh'%b are equivalent. + + Setting any per-call initialization option above will disable the default values from the + other per-call initialization options, so only your provided values will be used. I.e. these + values are either all automatic, or all manual in each zmodule call. To use default values + and also provided values, use separate zmodule calls." if [[ ${${funcfiletrace[1]%:*}:t} != .zimrc ]]; then print -u2 -PlR "%F{red}${0}: Must be called from %B${ZDOTDIR:-${HOME}}/.zimrc%b%f" '' ${zusage} return 2 @@ -138,7 +153,7 @@ Initialization options: _zfailed=1 return 2 fi - local zurl=${1} zname=${1:t} zarg + local zurl=${1} zname=${1:t} zroot zarg local -a zfpaths zfunctions zcmds if [[ ${zurl} =~ ^[^:/]+: ]]; then zname=${zname%.git} @@ -150,14 +165,22 @@ Initialization options: esac fi shift - while [[ ${1} == (-n|--name) ]]; do + while [[ ${1} == (-n|--name|-r|--root) ]]; do if (( # < 2 )); then print -u2 -PlR "%F{red}x ${funcfiletrace[1]}:%B${zname}:%b Missing argument for zmodule option %B${1}%b%f" '' ${zusage} _zfailed=1 return 2 fi - shift - zname=${${1%%/##}##/##} + case ${1} in + -n|--name) + shift + zname=${${1%%/##}##/##} + ;; + -r|--root) + shift + zroot=${${1%%/##}##/##} + ;; + esac shift done if [[ ${zurl} == /* ]]; then @@ -166,7 +189,14 @@ Initialization options: else _zdirs[${zname}]=${ZIM_HOME}/modules/${zname} fi + if [[ ${+_zurls[${zname}]} -ne 0 && ${_zurls[${zname}]} != ${zurl} ]]; then + print -u2 -PlR "%F{red}x ${funcfiletrace[1]}:%B${zname}:%b Module already defined with a different URL. Expected %B${_zurls[${zname}]}%b%f" '' ${zusage} + _zfailed=1 + return 2 + fi _zurls[${zname}]=${zurl} + local -r zroot_dir=${_zdirs[${zname}]}${zroot:+/${zroot}} + _zroot_dirs+=(${zroot_dir}) # Set default values if (( ! ${+_ztools[${zname}]} )); then zstyle -s ':zim:zmodule' use "_ztools[${zname}]" || _ztools[${zname}]=git @@ -208,12 +238,14 @@ Initialization options: -z|--frozen) _zfrozens[${zname}]=1 ;; --on-pull) shift - _zonpulls[${zname}]="${_zonpulls[${zname}]+${_zonpulls[${zname}]}; }${1}" + zarg=${1} + if [[ -n ${zroot} ]] zarg="(builtin cd -q ${zroot}; ${zarg})" + _zonpulls[${zname}]="${_zonpulls[${zname}]+${_zonpulls[${zname}]}; }${zarg}" ;; -f|--fpath) shift zarg=${1} - if [[ ${zarg} != /* ]] zarg=${_zdirs[${zname}]}/${zarg} + if [[ ${zarg} != /* ]] zarg=${zroot_dir}/${zarg} zfpaths+=(${zarg}) ;; -a|--autoload) @@ -223,14 +255,14 @@ Initialization options: -s|--source) shift zarg=${1} - if [[ ${zarg} != /* ]] zarg=${_zdirs[${zname}]}/${zarg} + if [[ ${zarg} != /* ]] zarg=${zroot_dir}/${zarg} zcmds+=("source ${zarg:A}") ;; -c|--cmd) shift - zcmds+=(${1//{}/${_zdirs[${zname}]:A}}) + zcmds+=(${1//{}/${zroot_dir:A}}) ;; - -d|--disabled) _zdisableds[${zname}]=1 ;; + -d|--disabled) _zdisabled_root_dirs+=(${zroot_dir}) ;; *) print -u2 -PlR "%F{red}x ${funcfiletrace[1]}:%B${zname}:%b Unknown zmodule option %B${1}%b%f" '' ${zusage} _zfailed=1 @@ -243,38 +275,34 @@ Initialization options: _znames+=(${zname}) fi if (( _zflags & 2 )); then - if (( _zdisableds[${zname}] )); then - _zdisabled_dirs+=(${_zdirs[${zname}]}) - else - if [[ ! -e ${_zdirs[${zname}]} ]]; then - print -u2 -PR "%F{red}x ${funcfiletrace[1]}:%B${zname}: ${_zdirs[${zname}]}%b not found%f" - _zfailed=1 - return 1 - fi - if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then - zfpaths=(${_zdirs[${zname}]}/functions(NF)) - # _* functions are autoloaded by compinit - # prompt_*_setup functions are autoloaded by promptinit - zfunctions=(${^zfpaths}/^(*~|*.zwc(|.old)|_*|prompt_*_setup)(N-.:t)) - local -ra prezto_scripts=(${_zdirs[${zname}]}/init.zsh(N)) - if (( ${#zfpaths} && ${#prezto_scripts} )); then - # this follows the prezto module format, no need to check for other scripts - zcmds=('source '${^prezto_scripts:A}) - else - # get script with largest size (descending `O`rder by `L`ength, and return only `[1]` first) - local -ra zscripts=(${_zdirs[${zname}]}/(init.zsh|${zname:t}.(zsh|plugin.zsh|zsh-theme|sh))(NOL[1])) - zcmds=('source '${^zscripts:A}) - fi - fi - if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then - _zimfw_print -u2 -PlR "%F{yellow}! ${funcfiletrace[1]}:%B${zname}:%b Nothing found to be initialized. Customize the module name or initialization with %Bzmodule%b options.%f" '' ${zusage} - fi - # Prefix is added to all _zfpaths, _zfunctions and _zcmds to distinguish the originating names - local -r zpre=${zname}$'\0' - _zfpaths+=(${zpre}${^zfpaths}) - _zfunctions+=(${zpre}${^zfunctions}) - _zcmds+=(${zpre}${^zcmds}) + if [[ ! -e ${zroot_dir} ]]; then + print -u2 -PR "%F{red}x ${funcfiletrace[1]}:%B${zname}: ${zroot_dir}%b not found%f" + _zfailed=1 + return 1 fi + if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then + zfpaths=(${zroot_dir}/functions(NF)) + # _* functions are autoloaded by compinit + # prompt_*_setup functions are autoloaded by promptinit + zfunctions=(${^zfpaths}/^(*~|*.zwc(|.old)|_*|prompt_*_setup)(N-.:t)) + local -ra prezto_scripts=(${zroot_dir}/init.zsh(N)) + if (( ${#zfpaths} && ${#prezto_scripts} )); then + # this follows the prezto module format, no need to check for other scripts + zcmds=('source '${^prezto_scripts:A}) + else + # get script with largest size (descending `O`rder by `L`ength, and return only `[1]` first) + local -ra zscripts=(${zroot_dir}/(init.zsh|${zroot_dir:t}.(zsh|plugin.zsh|zsh-theme|sh))(NOL[1])) + zcmds=('source '${^zscripts:A}) + fi + fi + if (( ! ${#zfpaths} && ! ${#zfunctions} && ! ${#zcmds} )); then + _zimfw_print -u2 -PlR "%F{yellow}! ${funcfiletrace[1]}:%B${zname}:%b Nothing found to be initialized. Customize the module name or initialization with %Bzmodule%b options.%f" '' ${zusage} + fi + # Prefix is added to all _zfpaths, _zfunctions and _zcmds to distinguish the originating root dir + local -r zpre=${zroot_dir}$'\0' + _zfpaths+=(${zpre}${^zfpaths}) + _zfunctions+=(${zpre}${^zfunctions}) + _zcmds+=(${zpre}${^zcmds}) fi } @@ -289,23 +317,31 @@ _zimfw_source_zimrc() { print -u2 -PR "%F{red}No modules defined in %B${ztarget}%b%f" return 1 fi + # Remove all from _zfpaths, _zfunctions and _zcmds with disabled root dirs prefixes + local zroot_dir zpre + for zroot_dir in ${_zdisabled_root_dirs}; do + zpre=${zroot_dir}$'\0' + _zfpaths=(${_zfpaths:#${zpre}*}) + _zfunctions=(${_zfunctions:#${zpre}*}) + _zcmds=(${_zcmds:#${zpre}*}) + done } _zimfw_list_unuseds() { local -i i=1 - local -a zinstalled=(${ZIM_HOME}/modules/*(N/)) - local -ar zdirs=(${(v)_zdirs}) + local zinstalled=(${ZIM_HOME}/modules/*(N/)) + local -r zdirs=(${(v)_zdirs}) # Search into subdirectories while (( i <= ${#zinstalled} )); do - if (( ${zdirs[(I)${zinstalled[i]}/*]} || ${_zdisabled_dirs[(I)${zinstalled[i]}/*]} )); then + if (( ${zdirs[(I)${zinstalled[i]}/*]} )); then zinstalled+=(${zinstalled[i]}/*(N/)) zinstalled[i]=() else (( i++ )) fi done - # Unused = all installed dirs not in zdirs and _zdisabled_dirs - _zunused_dirs=(${${zinstalled:|zdirs}:|_zdisabled_dirs}) + # Unused = all installed dirs not in zdirs + _zunused_dirs=(${zinstalled:|zdirs}) local zunused for zunused (${_zunused_dirs}) _zimfw_print -PR "%B${zunused:t}:%b ${zunused}${1}" } @@ -371,20 +407,20 @@ _zimfw_clean_dumpfile() { } _zimfw_compile() { - # Array with unique dirs. ${ZIM_HOME} or any subdirectory should only occur once. - local -Ur zscriptdirs=(${ZIM_HOME} ${${(v)_zdirs##${ZIM_HOME}/*}:A}) # Compile Zim scripts - local zfile - for zfile in ${^zscriptdirs}/(^*test*/)#*.zsh(|-theme)(N-.); do - if [[ ! ${zfile}.zwc -nt ${zfile} ]]; then - zcompile -R ${zfile} && _zimfw_print -PR "%F{green})%f %B${zfile}.zwc:%b Compiled" - fi + local zroot_dir zfile + for zroot_dir in ${_zroot_dirs:|_zdisabled_root_dirs}; do + for zfile in ${zroot_dir}/(^*test*/)#*.zsh(|-theme)(N-.); do + if [[ ! ${zfile}.zwc -nt ${zfile} ]]; then + zcompile -UR ${zfile} && _zimfw_print -PR "%F{green})%f %B${zfile}.zwc:%b Compiled" + fi + done done _zimfw_print -P 'Done with compile.' } _zimfw_info() { - print -R 'zimfw version: '${_zversion}' (built at 2022-08-02 17:46:34 UTC, previous commit is b5703f9)' + print -R 'zimfw version: '${_zversion}' (built at 2022-09-27 01:07:23 UTC, previous commit is 887bfd6)' print -R 'OSTYPE: '${OSTYPE} print -R 'TERM: '${TERM} print -R 'TERM_PROGRAM: '${TERM_PROGRAM} @@ -440,10 +476,11 @@ _zimfw_upgrade() { _zimfw_run_list() { local -r zname=${1} - print -PnR "%B${zname}:%b ${_zdirs[${zname}]}" - if [[ -z ${_zurls[${zname}]} ]] print -Pn ' (external)' - if (( ${_zfrozens[${zname}]} )) print -Pn ' (frozen)' - if (( ${_zdisableds[${zname}]} )) print -Pn ' (disabled)' + local -r zdir=${_zdirs[${zname}]} + print -PnR "%B${zname}:%b ${zdir}" + if [[ -z ${_zurls[${zname}]} ]] print -n ' (external)' + if (( ${_zfrozens[${zname}]} )) print -n ' (frozen)' + if (( ${_zdisabled_root_dirs[(I)${zdir}]} )) print -n ' (disabled)' print if (( _zprintlevel > 1 )); then if [[ ${_zfrozens[${zname}]} -eq 0 && -n ${_zurls[${zname}]} ]]; then @@ -454,13 +491,24 @@ _zimfw_run_list() { print -nR "${_ztypes[${zname}]} ${_zrevs[${zname}]}" fi print -nR ", using ${_ztools[${zname}]}" - if (( ! _zsubmodules[${zname}] )) print -nR ', no git submodules' + if (( ! _zsubmodules[${zname}] )) print -n ', no git submodules' print if [[ -n ${_zonpulls[${zname}]} ]] print -R " On-pull: ${_zonpulls[${zname}]}" fi - # Match and remove the current module prefix from _zfpaths, _zfunctions and _zcmds - local -r zpre=${zname}$'\0' - local -r zfpaths=(${${(M)_zfpaths:#${zpre}*}#${zpre}}) zfunctions=(${${(M)_zfunctions:#${zpre}*}#${zpre}}) zcmds=(${${(M)_zcmds:#${zpre}*}#${zpre}}) + # Match the current module dir prefix from _zroot_dirs + local -r zroot_dirs=(${(M)_zroot_dirs:#${zdir}/*}) + if (( ${#zroot_dirs} )); then + print ' Additional root:' + local zroot_dir + for zroot_dir in ${zroot_dirs}; do + print -nR " ${zroot_dir}" + if (( ${_zdisabled_root_dirs[(I)${zroot_dir}]} )) print -n ' (disabled)' + print + done + fi + # Match and remove the prefix from _zfpaths, _zfunctions and _zcmds + local -r zpre="${zdir}(|/*)"$'\0' + local -r zfpaths=(${${(M)_zfpaths:#${~zpre}*}#${~zpre}}) zfunctions=(${${(M)_zfunctions:#${~zpre}*}#${~zpre}}) zcmds=(${${(M)_zcmds:#${~zpre}*}#${~zpre}}) if (( ${#zfpaths} )) print -R ' fpath: '${zfpaths} if (( ${#zfunctions} )) print -R ' autoload: '${zfunctions} if (( ${#zcmds} )) print -R ' cmd: '${(j:; :)zcmds} @@ -785,8 +833,8 @@ Actions: Options: %B-q%b Quiet (yes to prompts, and only outputs errors) %B-v%b Verbose (outputs more details)" - local -Ua _znames _zdisabled_dirs - local -A _zfrozens _zdisableds _ztools _zdirs _zurls _ztypes _zrevs _zsubmodules _zonpulls + local -Ua _znames _zroot_dirs _zdisabled_root_dirs + local -A _zfrozens _ztools _zdirs _zurls _ztypes _zrevs _zsubmodules _zonpulls local -a _zfpaths _zfunctions _zcmds _zunused_dirs local -i _zprintlevel=1 if (( # > 2 )); then