Bash: newline condicional em quebra PS1 typeahead

2

Eu uso o Bash, e meu PS1 abrange duas linhas.

╭-ivan·dotfiles (master)
╰ဝ █

Ocasionalmente, eu executo um comando cuja saída não tem uma nova linha, e meu prompt fica desalinhado,

╭-ivan·dotfiles (master)
╰ဝ curl localhost:3002/is_alive
{"web_server_status":"success","db_status":"success"}╭-ivan·dotfiles (master)
╰ဝ █

Eu finalmente encontrei uma solução que preenche condicionalmente uma nova linha para o prompt se o cursor estiver além da primeira coluna:

build_prompt() {
  export PS1="\$(ps1_head)...
}

ps1_head() {
  if (( $(cursor_col) > 1 )); then
    printf '\n╭-'
  else
    printf '╭-'
  fi
}

cursor_col() {
  local _row col
  IFS=';' read -s -dR -p $'3[6n' _row col
  echo "${col}"
}

Isso corrigiu o problema original,

╭-ivan·dotfiles (master)
╰ဝ curl localhost:3002/is_alive
{"web_server_status":"success","db_status":"success"}
╭-ivan·dotfiles (master)
╰ဝ █

mas, é introduzido um novo. Eu confio no typeahead para permitir que eu digite meu próximo comando antes que o atual seja concluído. A nova linha condicional parece quebrar esse comportamento.

Um exemplo sem a lógica de nova linha de condição:

╭-ivan·dotfiles (master)
╰ဝ git status
On branch master
Your branch is up-to-date with 'origin/master'.

lnothing to commit, working tree clean
s╭-ivan·dotfiles (master)
╰ဝ ls
myfile.txt

Observe que eu digitei l ( lnothing to commit ) antes que a saída do primeiro comando tivesse terminado de ser impressa e digitei s depois que o primeiro comando foi concluído, mas antes do prompt ser impresso. O typeahead graciosamente puxou ambos os chars ( ls ) para o próximo comando.

Agora, o mesmo exemplo com a lógica de nova linha condicional no meu prompt:

╭-ivan·dotfiles (master)
╰ဝ git status
On branch master
Your branch is up-to-date with 'origin/master'.

lnothing to commit, working tree clean
s╭-ivan·dotfiles (master)
╰ဝ s
bash: s: command not found

Observe como, desta vez, typeahead puxou graciosamente o s para o segundo comando, mas deixou o l para trás.

Existe alguma maneira de lidar com isso com mais graça, ou devo finalmente mudar para o zsh?

    
por ivan 20.09.2017 / 23:46

1 resposta

1

Eu tenho um texto de prompt dinâmico como este e não há problemas com o typeahead. Mas, em vez de incorporar a substituição de processo diretamente em PS1 , uso PROMPT_COMMAND para chamar métodos de configuração. Eles produzem o texto dinâmico apropriado que é armazenado em variáveis e as variáveis são então incorporadas em PS1 .

Então, tente algo assim ...

export ps1_head_text

build_prompt() {
  export PS1="\${ps1_head_text}..."
}

ps1_head() {
  if (( $(cursor_col) > 1 )); then
    ps1_head_text=$'\n'╭-
  else
    ps1_head_text=╭-
  fi
}

export PROMPT_COMMAND=ps1_head

Eu acabei fazendo isso precisamente porque eu tive problemas com a substituição de processos (embora eu não me lembre se foi um erro ou algum outro problema).

Editar: Agora que penso nisso, você pode ter problemas de tempo ... se PROMPT_COMMAND for chamado por vez, o que impede uma leitura correta da posição do cursor. Se isso acontecer, provavelmente você está no barco "use zsh". Mas dê uma chance.

Atualização: de acordo com comentário da dave_thompson_085 ler a resposta para emitir uma seqüência de escape (para imprimir a posição do cursor) pode entrar em conflito com a entrada typeahead.

Faz sentido, pois a leitura está ocorrendo no mesmo shell em que o texto do cabeçalho é digitado. Então, e se você não fizer isso no mesmo shell? O rodeia com parentes para colocá-lo em um subshell ajuda? Que tal redirecionar a resposta do terminal (por exemplo, para um arquivo ou pipe ou qualquer outro) e lê-lo de lá?

Parece que há uma maneira de superar o problema, por isso estou jogando algumas coisas contra a parede para ver o que pega.

    
por 21.09.2017 / 03:47

Tags