Vou abordar apenas a questão (1).
Seu problema é KEYTIMEOUT. Cito zshzle (1):
Quando o ZLE está lendo um comando do terminal, ele pode ler uma sequência que está vinculada a algum comando e também é um prefixo de uma cadeia de caracteres mais longa. Nesse caso, o ZLE aguardará um certo tempo para ver se mais caracteres são digitados e, se não (ou não corresponderem a nenhuma sequência mais), ele executará a ligação. Esse tempo limite é definido pelo parâmetro KEYTIMEOUT; seu padrão é 0,4 seg. Não haverá tempo limite se a sequência do prefixo não estiver vinculada a um comando.
0,4s é o atraso que você está enfrentando depois de pressionar ESC. A correção é definir KEYTIMEOUT até 0,01s em um dos arquivos de inicialização do shell:
export KEYTIMEOUT=1
Infelizmente, isso tem um efeito indireto: outras coisas começam a dar errado ...
Primeiro, agora existe um problema no modo de comando vi: digitar ESC faz com que o cursor seja interrompido e, em seguida, o caractere digitado a seguir é engolido. Isso ocorre porque o ESC não está vinculado a nada por padrão no modo de comando vi, mas existem widgets com vários caracteres que começam com ESC (teclas do cursor!). Então, quando você pressiona ESC, o ZLE aguarda o próximo caractere ... e o consome.
A correção é ligar o ESC a algo no modo de comando, garantindo assim que o algo seja passado para o ZLE após $ KEYTIMEOUT centisegundos. Agora podemos manter as ligações começando com ESC no modo de comando sem esses efeitos nocivos. Vinculo ESC ao caractere bell, que considero menos invasivo do que a inserção automática (e meu shell é silenciado):
bindkey -sM vicmd '^[' '^G'
Atualização 2017:
Desde então, encontrei uma solução ainda melhor para vincular o ESC - o undefined-key
widget. Não tenho certeza se este widget estava disponível no zsh quando escrevi originalmente esta resposta.
bindkey -M vicmd '^[' undefined-key
Próximo problema: por padrão, existem widgets de duas teclas iniciando em ^ X no modo de inserção vi; eles se tornarão inutilizáveis se $ KEYTIMEOUT estiver definido até o fim. O que faço é desvincular ^ X no modo vi insert (é auto-inserir por padrão); isso permite que esses widgets de duas chaves continuem funcionando.
bindkey -rM viins '^X'
Você perde a ligação para a inserção automática, mas pode vinculá-la a outra coisa, é claro. (Não, pois não tenho utilidade para isso.)
O último problema (que encontrei até agora): Existem algumas combinações de teclas padrão restantes que "perdemos" devido à configuração de $ KEYTIMEOUT logo abaixo, ou seja: aquelas que começam com ESC no modo de inserção vi que não são teclas de cursor. Pessoalmente, eu os religuei para começar com ^ X:
bindkey -M viins '^X,' _history-complete-newer \
'^X/' _history-complete-older \
'^X`' _bash_complete-word
Atualização 2018:
Acontece que a seção inteira acima (após a "Atualização 2017") não é necessariamente necessária. É possível definir a tecla META como equivalente ao ESC nos mapeamentos de teclado usando:
bindkey -mv
Portanto, é possível não desvincular ^ X e acessar as combinações de teclas iniciadas no ESC pressionando META como líder (ALT ou OPT nos teclados modernos).
Se você tiver acesso ao livro From Bash to Z Shell de Kiddle et al., A equivalência de ESC e META em combinações de teclas é discutida na barra lateral do Capítulo 4 nas páginas 78–79.
i
duas vezes para voltar ao modo de inserção, eu recomendo essa correção!