需要帮助在我的自定义 CLI 中使用 ncurses 进行命令输出分页

Need help using ncurses for command output pagination in my custom CLI

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

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

这是我使用的简单代码:

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
}

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

除此之外,欢迎任何改进我的简单寻呼机的想法...

虽然您已经在着手处理它,但这里有一个向后移动的实现,它利用 fseek() 来记录 (physical/window) 行开头的偏移量,这些行是在读取行时收集的:

    …
    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。