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,
   },
 };

Reply via email to