Стрелка навигационного ввода в C

Я создаю интерфейс оболочки для программы, сначала я использовал getline в сочетании с strtok разделять запись пользователя, но это не лучший выбор, потому что, если передана строка в кавычках, она будет разбита на несколько аргументов, или, если в строке в кавычках есть пробелы, они будут проигнорированы. Кроме того, я хотел бы реализовать некоторые основные функции оболочки, такие как ярлык Ctrl-L для очистки оболочки.

Поэтому я решил пользователя termios и создать свою собственную функцию для ввода в оболочке.

На данный момент код выглядит

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>


char *read_cmdline() {
    struct termios oldt;
    struct termios newt;
    tcgetattr(STDIN_FILENO, &oldt); /*store old settings */
    newt = oldt; /* copy old settings to new settings */
    newt.c_lflag &= ~(ICANON | ECHO); /* make one change to old settings in new settings */
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); /*apply the new settings immediatly */

   char *line = malloc(128); 
   int end_of_line = 0;
   char c, y, z;
   unsigned lus = 0;
   unsigned size = 128;

   while (!end_of_line) {

       if (lus+1 == size) {
           size *= 2;
           line = realloc(line, size);
       }

       c = getc(stdin);

       switch (c)
       {
           case 27:
               y = getchar();
               switch (y)
               {
                   case 91:
                       z = getchar();
                       switch (z)
                       {
                           case 65:
                               printf("up arrow key pressed\n");
                               continue;

                           case 66:
                               printf("down arrow key pressed\n");
                               continue;

                           case 67:
                               printf("right arrow key pressed\n");
                               continue;

                           case 68:
                               printf("left arrow key pressed\n");
                               continue;
                       }
                       break;
               }
           case 12:
               system("clear");
               break;
       }
       if (c  >= 32 && c <= 126) {
           putchar(c);
           line[lus++] = c;
       }
       else if (c == 13)
           end_of_line = 1;
   }
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /*reapply the old settings */
    return line;
}

Синтаксический анализ пока не реализован, только базовое чтение строки с ярлыком Ctrl-L реализовано также.

Как сделать навигацию влево / вправо в строке?

Редактировать: у меня есть реализация, которая теперь может перемещаться по одной строке, но несколько строк не работают с этим кодом:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>

#define MIN_SIZE 128
char *line = NULL;
static unsigned pos = 0;
static int size;
static int b_size;
static unsigned length = 0;
char *buff = NULL;
static unsigned b_pos = 0;
static unsigned b_length = 0;


void insert(char c)
{
    if (pos == length) {
        ++length;
        if (length == size) {
            size *= 2;
            line = realloc(line, size);
        }
        line[pos++] = c;
    }
    else {
        ++length;
        if (length == b_size) {
            b_size = size;
            size *= 2;
            buff = realloc(buff, size);
        }
        strncpy(buff, line, pos);
        strncpy(&buff[pos+1], &line[pos], length-pos);
        buff[pos++] = c;
        char *temp = buff;
        buff = line;
        line = temp;
    }
}

int move_cursor(int delta) {
    int pos2 = pos + delta;
    if (pos2 >= 0 && pos2 <= length) {
        pos = pos2;
        return 1;
    }
    else
        return 0;
}

int backspace() {
    if (pos == 0)
        return 0;
    else {
        strncpy(&line[pos-1], &line[pos], length - pos);
        --pos;
        --length;
        return 1;
    }
}

int suppr() {
    if (pos == length)
        return 0;
    else {
        strncpy(&line[pos], &line[pos+1], length-pos);
        --length;
    }
}

char *read_cmdline() {
    if (line == NULL) 
        line = malloc(MIN_SIZE);
    if (buff == NULL)
        buff = malloc(MIN_SIZE);
    struct termios oldt;
    struct termios newt;
    tcgetattr(STDIN_FILENO, &oldt); /*store old settings */
    newt = oldt; /* copy old settings to new settings */
    newt.c_lflag &= ~(ICANON | ECHO); /* make one change to old settings in new settings */
    tcsetattr(STDIN_FILENO, TCSANOW, &newt); /*apply the new settings immediatly */

   int end_of_line = 0;
   char c, y, z;

   while (!end_of_line) {

       c = getc(stdin);

       switch (c)
       {
           case 127:
               backspace();
               putchar('\b');
           case 27:
               y = getchar();
               switch (y)
               {
                   case 91:
                       z = getchar();
                       switch (z)
                       {
                           case 65:
                               printf("up arrow key pressed\n");
                               continue;

                           case 66:
                               printf("down arrow key pressed\n");
                               continue;

                           case 67:
                               printf("right arrow key pressed\n");
                               continue;

                           case 68:
                               printf("\033[1D");
                               move_cursor(-1);
                               continue;
                       }
                       break;
               }
           case 12:
               system("clear");
               break;
       }
       if (c  >= 32 && c <= 126) {
           insert(c);
           printf("\033[%dD", length);
           printf("%s", line);
           if (pos < length)
               printf("\033[%dD", length-pos);
       }
       else if (c == 13)
           end_of_line = 1;
   }
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt); /*reapply the old settings */
    return line;
}

Проблема в том, как я реализовал печать в цикле while, мне нужно восстановить размер терминала и печатать в соответствии с этим размером... Это сложная проблема! Я не упомянул, что не хочу добавлять зависимости в свой проект, поэтому ncurses не разрешен, но это проект UNIX, поэтому нет необходимости в совместимости платформы. (проклятия стандартны?)

0 ответов

Другие вопросы по тегам