“readline” quando houver saída no início da linha [closed]

1

Estou usando a biblioteca (excelente) readline (versão 6.3, padrão [não-vi]) de dentro do meu próprio programa, sendo executada em uma janela do Terminal (em um PC). Há um problema quando há saída anterior não terminada pela nova linha quando readline() é chamado.

#include <stdio.h>
#include <readline/readline.h>

void main(void)
{
  // Previous output from some other part of application
  // which *may* have output stuff *not* terminated with a '\n'
  printf("Hello ");
  fflush(stdout);

  char *in = readline("OK> ");
}

Então a linha parece:

Hello OK> <caret here>

Se você digitar um pequeno número de caracteres (até 5?) e, digamos, Ctrl+U (pode ser outros) para excluir sua entrada até certo ponto, tudo parece bem --- readline() move o cursor de volta para logo após o seu próprio prompt. No entanto, tente digitar, por exemplo:

123456 <Ctrl+U>

Agora, ele é excluído para o Hello , deixando apenas Hell na linha, seguido pelo cursor.

Eu preciso de uma das duas soluções possíveis:

  1. Isso parece um bug, agora que eu percebi que depende de quantos caracteres são digitados na linha onde está errado. Qualquer correção / solução alternativa?

  2. Como alternativa, há uma chamada à biblioteca readline que eu poderia fazer, que me diria em que posição / coluna o cursor está antes de invocar readline() ? Então, pelo menos, eu poderia reconhecer o fato de que estou no final de uma linha existente e gerar um \n para me posicionar no começo de uma nova linha.

P.S. Este é um bom lugar para perguntar sobre readline programação no Ubuntu ou devo estar postando em stackoverflow.com ?

    
por JonBrave 17.12.2016 / 11:00

2 respostas

0

Acontece que readline não pode reconhecer se não está começando na coluna # 1 e, assim, parar de atrapalhar a saída anterior na linha.

A única maneira de lidar com isso é reconhecendo a coluna inicial nós mesmos, e mover para o início da próxima linha para baixo se a posição atual for não coluna # 1. Em seguida, ele sempre será iniciado a partir da coluna mais à esquerda, sem gerar uma nova linha desnecessária quando ela já estiver na coluna 1.

Podemos fazer isso para o "Terminal" padrão porque ele entende uma sequência de escape ANSI para consultar a linha atual & amp; coluna do terminal. A consulta é enviada por meio de caracteres para stdout e a resposta é lida por caracteres inseridos pelo terminal em stdin . Devemos colocar o terminal no modo de entrada "raw" para que os caracteres de resposta possam ser lidos imediatamente e não sejam ecoados.

Então aqui está o código:

rl_prep_terminal(1);       // put the terminal into "raw" mode
fputs("3[6n", stdout);  // <ESC>[6n is ANSI sequence to query terminal position
int row, col;              // terminal will reply with <ESC>[<row>;<col>R
fscanf(stdin, "3[%d;%dR", &row, &col);
rl_deprep_terminal();      // restore terminal "cooked" mode
if (col > 1)               // if beyond the first column...
  fputc('\n', stdout);     // output '\n' to move to start of next line

in = readline(prompt);     // now we can invoke readline() with our prompt
    
por JonBrave 24.12.2016 / 10:17
0

[O Stackoverflow seria um lugar mais apropriado para essa questão de programação]

Isso não é um bug, mas o comportamento esperado. readline não está ciente do que foi escrito no terminal antes e em que posição está escrevendo. Pense em "terminal serial básico". Além disso, outros processos em segundo plano (que seu programa não está ciente) também podem gravar no terminal.

Então, readline assume que começa a escrever no início da linha do terminal. Quando você pressiona Ctrl-U (unix-line-discard), readline volta onde pensa que você começou a digitar caracteres, ou seja, logo após o seu prompt. Seu prompt "OK >" tem quatro caracteres, então readline coloca o cursor em 5º lugar e apaga a linha, deixando apenas "Inferno".

A solução alternativa seria pular uma linha antes de chamar readline ou iniciar seu prompt com um caractere CR (por exemplo, \r ), o que forçaria o prompt no início da linha, sobrescrevendo "Hello" (mas texto mais longo seria apenas parcialmente sobrescrito).

[atualização]

Por que às vezes Ctrl-U apaga apenas os últimos caracteres digitados e, às vezes, apaga (quase) toda a linha, é uma otimização de linha de leitura.

readline pode emitir duas seqüências de caracteres diferentes para apagar toda a entrada:

  • : n × <BS> (backspace) + < sequência de controle para apagar toda a linha > (por exemplo, ANSI <ESC> [ K ), em que n é o número de caracteres digitados até o momento.
  • ou: <CR> + m × < seqüência de controle para mover o cursor para a direita > (por exemplo, ANSI <ESC> [ C ) + < sequência de controle para apagar toda a linha & gt ;, onde m é o tamanho do prompt.

readline escolha o menor, que depende do número de caracteres digitados pelo tamanho do seu prompt.

    
por xhienne 17.12.2016 / 12:02