Quando a função preexec é chamada, zle já está concluído e, portanto, os widgets zle não podem mais ser usados.
Portanto, você deve interceptar a pressão da tecla ENTER antes que zle termine. Por padrão, ENTER está vinculado a accept-line , mas isso pode depender de outros truques que você já usa;
$ bindkey | grep '\^M'
"^M" accept-line
Agora, escrevemos um novo widget que queremos vincular a ENTER :
del-prompt-accept-line() {
OLD_PROMPT="$PROMPT"
PROMPT="> "
zle reset-prompt
PROMPT="$OLD_PROMPT"
zle accept-line
}
A lógica é retirada da sua abordagem. Na última linha, chamamos o widget accept-line ou qualquer outra coisa que foi executada ao pressionar ENTER .
Por fim, apresentamos o novo widget para zle e vinculamos a ENTER :
zle -N del-prompt-accept-line
bindkey "^M" del-prompt-accept-line
Et voilà:
> echo foo bar
foo bar
+------------ Long prompt ----------+
'> echo this is my new command... not pressed ENTER, yet!