开发者

What is the recommended way to implement text scrolling in ncurses?

I am trying to implement an ncurses app with text scrolling like less. What is the recommended way to do this?

Here's what I know:

  1. You can use scroll to move the text buffer up or down by 1 row. However, you'll end up with one blank line at the top if you scroll down, or at the bottom if you scroll up, which you'll have to repaint yourself.
  2. Ncurses does wordwrap for you, which messes up my math when I have to determine what l开发者_JAVA百科ine I have to repaint in step 1.

I guess I could re-implement wordwrap myself and keep an array of all the post-wrapped lines, but this seems like a common problem, so there might be a better way.


The answer depends on how much text you have, and what other uses you are making of the data on the screen. But usually the pad feature is preferred way to display scrollable text. This is not only an ncurses feature, but is supported by most implementations of curses (i.e., anything after the late 1980s).

A pad is like a window, but its size is not limited to the current screen size. Instead, the data is shown through a view whose position within the pad can be easily changed.

There are two sample programs in ncurses-examples which are relevant: view.c displays a file by writing its contents onto a window, while padview.c uses a pad on which the entire file is drawn, and uses the pad-functions for moving the view around as needed, up/down, and left/right.

In those programs, the show_all function does the actual drawing, and is about a third as long for padview.c (35 lines) compared to the equivalent for view.c (94 lines).

Further reading: discussion of view as an example for comparing ncurses and slang libraries.


I'm not very experienced in ncurses yet, so I don't know all the library functions, but keeping a doubly-linked list of text lines could work. Here's a primitive clone of less:

#include <ncurses.h>
#include <stdlib.h>

#define MAXLEN 128

typedef struct Line {
    char contents[MAXLEN];
    struct Line *prev, *next;
} Line;

Line *head, *curr;

int nr_lines;
int curr_line;

int term_rows, term_cols;

void load(const char *filename);
void draw(Line *l);

int main(int argc, char **argv)
{
    if (argc == 1)
    {
        fputs("less: No file to open\n", stderr);
        return 1;
    }

    initscr();
    noecho();
    keypad(stdscr, TRUE);   // for KEY_UP, KEY_DOWN
    getmaxyx(stdscr, term_rows, term_cols);
    addstr("Reading text...\n");

    load(argv[1]);

    curr = head;
    curr_line = 0;
    draw(curr);

    int ch;
    while ((ch = getch()) != EOF && ch != 'q')
    {
        if (ch == KEY_UP && curr->prev != NULL)
        {
            curr_line--;
            curr = curr->prev;
        }
        else if (ch == KEY_DOWN && curr->next != NULL
            && curr_line + term_rows < nr_lines)
        {
            curr_line++;
            curr = curr->next;
        }
        draw(curr);
    }

    endwin();
    return 0;
}

void load(const char *filename)
{
    FILE *fp = fopen(filename, "r");
    Line *lp;

    head = malloc(sizeof(Line));
    head->prev = head->next = NULL;
    curr = head;

    while (fgets(curr->contents, MAXLEN, fp))
    {
        lp = malloc(sizeof(Line));
        lp->prev = curr;
        curr->next = lp;
        curr = lp;
        nr_lines++;
    }
    curr->next = NULL;
}

void draw(Line *l)
{
    int i;
    clear();
    for (i = 0; i < term_rows && l != NULL; i++, l = l->next)
        addstr(l->contents);
}

I'm not sure how this would handle lines longer than 128 characters, but that's a different problem with a different solution.

As for word wrapping, if you don't need to preserve the original text format you could split long lines into two as they're read from the file.


ncurses only knows about the current screen. When the screen is scrolled ncurses does not keep track of any text that leaves the screen. Your terminal might have a scroll back buffer but that is independent of ncurses and curses has no visibility into the terminal's scroll back buffer.

I expect that you will need to keep track of your current location in the file if you need to scroll.

I didn't think ncurses did word wrap how are you doing the word wrap?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜