You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

非规范模式下终端输出换行异常,如何用Termcap实现类bash自适应换行

问题根因

你遇到的长文本调整窗口大小后换行异常问题核心有两个:

  • 没有缓存完整的用户输入字符串,窗口大小变化时无法基于新的宽度重新排版输出全部内容
  • 现有的SIGWINCH信号处理仅更新了内部变量值,没有触发终端内容的重绘;同时你手动实现的满行硬换行逻辑会被终端识别为固定换行,窗口放大时不会自动合并上下行内容
修复思路
  1. 新增输入缓冲区存储所有用户输入的可打印字符
  2. 取消手动硬换行逻辑,依赖终端原生的软换行能力:只要不主动输出换行符,终端会自动对连续的可打印字符做自适应换行,调整窗口大小时也会自动重排
  3. 完善SIGWINCH信号处理逻辑:窗口大小变化时清空当前输入行的所有内容,基于新的窗口宽度重新输出缓冲区的全部输入,再把光标定位到正确位置
修复后完整代码

编译时需添加-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>

#define INPUT_BUF_SIZE 4096

int     g_screen_width = 0;
int     g_cursor_colm = 0;
int     g_printed = 0;
char    g_input_buf[INPUT_BUF_SIZE] = {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 clear_input_display() {
    int lines = (g_printed + g_screen_width - 1) / g_screen_width;
    // 向上移动对应行数,清空到屏幕末尾
    for (int i = 0; i < lines; i++) {
        tputs(tgetstr("up", NULL), 1, ft_putchar);
    }
    tputs(tgoto(tgetstr("ch", NULL), 0, 0), 1, ft_putchar);
    tputs(tgetstr("cd", NULL), 1, ft_putchar);
}

// 重绘全部输入内容
void redraw_input() {
    clear_input_display();
    write(1, g_input_buf, g_printed);
    update_cursor_position();
}

void    sigwinch_handler(int signo)
{
    if (signo == SIGWINCH)
    {
        update_screen_width();
        redraw_input(); // 窗口大小变化时触发重绘
    }
}

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;

    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) && g_printed < INPUT_BUF_SIZE - 1)
        {
            g_input_buf[g_printed] = c; // 字符存入缓冲区
            ft_putchar(c);
            g_printed++;
            g_cursor_colm++;
            // 取消手动硬换行,依赖终端自动软换行能力
        }
        else if (c == 27) // ESC键退出
        {
            disable_raw_mode(original_termios_state);
            exit(0);
        }
    }
    
    disable_raw_mode(original_termios_state);
    return (0);
}

内容的提问来源于stack exchange,提问作者Holy semicolon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 18:06:01