我正在尝试实现一个文本滚动较少的 ncurses 应用程序。推荐的方法是什么?
这是我所知道的:
- 您可以使用
scroll
将文本缓冲区向上或向下移动 1 行。但是,如果向下滚动,您将在顶部有一个空白行,如果向上滚动,您将在底部有一个空白行,您必须自己重新绘制。 - Ncurses 会为您自动换行,当我必须确定在步骤 1 中必须重新绘制哪一行时,这会打乱我的数学运算。
我想我可以自己重新实现自动换行并保留所有后换行的数组,但这似乎是一个常见问题,所以可能有更好的方法。
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.
我在 ncurses 方面还不是很有经验,所以我不知道所有的库函数,但是保持文本行的双向链接列表是可行的。这是 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);
}
我不确定这将如何处理超过 128 个字符的行,但这是不同解决方案的不同问题。
至于自动换行,如果您不需要保留原始文本格式,则可以在从文件中读取长行时将它们分成两行。
ncurses 只知道当前屏幕。当屏幕滚动时,ncurses 不会跟踪离开屏幕的任何文本。您的终端可能有一个回滚缓冲区,但它独立于 ncurses,并且 curses 无法查看终端的回滚缓冲区。
如果您需要滚动,我希望您需要跟踪文件中的当前位置。
我不认为 ncurses 做了自动换行 你是怎么做自动换行的?