fix(cli): address review feedback on omz generate plugin

- Turn %placeholders% into private markers when a template is read and
  strip the marker from every value, so text inserted from user input
  (e.g. -d '%name%') is never rescanned as a placeholder.
- When --enable is used for a name already in $plugins (a custom
  override of an enabled built-in), report it and reload instead of
  failing in _omz::plugin::enable.
- Make the completion note accurate whether or not a _<cmd> file was
  generated.
- Test the write-phase cleanup with a template set missing a later
  template, and test that placeholder-looking values come out literally.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Robby Russell
2026-09-05 14:48:54 -07:00
co-authored by Claude Fable 5.1
parent 46aee25f27
commit de76990950
3 changed files with 53 additions and 15 deletions
+28 -14
View File
@@ -429,7 +429,13 @@ function _omz::generate::plugin {
# Last thing we do: in an interactive shell this restarts zsh
if (( enable )); then
print
_omz::plugin::enable "$name"
if (( ${plugins[(Ie)$name]} )); then
# Already enabled (e.g. a custom override of a built-in): just reload
_omz::log info "'$name' is already in your plugins list."
[[ ! -o interactive ]] || _omz::reload
else
_omz::plugin::enable "$name"
fi
fi
}
@@ -516,31 +522,39 @@ function _omz::generate::plugin::ask {
REPLY="${${REPLY##[[:space:]]#}%%[[:space:]]#}"
}
# Print a template file, or explain which one is missing
# Print a template file with its %placeholders% turned into private markers,
# or explain which one is missing
function _omz::generate::plugin::template {
if [[ ! -f "$templates/$1" ]]; then
_omz::log error "missing template '${templates/#$HOME/\~}/$1'." "omz::generate::plugin"
return 1
fi
print -r -- "$(<"$templates/$1")"
local content="$(<"$templates/$1")" token m=$'\x1f'
for token in completion cache name command description compgen; do
content="${content//\%${token}\%/${m}${token}${m}}"
done
print -r -- "$content"
}
# Fill in the %placeholders% of a template and write it to a file. Values come
# Fill in the placeholders of a template and write it to a file. Values come
# from the caller: $name, $cmd, $description, $compgen, $block and $cache.
# Substitution is done with parameter expansion rather than sed so that the
# values are always taken literally.
#
# Placeholders are matched as the markers that ::template produced, and the
# marker character is stripped from every value, so a value that happens to
# look like a placeholder (e.g. -d '%name%') is written out literally.
function _omz::generate::plugin::render {
setopt localoptions extendedglob
local content
local content m=$'\x1f'
content="$(_omz::generate::plugin::template "$1")" || return 1
# Blocks go first: they contain placeholders of their own
content="${content//'%completion%'/$block}"
content="${content//'%cache%'/$cache}"
content="${content//'%name%'/$name}"
content="${content//'%command%'/$cmd}"
content="${content//'%description%'/$description}"
content="${content//'%compgen%'/$compgen}"
# Blocks go first: they are templates too and carry markers of their own
content="${content//${m}completion${m}/$block}"
content="${content//${m}cache${m}/$cache}"
content="${content//${m}name${m}/${name//$m/}}"
content="${content//${m}command${m}/${cmd//$m/}}"
content="${content//${m}description${m}/${description//$m/}}"
content="${content//${m}compgen${m}/${compgen//$m/}}"
# Drop blank lines left behind by an empty placeholder at the end
content="${content%%$'\n'##}"