Per Copilot review on #987: _zsh_highlight_main__type's cache is keyed
on the command name alone, so classifying a name once under PATH_DIRS
(e.g. as a plain top-level command) would silently poison later
lookups of that same name after sudo -- and vice versa -- regardless
of the PATH_DIRS removal, since the cache lookup happens before
$options_to_set is even consulted.
Give _zsh_highlight_main__type an explicit no_cache parameter, and
add _zsh_highlight_main__type_maybe_no_pathdirs(), a small wrapper
that only shadows $options_to_set (and only bypasses the cache) when
PATH_DIRS was actually present to remove -- so a user without
PATH_DIRS set sees this codepath do nothing at all. Both call sites
in the main word-classification block now go through this wrapper
instead of duplicating the shadowing logic inline.
Strengthened sudo-path_dirs.zsh to classify the same name twice in
one buffer (plain, then sudo-prefixed) specifically to exercise this
cache interaction, not just the PATH_DIRS removal in isolation.
Verified via WSL zsh 5.9: make test passes (same 28 pre-existing
TODO failures, zero new), and the strengthened test fails as expected
(observes "command" instead of "unknown-token" on the sudo-prefixed
occurrence) when run against the pre-fix highlighter.
sudo(8) (and env, nice, and other entries in \$precommand_options)
resolve their target command via execvp(3)-style lookup, which never
searches \$path for a name containing a slash -- unlike the shell's
own PATH_DIRS option. So "sudo foo/bar" was highlighted as a valid
command whenever the user had PATH_DIRS set and some \$path element
made "foo/bar" resolvable that way, even though sudo itself would
fail to find it.
:sudo_opt: already marks every word from a recognised precommand up
to and including its actual command word (for any precommand in
\$precommand_options, not just sudo). Key off that existing marker to
shadow PATH_DIRS out of \$options_to_set for just those two
_zsh_highlight_main__type calls, via an anonymous-function scope so
the shadow reverts automatically and normal command-word classification
elsewhere in the line is unaffected.
Fixes#595.