在非规范模式下,输出的行在终端内没有正确换行
Outputed lines doesn't wrap correctlly within a terminal in Non Canonical mode
我正在尝试使用 Termcap
功能实现 bash 的迷你版本,现在我正在尝试读取用户的输入并在终端标准输出中重新输入。
一切正常,但在尝试调整终端大小时出现问题 window,正如您在下面的 gif 中看到的,当我写一个 SINGLE 行,然后缩小 window,然后再次展开它,输出会很好地包装。
但是当我的文本经过第一行终端时(没有按 Enter 键),如果我执行与以前相同的步骤,输出换行与我想要的不同。我需要的是,当缩小 window 时,第一行的最后一个字符必须与第二行字符连接,反之亦然,当我扩展 window 时,第二行的第一个字符与第一行字符。
有没有办法使输出的换行与 bash 完全相同?(将每行连接起来其他)
到目前为止,这是我的代码,如果你想编译它,请使用 -ltermcap
标志,提前致谢。
#include <ctype.h>
#include <termcap.h>
#include <termios.h>
# include <sys/ioctl.h>
# include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int g_screen_width = 0;
int g_cursor_colm = 0;
int g_printed = 0;
int ft_putchar(int c)
{
int len = write(1, &c, 1);
return (len);
}
int ft_isprint(int c)
{
return (c >= 32 && c < 127);
}
void update_cursor_position()
{
g_cursor_colm = g_printed % g_screen_width;
}
void update_screen_width()
{
struct winsize w;
ioctl(STDIN_FILENO, TIOCGWINSZ, &w);
g_screen_width = w.ws_col;
}
void sigwinch_handler(int signo)
{
if (signo == SIGWINCH)
{
update_screen_width();
update_cursor_position();
}
}
void move_cursor_to_colum(int col)
{
char *ch_cap;
ch_cap = tgetstr("ch", NULL);
tputs(tgoto(ch_cap, 0, col), 1, ft_putchar);
}
void move_cursor_down_vertically()
{
char *do_cap;
do_cap = tgetstr("do", NULL);
tputs(do_cap, 1, ft_putchar);
}
void move_cursor_to_next_line()
{
move_cursor_to_colum(0);
move_cursor_down_vertically();
}
void enable_raw_mode()
{
struct termios raw;
tcgetattr(STDIN_FILENO, &raw);
raw.c_lflag &= ~(ECHO | ICANON);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
void disable_raw_mode(struct termios old_termios_state)
{
tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_termios_state);
}
int main()
{
struct termios original_termios_state;
char *term_type = getenv("TERM");
char c;
char *line;
tgetent(NULL, term_type);
tcgetattr(STDIN_FILENO, &original_termios_state);
enable_raw_mode();
update_screen_width();
signal(SIGWINCH, sigwinch_handler);
while (read(STDIN_FILENO, &c, 1))
{
if (ft_isprint(c))
{
ft_putchar(c);
g_printed++;
g_cursor_colm++;
if (g_cursor_colm == g_screen_width)
{
g_cursor_colm = 0;
move_cursor_to_next_line();
}
}
else if (c == 27) // ESC
{
disable_raw_mode(original_termios_state);
exit(0);
}
}
disable_raw_mode(original_termios_state);
return (0);
}
您的终端会记住实际跳行的位置(您在 move_cursor_down_vertically()
中使用 cursor_down 明确执行的那个),而不是终端由于其有限而自行执行的换行宽度。
所以:
- 要么你根本不移动(向下)你的光标,只对 一个 虚拟文本行进行所有处理,让终端根据它的宽度(这可能是最简单的解决方案);
- 或者您在
sigwinch_handler()
收到 SIGWINCH 信号后自己重新绘制屏幕。
我正在尝试使用 Termcap
功能实现 bash 的迷你版本,现在我正在尝试读取用户的输入并在终端标准输出中重新输入。
一切正常,但在尝试调整终端大小时出现问题 window,正如您在下面的 gif 中看到的,当我写一个 SINGLE 行,然后缩小 window,然后再次展开它,输出会很好地包装。
但是当我的文本经过第一行终端时(没有按 Enter 键),如果我执行与以前相同的步骤,输出换行与我想要的不同。我需要的是,当缩小 window 时,第一行的最后一个字符必须与第二行字符连接,反之亦然,当我扩展 window 时,第二行的第一个字符与第一行字符。
有没有办法使输出的换行与 bash 完全相同?(将每行连接起来其他)
到目前为止,这是我的代码,如果你想编译它,请使用 -ltermcap
标志,提前致谢。
#include <ctype.h>
#include <termcap.h>
#include <termios.h>
# include <sys/ioctl.h>
# include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int g_screen_width = 0;
int g_cursor_colm = 0;
int g_printed = 0;
int ft_putchar(int c)
{
int len = write(1, &c, 1);
return (len);
}
int ft_isprint(int c)
{
return (c >= 32 && c < 127);
}
void update_cursor_position()
{
g_cursor_colm = g_printed % g_screen_width;
}
void update_screen_width()
{
struct winsize w;
ioctl(STDIN_FILENO, TIOCGWINSZ, &w);
g_screen_width = w.ws_col;
}
void sigwinch_handler(int signo)
{
if (signo == SIGWINCH)
{
update_screen_width();
update_cursor_position();
}
}
void move_cursor_to_colum(int col)
{
char *ch_cap;
ch_cap = tgetstr("ch", NULL);
tputs(tgoto(ch_cap, 0, col), 1, ft_putchar);
}
void move_cursor_down_vertically()
{
char *do_cap;
do_cap = tgetstr("do", NULL);
tputs(do_cap, 1, ft_putchar);
}
void move_cursor_to_next_line()
{
move_cursor_to_colum(0);
move_cursor_down_vertically();
}
void enable_raw_mode()
{
struct termios raw;
tcgetattr(STDIN_FILENO, &raw);
raw.c_lflag &= ~(ECHO | ICANON);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
void disable_raw_mode(struct termios old_termios_state)
{
tcsetattr(STDIN_FILENO, TCSAFLUSH, &old_termios_state);
}
int main()
{
struct termios original_termios_state;
char *term_type = getenv("TERM");
char c;
char *line;
tgetent(NULL, term_type);
tcgetattr(STDIN_FILENO, &original_termios_state);
enable_raw_mode();
update_screen_width();
signal(SIGWINCH, sigwinch_handler);
while (read(STDIN_FILENO, &c, 1))
{
if (ft_isprint(c))
{
ft_putchar(c);
g_printed++;
g_cursor_colm++;
if (g_cursor_colm == g_screen_width)
{
g_cursor_colm = 0;
move_cursor_to_next_line();
}
}
else if (c == 27) // ESC
{
disable_raw_mode(original_termios_state);
exit(0);
}
}
disable_raw_mode(original_termios_state);
return (0);
}
您的终端会记住实际跳行的位置(您在 move_cursor_down_vertically()
中使用 cursor_down 明确执行的那个),而不是终端由于其有限而自行执行的换行宽度。
所以:
- 要么你根本不移动(向下)你的光标,只对 一个 虚拟文本行进行所有处理,让终端根据它的宽度(这可能是最简单的解决方案);
- 或者您在
sigwinch_handler()
收到 SIGWINCH 信号后自己重新绘制屏幕。