https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=835358af6465dd1be1263525d6b970621a28f676
commit 835358af6465dd1be1263525d6b970621a28f676 Author: Takashi Yano <[email protected]> Date: Wed Dec 10 10:28:19 2025 +0900 Cygwin: pty: Add new workaround for rlwrap in pcon enabled mode In Windows 11, the command "rlwrap cmd" outputs garbaged screen. This is because rlwrap treats text between NLs as a line, while pseudo console sometimes omits NL before "CSIm;nH". This issue does not happen in Windows 10. This patch fixes the issue by adding CR NL before "CSIm:nH" into the output from the pseudo console if the OS is Windows 11. Reviewed-by: Corinna Vinschen <[email protected]>, Johannes Schindelin <[email protected]> Signed-off-by: Takashi Yano <[email protected]> Diff: --- winsup/cygwin/fhandler/pty.cc | 44 +++++++++++++++++++++++++++++++++++ winsup/cygwin/local_includes/wincap.h | 2 ++ winsup/cygwin/wincap.cc | 11 +++++++++ 3 files changed, 57 insertions(+) diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index 2cad80a5a..32e50540e 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -2787,6 +2787,50 @@ fhandler_pty_master::pty_master_fwd_thread (const master_fwd_thread_param_t *p) else state = 0; + /* Workaround for rlwrap in Win11. rlwrap treats text between + NLs as a line, however, pseudo console in Win11 somtimes + omits NL before "CSIm;nH". This does not happen in Win10. */ + if (wincap.has_pcon_omit_nl_before_cursor_move ()) + { + state = 0; + for (DWORD i = 0; i < rlen; i++) + if (state == 0 && outbuf[i] == '\033') + { + start_at = i; + state++; + continue; + } + else if (state == 1 && outbuf[i] == '[') + { + state++; + continue; + } + else if (state == 2 + && (isdigit (outbuf[i]) || outbuf[i] == ';')) + continue; + else if (state == 2 && outbuf[i] == 'H') + { + /* Add omitted CR NL before "CSIm;nH". However, when the + cusor is on the bottom-most line, adding NL might cause + unexpected scrolling. To avoid this, add "CSI H" before + CR NL. */ + const char *ins = "\033[H\r\n"; + const int ins_len = strlen (ins); + if (rlen + ins_len <= NT_MAX_PATH) + { + memmove (&outbuf[start_at + ins_len], + &outbuf[start_at], rlen - start_at); + memcpy (&outbuf[start_at], ins, ins_len); + rlen += ins_len; + i += ins_len; + } + state = 0; + continue; + } + else + state = 0; + } + if (p->ttyp->term_code_page != CP_UTF8) { size_t nlen = NT_MAX_PATH; diff --git a/winsup/cygwin/local_includes/wincap.h b/winsup/cygwin/local_includes/wincap.h index 2416eee1d..0496d807e 100644 --- a/winsup/cygwin/local_includes/wincap.h +++ b/winsup/cygwin/local_includes/wincap.h @@ -34,6 +34,7 @@ struct wincaps unsigned has_con_broken_tabs : 1; unsigned has_user_shstk : 1; unsigned has_alloc_console_with_options : 1; + unsigned has_pcon_omit_nl_before_cursor_move : 1; }; }; @@ -92,6 +93,7 @@ public: bool IMPLEMENT (has_con_broken_tabs) bool IMPLEMENT (has_user_shstk) bool IMPLEMENT (has_alloc_console_with_options) + bool IMPLEMENT (has_pcon_omit_nl_before_cursor_move) void disable_case_sensitive_dirs () { diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 91caefe9b..f94b9f60b 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -33,6 +33,7 @@ static const wincaps wincap_8_1 = { has_con_broken_tabs:false, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -56,6 +57,7 @@ static const wincaps wincap_10_1507 = { has_con_broken_tabs:false, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -79,6 +81,7 @@ static const wincaps wincap_10_1607 = { has_con_broken_tabs:false, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -102,6 +105,7 @@ static const wincaps wincap_10_1703 = { has_con_broken_tabs:true, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -125,6 +129,7 @@ static const wincaps wincap_10_1709 = { has_con_broken_tabs:true, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -148,6 +153,7 @@ static const wincaps wincap_10_1803 = { has_con_broken_tabs:true, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -171,6 +177,7 @@ static const wincaps wincap_10_1809 = { has_con_broken_tabs:true, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -194,6 +201,7 @@ static const wincaps wincap_10_1903 = { has_con_broken_tabs:true, has_user_shstk:false, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -217,6 +225,7 @@ static const wincaps wincap_10_2004 = { has_con_broken_tabs:true, has_user_shstk:true, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:false, }, }; @@ -240,6 +249,7 @@ static const wincaps wincap_11 = { has_con_broken_tabs:false, has_user_shstk:true, has_alloc_console_with_options:false, + has_pcon_omit_nl_before_cursor_move:true, }, }; @@ -263,6 +273,7 @@ static const wincaps wincap_11_24h2 = { has_con_broken_tabs:false, has_user_shstk:true, has_alloc_console_with_options:true, + has_pcon_omit_nl_before_cursor_move:true, }, };
