> The menu invoked by a second TAB is based on where the cursor started,
> not on where it is. In this case the cursor was originally after the
> "z", so if you have "foo-baz" on the line after the first tab, the
> second tab selects that as an exact match.
Thanks for the explanation!
> If you start with the cursor to the left of "z", e.g.
>
> % ls z<LEFT><TAB>
>
> Then you get the placement "foo-ba|z" and complete-in-word acts as you expect.
This makes perfect sense: the cursor started originally before "z" and is now before "z" for the next completion attempt. The difference with the other "ls z<TAB>" scenario is that in this case both the "screen cursor" and the "completion cursor" are in the same position.
I wonder what could be done to avoid that situation where the "screen cursor" and the "completion cursor" are not in the same position, or to avoid the <TAB> triggering a completion in that situation. Besides a possible customization to make completion behave as if "in" the word, maybe if completion would only fill in the common prefix, but not the common suffix (and only a common suffix if there's no common prefix).
Might be completely unrelated regarding how this was achieved, but I've unintentionally found this behavior that drops the typed in suffix and fills in the common prefix:
% zstyle ':completion:*' matcher-list 'r:|[._-]=* r:|=*' '+l:|=*'
% ls z<LEFT><TAB>
% ls foo-ba