Como iniciar o XTerm com o prompt na parte inferior?

12

Ao iniciar o XTerm, o prompt inicia na primeira linha do terminal. Ao executar comandos, o prompt desce até chegar ao fundo e, a partir de então, permanece lá (nem mesmo Shift- Page Downou o mouse pode mudar isso). Em vez de o início da vida útil do terminal ser "especial", o prompt deve sempre estar na parte inferior do terminal. Observe que eu tenho um prompt de várias linhas .

Obviamente, ele deve funcionar como antes (redimensionável, rolável, sem novas linhas desnecessárias na saída e nenhuma saída desaparecendo misteriosamente), portanto, PROMPT_COMMAND='echo;echo;...'ou similar, não é uma opção. A solução idealmente não deve ser específica do shell.

Edit: A solução atual , enquanto trabalha em casos simples, tem alguns problemas:

  • É específico do Bash . Uma solução ideal deve ser portátil para outras conchas.
  • Ele falha se outros processos modificarPS1 . Um exemplo é o virtualenv, que adiciona (virtualenv)no início de PS1, que desaparece sempre logo acima da dobra.
  • Ctrl- lagora remove a última página do histórico.

Existe uma maneira de evitar esses problemas, além de bifurcar o XTerm?

l0b0
fonte
De alguma forma, precisamos introduzir caracteres em branco no buffer da barra de rolagem do Xterm.
SHW
3
Na verdade, o prompt pode ser facilmente movido de volta ao topo a qualquer momento, executando o clearcomando.
Werediver
@ SHW Eu esperava que houvesse uma configuração para isso, em vez de um hack. Os hacks de terminal tendem a introduzir bugs muito sutis na minha experiência.
L0b0
@werediver Mas eu nunca quero que fique no topo.
L0b0
1
Como apenas o shell sabe quando gera um prompt, qualquer solução deve estar no contexto do shell. Mesmo a bifurcação do XTerm não ajudará, porque o XTerm não sabe se o que é solicitado a saída é um prompt ou não. Para o terminal, o prompt do shell é apenas outra sequência de caracteres, diferente de qualquer outra sequência de caracteres que possa receber.
Celtschk #

Respostas:

11

Se estiver usando bash, o seguinte deve fazer o truque:

TOLASTLINE=$(tput cup "$LINES")
PS1="\[$TOLASTLINE\]$PS1"

Ou (menos eficiente, pois executa um tputcomando antes de cada prompt, mas funciona após o redimensionamento da janela do terminal):

PS1='\[$(tput cup "$LINES")\]'$PS1

Para impedir a tputalteração do código de saída, você pode salvá-lo e redefini-lo explicitamente:

PS1='\[$(retval=$?;tput cup "$LINES";exit $retval)\]'$PS1

Observe que a variável retvalé local; isso não afeta nenhuma retvalvariável que você possa ter definido no shell.

Como a cupcapacidade da maioria dos terminais é a mesma \e[y;xH, você também pode codificá-la:

PS1='\[\e[$LINES;1H\]'$PS1

Se você quiser que seja seguro contra redefinições posteriores do PS1, você também pode utilizar a PROMPT_COMMANDvariável. Se definido, ele será executado como comando antes da saída do prompt. Portanto, o efeito também pode ser alcançado por

PROMPT_COMMAND='(retval=$?;tput cup "$LINES";exit $retval)'

É claro que, embora a redefinição PS1não afete isso, alguns outros softwares também podem mudar PROMPT_COMMAND.

celtschk
fonte
Como tputdiferem de muitos echocomandos? (Pedindo por curiosidade) #
SHW
@ l0b0, provavelmente não merece uma resposta separada. Espero que o celtschk não se importe de ter editado sua resposta.
Stéphane Chazelas
'\[$(tput cup "$LINES")\]' funciona lindamente . Obrigado!
L0b0
Há um problema com tput: Parece redefinir $exit_code. Corrigido usando \[\e[$LINES;1H\].
L0b0
1
@ l0b0: agora adicionei uma versão usando tputque preserva o código de saída.
Celtschk 11/09/14
4

Como uma pequena simplificação da resposta anterior, achei mais fácil executar:

tput cup $LINES

no começo de .bashrcou .zshrc. Apenas faz o trabalho.

Prós:

  • só imprime uma vez, quando você inicia seu shell

Contras:

  • ao limpar a tela com ^ L, não imprimir e aliasing clearpara clear; tput ...não ajuda;
  • prompt se move para outro lugar quando o terminal é redimensionado
phil pirozhkov
fonte
2

As respostas usadas $LINESsão desnecessariamente não portáteis. Conforme feito resize, você pode simplesmente pedir xtermpara definir a posição com um número de linha arbitrariamente grande, por exemplo,

tput cup 9999 0

(supondo que você tenha uma janela menor que 10 mil linhas, desconsiderando a rolagem ).

Como a sequência não será alterada como um efeito colateral do redimensionamento da janela, você pode calcular isso uma vez e colá-la na sequência de prompt como uma constante, por exemplo,

TPUT_END=$(tput cup 9999 0)

e depois

PS1="${TPUT_END} myprompt: "

de acordo com suas preferências.

Quanto a outros processos de modificação PS1: você terá que recalcular PS1após essas alterações, para garantir que ela tenha a aparência desejada. Mas não há detalhes suficientes na pergunta para apontar onde fazer as alterações.

E finalmente: o comportamento de conclusão de tabulação não combina com esse tipo de alteração, devido às suposições do bash.

Thomas Dickey
fonte
O que você quer dizer com "o comportamento de conclusão de tabulação não combina com esse tipo de alteração"?
L0b0
Eu acho que você quer dizer PS1="${TPUT_END} myprompt: ", ou mesmoPS1="${TPUT_END}${PS1}"
l0b0
Para o último - certo (erro de digitação de makefiles). Para os primeiros, tenho em mente que a edição de comandos do bash depende de ser capaz de reimprimir a linha (com prompt), e que você pode ter um comportamento estranho quando isso se combina com a rolagem devido à conclusão do comando.
21416 Thomas Dickey