【问题标题】:Need help using ncurses for command output pagination in my custom CLI在我的自定义 CLI 中使用 ncurses 进行命令输出分页需要帮助
【发布时间】:2019-02-04 15:51:25
【问题描述】:

我的 CLI 命令输出需要一个简单的寻呼机。我希望能够在输出中向上/向下滚动,一次一整页或一行一行。

我看了一下“less”的源代码,但它太复杂了,无法帮助我。于是我开始自己写一个简单的。到目前为止,我所做的是将命令输出写入文件。然后逐行读取文件并写入ncurses窗口。当我到达窗口底部时,我等待用户按下一个键,然后清除屏幕并写入一个新页面,依此类推。结果类似于“更多”命令。

这是我使用的简单代码:

int print()
{
    FILE *fp;
    ssize_t read;
    int row, col, x, y;
    char *line = NULL;
    char c;
    size_t len;

    initscr();
    getmaxyx(stdscr, row, col);

    fp = fopen("path_to_output_file", "r");

    if (!fp)
    {
        printf("Failed to open CLI output file.\n");
        return -1;
    }

    while ((read = getline(&line, &len, fp)) != -1)
    {
        getyx(stdscr, y, x);

        if (y == (row - 1))
        {
            printw("Press Any Key to continue...");
            c = getch();

            if (c == 'q')
            {
                break;
            }

            clear();
            move(0, 0);
        }

        printw(line);
        refresh();
    }

    fclose(fp);
    getch();
    endwin();

    return 0
}

现在我需要帮助来找到实现向后滚动以在输出中向上移动一页/行的想法。我应该如何遍历文件并将行打印到 ncurses 窗口以获得我想要的结果。

除此之外,任何改进我的简单寻呼机的想法都值得赞赏...

【问题讨论】:

  • CLI 输出 是否可以包含比窗口宽度更长的行?它可以包含 TAB 吗?
  • @Armali 两个问题都是。现在我正在努力。我创建了一个大小为window_rowschar * 数组。该数组的每个元素都是大小为window_cols 个字符的字符串。我从文件中读取了这么多数据并打印到 ncurses 窗口。我解决了你提到的第一个问题。但是 TAB 字符仍然是一个问题,但现在我忽略了它。

标签: c pagination ncurses


【解决方案1】:

虽然您已经在研究它,但这里有一个向后移动的实现,它利用fseek() 来归档(物理/窗口)行开始的偏移量,在读取行时收集:

    …
    keypad(stdscr, TRUE);   // enable returning function key tokens
    long offset, *pos = NULL, lineno = 0;
    char buffer[col+1];
    TABSIZE = 1;
    do
    {   y = 0;
        long topline = lineno;
        while (offset = ftell(fp), line = fgets(buffer, sizeof buffer, fp))
        {
            pos = realloc(pos, (lineno+1) * sizeof *pos);   if (!pos) exit(1);
            pos[lineno++] = offset; // save offset of current line
            addstr(line);
            getyx(stdscr, y, x);
            if (y == row-1)
                break;
        }
        printw("Press [upward arrow] or [Page Up] or any key to continue...");
        int c = getch();
        if (c == KEY_UP)    // Up arrow
            fseek(fp, pos[lineno = topline>1 ? topline-1 : 0], SEEK_SET);
        else
        if (c == KEY_PPAGE) // Previous page
            fseek(fp, pos[lineno = topline>=row ? topline-row+1 : 0], SEEK_SET);
        else
        if (c == 'q' || !line)
            break;

        clear();
        move(0, 0);
    } while (1);

    fclose(fp);
    endwin();
    …

作为处理 TAB 问题的一种简单方法,我将 TABSIZE 设置为 1。

【讨论】:

  • 非常感谢。我会检查一下并在这里发送反馈。
  • 您的代码按预期工作。谢谢。如果您对处理 TAB 字符有任何想法,我会很高兴听到的。再次感谢:)
  • @Mahdi.B - 你考虑过我对TABSIZE 的编辑吗?或者您是否寻求一种更精细的方式来处理 TAB?
  • 是的,我考虑过。在这个时候,它不是那么重要。我只是想知道你是否已经有了想法。很快我应该处理解析 ansii 颜色代码以与 ncurses 一起使用,也许那时我也会处理 TAB 字符。感谢您的帮助:)
  • @Mahdi.B - ...一个想法:如果我想将 TAB 扩展到多个空格,我可能会编写一个特殊的输入函数来替换 fgets(),即时扩展 TAB到空格,同时考虑行缓冲区大小。这样,上述代码的逻辑就不会受到影响。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-02
  • 1970-01-01
相关资源
最近更新 更多