[newlib-cygwin/cygwin-3_6-branch] Cygwin: pty: Add new workaround for rlwrap in pcon enabled mode

Takashi Yano tyan0@sourceware.org
Fri Dec 19 18:28:33 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=a82ec69386269bdefb0b2c041beafc7cee5539a3

commit a82ec69386269bdefb0b2c041beafc7cee5539a3
Author: Takashi Yano <takashi.yano@nifty.ne.jp>
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 <corinna@vinschen.de>, Johannes Schindelin <Johannes.Schindelin@gmx.de>
    Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
    (cherry picked from commit 835358af6465dd1be1263525d6b970621a28f676)

Diff:
---
 winsup/cygwin/fhandler/pty.cc         | 44 +++++++++++++++++++++++++++++++++++
 winsup/cygwin/local_includes/wincap.h |  2 ++
 winsup/cygwin/wincap.cc               | 10 ++++++++
 3 files changed, 56 insertions(+)

diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index 03fd47858..90f58671c 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -2766,6 +2766,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 250866f06..55a678da1 100644
--- a/winsup/cygwin/local_includes/wincap.h
+++ b/winsup/cygwin/local_includes/wincap.h
@@ -33,6 +33,7 @@ struct wincaps
     unsigned has_tcp_maxrtms					: 1;
     unsigned has_con_broken_tabs				: 1;
     unsigned has_user_shstk					: 1;
+    unsigned has_pcon_omit_nl_before_cursor_move		: 1;
   };
 };
 
@@ -90,6 +91,7 @@ public:
   bool	IMPLEMENT (has_tcp_maxrtms)
   bool	IMPLEMENT (has_con_broken_tabs)
   bool	IMPLEMENT (has_user_shstk)
+  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 deecf8ba5..a9a7aea78 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -32,6 +32,7 @@ static const wincaps wincap_8_1 = {
     has_tcp_maxrtms:false,
     has_con_broken_tabs:false,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -54,6 +55,7 @@ static const wincaps  wincap_10_1507 = {
     has_tcp_maxrtms:false,
     has_con_broken_tabs:false,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -76,6 +78,7 @@ static const wincaps  wincap_10_1607 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:false,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -98,6 +101,7 @@ static const wincaps wincap_10_1703 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:true,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -120,6 +124,7 @@ static const wincaps wincap_10_1709 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:true,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -142,6 +147,7 @@ static const wincaps wincap_10_1803 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:true,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -164,6 +170,7 @@ static const wincaps wincap_10_1809 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:true,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -186,6 +193,7 @@ static const wincaps wincap_10_1903 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:true,
     has_user_shstk:false,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -208,6 +216,7 @@ static const wincaps wincap_10_2004 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:true,
     has_user_shstk:true,
+    has_pcon_omit_nl_before_cursor_move:false,
   },
 };
 
@@ -230,6 +239,7 @@ static const wincaps wincap_11 = {
     has_tcp_maxrtms:true,
     has_con_broken_tabs:false,
     has_user_shstk:true,
+    has_pcon_omit_nl_before_cursor_move:true,
   },
 };


More information about the Cygwin-cvs mailing list