简体   繁体   English

在非规范模式下,输出的行不能在终端内正确换行

[英]Outputed lines doesn't wrap correctlly within a terminal in Non Canonical mode

I am trying to implement a mini version of bash using Termcap capabilities, and now I am trying to read user's input and retype it in the terminal Stdout.我正在尝试使用Termcap功能实现 bash 的迷你版本,现在我正在尝试读取用户的输入并在终端 Stdout 中重新输入。

Every thing is working fine, but the problem occurs when trying to resize the terminal window, as you can see in the below gif, when I write a SINGLE line and then shrink the window, and expand it again the output wraps good as it should.一切正常,但是在尝试调整终端 window 的大小时会出现问题,正如您在下面的 gif 中看到的那样,当我编写单行然后缩小window并再次展开 Z78E6221F6393D135DZF681DB3 .

在此处输入图像描述

But when my text goes past the first terminal line (without pressing Enter), if I do the same steps as before, the output wrapping is different from what I want.但是当我的文本经过第一行(不按 Enter)时,如果我执行与以前相同的步骤,则 output 换行与我想要的不同。 What I need is that the last characters of the first line must join with the second line characters when shrinking the window, and vice versa when I expand the window the first characters of the second line join with the first line characters.我需要的是,在缩小 window 时,第一行的最后一个字符必须与第二行字符连接,反之亦然,当我展开 window 时,第二行的第一个字符与第一行字符连接。

在此处输入图像描述

Is there a way to make the outputted lines wrap exactly the same as bash?有没有办法让输出的行换行与 bash 完全相同? (joining lines with each other) (相互连接线)

Here is my code so far, use -ltermcap flag when you want to compile it and Thanks in advance.到目前为止,这是我的代码,当你想编译它时使用-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);
}

Your terminal remembers where there are actual line skips (the one that you do explicitly with cursor_down in move_cursor_down_vertically() ), as opposed to line wraps the terminal does on its own due to its limited width.您的终端会记住实际的换行位置(您在move_cursor_down_vertically()中使用 cursor_down 显式执行的换行),而不是终端由于其有限的宽度而自行执行的换行。

So:所以:

  • either you don't move (downwards) your cursor at all and do all your processing on only one virtual line of text, letting the terminal wrap that line according to its width (this is probably the easiest solution);要么您根本不移动(向下)您的 cursor 并且只在一个虚拟文本行上进行所有处理,让终端根据其宽度包裹该行(这可能是最简单的解决方案);
  • or you redraw the screen yourself in sigwinch_handler() when you receive the SIGWINCH signal.或者当您收到 SIGWINCH 信号时,您自己在sigwinch_handler()中重绘屏幕。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM