From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Ke Wu Newsgroups: gmane.emacs.bugs Subject: bug#71472: [PATCH] Add pty support by using ConPTY on Windows Date: Mon, 10 Jun 2024 18:26:46 +0800 Message-ID: <874ja1m6u1.fsf@zohomail.jp> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="14502"; mail-complaints-to="usenet@ciao.gmane.io" To: 71472@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Mon Jun 10 16:41:17 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sGgCz-0003Zp-7j for geb-bug-gnu-emacs@m.gmane-mx.org; Mon, 10 Jun 2024 16:41:17 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sGgCW-0002cm-B6; Mon, 10 Jun 2024 10:40:48 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sGgCU-0002cN-7U for bug-gnu-emacs@gnu.org; Mon, 10 Jun 2024 10:40:46 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sGgCT-0000ve-Ff for bug-gnu-emacs@gnu.org; Mon, 10 Jun 2024 10:40:45 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1sGgCk-00022I-C6 for bug-gnu-emacs@gnu.org; Mon, 10 Jun 2024 10:41:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Ke Wu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 10 Jun 2024 14:41:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 71472 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.17180304177725 (code B ref -1); Mon, 10 Jun 2024 14:41:02 +0000 Original-Received: (at submit) by debbugs.gnu.org; 10 Jun 2024 14:40:17 +0000 Original-Received: from localhost ([127.0.0.1]:38647 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sGgC0-00020U-1j for submit@debbugs.gnu.org; Mon, 10 Jun 2024 10:40:17 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:41086) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sGeCX-00045G-7O for submit@debbugs.gnu.org; Mon, 10 Jun 2024 08:32:42 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sGcEx-0006aT-KU for bug-gnu-emacs@gnu.org; Mon, 10 Jun 2024 06:27:03 -0400 Original-Received: from sender-pp-o93.zoho.jp ([103.163.153.27]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sGcEv-0006ZN-3p for bug-gnu-emacs@gnu.org; Mon, 10 Jun 2024 06:27:03 -0400 Original-Received: by mx.zoho.jp with SMTPS id 17180152099851001.886543643876; Mon, 10 Jun 2024 19:26:49 +0900 (JST) X-Zoho-Virus-Status: 1 X-Zoho-AV-Stamp: zmail-av-1.3.1/217.927.51 X-ZohoMailClient: External Received-SPF: pass client-ip=103.163.153.27; envelope-from=ellpih@zohomail.jp; helo=sender-pp-o93.zoho.jp X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Mon, 10 Jun 2024 09:30:33 -0400 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:287033 Archived-At: --=-=-= Content-Type: text/plain Tags: patch Tags: patch This patch adds pty support by using ConPTY on Windows. The conhost.exe runs in pty mode and provides pty interface. The package term is also patched to make it usable on Windows. In GNU Emacs 30.0.50 (build 4, x86_64-w64-mingw32) of 2024-06-10 built on WIN1729 Repository revision: ed122417b98d711bacf5ed24778886bf21d86956 Repository branch: master Windowing system distributor 'Microsoft Corp.', version 10.0.22631 System Description: Microsoft Windows 10 Pro (v10.0.2009.22631.3672) Configured using: 'configure --prefix=/c/Users/oracl/Documents/Programs/emacs-dist --without-dbus' --=-=-= Content-Type: text/patch Content-Disposition: attachment; filename=0001-Add-pty-support-by-using-ConPTY-on-Windows.patch >From 99bdacc3d6b9e6ea1ddcb0ae31b44afffe0ff697 Mon Sep 17 00:00:00 2001 From: Ke Wu Date: Mon, 10 Jun 2024 18:09:45 +0800 Subject: [PATCH] Add pty support by using ConPTY on Windows * src/w32proc.c (w32-make-console-process): Add a function to create process with pty interface using conhost.exe in pty mode. * src/w32.c (make_console_with_pipe): Make a process using conhost.exe. Attach a pipe to conhost.exe for resize. This function is used by 'w32-make-console-process'. * src/w32.h (make_console_with_pipe): Make above function definition an extern function. * src/sysdep.c (set_window_size): Implement window resize for conhost.exe. * src/process.c (set-process-window-size): Implement window resize. * src/process.c (deactivate_process): Close pipe fd when process exits. The pipe is attached to conhost.exe in 'make_console_with_pipe'. * lisp/term.el (term-exec-1): Use 'w32-make-console-process' to create a process with pty interface. * lisp/term.el (term-coding-system): Set coding system to UTF-8 for newly created buffer with terminal process attached since conhost.exe assumes UTF-8 encoding in ConPTY mode. --- lisp/term.el | 39 +++++++++++++++-------- src/process.c | 28 +++++++++++++++++ src/sysdep.c | 12 +++++++ src/w32.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/w32.h | 2 ++ src/w32proc.c | 35 +++++++++++++++++++++ 6 files changed, 190 insertions(+), 13 deletions(-) diff --git a/lisp/term.el b/lisp/term.el index c15f6cf2e9f..24509037805 100644 --- a/lisp/term.el +++ b/lisp/term.el @@ -1746,18 +1746,24 @@ term-exec-1 (when (term--bash-needs-EMACSp) (push (format "EMACS=%s (term:%s)" emacs-version term-protocol-version) process-environment)) - (apply #'start-process name buffer - ;; On Android, /bin doesn't exist, and the default shell is - ;; found as /system/bin/sh. - (if (eq system-type 'android) - "/system/bin/sh" - "/bin/sh") - "-c" - (format "stty -nl echo rows %d columns %d sane 2>%s;\ + (if (eq system-type 'windows-nt) + ;; Use `w32-make-console-process' to make use of the Windows ConPTY. + (apply #'w32-make-console-process + (append (list :name name :buffer buffer) + (list :command (cons command switches)) + (list :width term-width :height term-height))) + (apply #'start-process name buffer + ;; On Android, /bin doesn't exist, and the default shell is + ;; found as /system/bin/sh. + (if (eq system-type 'android) + "/system/bin/sh" + "/bin/sh") + "-c" + (format "stty -nl echo rows %d columns %d sane 2>%s;\ if [ $1 = .. ]; then shift; fi; exec \"$@\"" - term-height term-width null-device) - ".." - command switches))) + term-height term-width null-device) + ".." + command switches)))) ;;; Input history processing in a buffer @@ -3007,6 +3013,13 @@ term-control-seq-regexp (defconst term-control-seq-prefix-regexp "[\032\e]") +(defconst term-coding-system + (if (eq system-type 'windows-nt) + ;; The conhost.exe assumes UTF-8 for ConPTY. + 'utf-8-dos + locale-coding-system) + "Coding system for terminal in term.el.") + (defun term-emulate-terminal (proc str) (when (buffer-live-p (process-buffer proc)) (with-current-buffer (process-buffer proc) @@ -3074,7 +3087,7 @@ term-emulate-terminal (setq decoded-substring (decode-coding-string (substring str i funny) - locale-coding-system t)) + term-coding-system t)) ;; Check for multibyte characters that ends ;; before end of string, and save it for ;; next time. @@ -3173,7 +3186,7 @@ term-emulate-terminal (- ctl-end (if (eq (aref str (- ctl-end 2)) ?\r) 2 1))) - locale-coding-system t))) + term-coding-system t))) (?\e (pcase (aref str (1+ i)) (?\[ diff --git a/src/process.c b/src/process.c index 9670be64279..b3e56bc8d9c 100644 --- a/src/process.c +++ b/src/process.c @@ -1497,12 +1497,32 @@ DEFUN ("set-process-window-size", Fset_process_window_size, unsigned short h = check_uinteger_max (height, USHRT_MAX); unsigned short w = check_uinteger_max (width, USHRT_MAX); +#ifdef WINDOWSNT + + Lisp_Object sigfd_obj; + int sigfd; + if (NETCONN_P (process)) + return Qnil; + + sigfd_obj = plist_get (XPROCESS (process) -> plist, QCfile_handler); + if (!FIXNUMP (sigfd_obj)) + return Qnil; + sigfd = XFIXNUM (sigfd_obj); + if(sigfd < 0 || set_window_size (sigfd, h, w) < 0) + return Qnil; + else + return Qt; + +#else + if (NETCONN_P (process) || XPROCESS (process)->infd < 0 || set_window_size (XPROCESS (process)->infd, h, w) < 0) return Qnil; else return Qt; + +#endif } DEFUN ("set-process-inherit-coding-system-flag", @@ -4783,6 +4803,14 @@ deactivate_process (Lisp_Object proc) /* Delete GnuTLS structures in PROC, if any. */ emacs_gnutls_deinit (proc); #endif /* HAVE_GNUTLS */ +#ifdef WINDOWSNT + /* Close write side of the pipe in console process of Windows */ + Lisp_Object infd = plist_get(p -> plist, QCfile_handler); + if (!NILP (infd) && FIXNUMP(infd)) { + i = XFIXNUM(infd); + emacs_close(i); + } +#endif /* WINDOWSNT */ if (p->read_output_delay > 0) { diff --git a/src/sysdep.c b/src/sysdep.c index 07237885cb9..144ea4b413b 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1481,8 +1481,20 @@ set_window_size (int fd, int height, int width) size.ts_cols = width; return ioctl (fd, TIOCGSIZE, &size); + +#else +#ifdef WINDOWSNT + + /* Windows console process */ + unsigned short signal_packet[3]; + signal_packet[0] = 8u; + signal_packet[1] = width; + signal_packet[2] = height; + return write(fd, signal_packet, sizeof(signal_packet)); + #else return -1; +#endif /* not Windows NT */ #endif /* not SunOS-style */ #endif /* not BSD-style */ } diff --git a/src/w32.c b/src/w32.c index 6d0b178e978..b5708458a8c 100644 --- a/src/w32.c +++ b/src/w32.c @@ -11166,6 +11166,93 @@ register_aux_fd (int infd) fd_info[ infd ].flags |= FILE_DONT_CLOSE; } +/* Start a console process by wraping the command in conhost.exe. The process is + started by calling make-process. The variable fds stores the infd and outfd of + the pipe serving as the signal pipe of conhost.exe. */ +Lisp_Object +make_console_with_pipe (ptrdiff_t nargs, Lisp_Object * args, const int * fds) +{ + + Lisp_Object command, contact; + Lisp_Object command_new, contact_new; + Lisp_Object width, height; + Lisp_Object process; + unsigned long pipe_outhnd; + + HANDLE parent, newoutfd; + + parent = GetCurrentProcess (); + + /* Make inheritable copies of the fds[0]. */ + if (!DuplicateHandle (parent, + (HANDLE) _get_osfhandle (fds[0]), + parent, + &newoutfd, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) + report_file_error ("Duplicating input handle for child", Qnil); + + emacs_close( fds[0] ); + pipe_outhnd = (unsigned long) newoutfd; + + /* Compose new command based on given parameters. */ + contact = Flist (nargs, args); + command = plist_get (contact, QCcommand); + if (NILP (command)) + return Qnil; + if (!CONSP (command)) + command = list1 (command); + width = plist_get (contact, QCwidth); + height = plist_get (contact, QCheight); + + command_new = CALLN (Flist, + build_string ("conhost.exe"), + build_string ("--headless"), + build_string ("--feature"), + build_string ("pty")); + if (!NILP (width)) + command_new = CALLN (Fappend, + command_new, + CALLN (Flist, + build_string ("--width"), + CALLN (Fformat, build_string ("%d"), width))); + + if (!NILP (height)) + command_new = CALLN (Fappend, + command_new, + CALLN (Flist, + build_string ("--height"), + CALLN (Fformat, build_string ("%d"), height))); + + command_new = CALLN (Fappend, + command_new, + CALLN (Flist, build_string ("--signal"), + CALLN (Fformat, + build_string ("0x%x"), + make_uint (pipe_outhnd)))); + + command_new = CALLN (Fappend, + command_new, + command); + + contact_new = plist_put (contact, QCcommand, command_new); + process = CALLN (Fapply, Qmake_process, contact_new); + + CloseHandle (newoutfd); + if (NILP (process)) + emacs_close( fds[1] ); + else { + fd_info[ fds[1] ].cp = fd_info[XPROCESS (process) -> infd].cp; + /* Store the signal pipe's out fd in process plist. Not sure if + QCfile_handler is a proper key. */ + XPROCESS (process) -> plist = + plist_put (XPROCESS (process) -> plist, + QCfile_handler, make_uint(fds[1])); + } + return process; +} + #ifdef HAVE_GNUTLS ssize_t diff --git a/src/w32.h b/src/w32.h index cf470ae9901..7393c5299f7 100644 --- a/src/w32.h +++ b/src/w32.h @@ -230,6 +230,8 @@ #define FILE_DONT_CLOSE 0x1000 extern int lchmod (char const *, mode_t); extern bool symlinks_supported (const char *); +/* Create console process with signal pipe */ +extern Lisp_Object make_console_with_pipe (ptrdiff_t, Lisp_Object *, const int *); /* Return total and free memory info. */ extern int w32_memory_info (unsigned long long *, unsigned long long *, diff --git a/src/w32proc.c b/src/w32proc.c index 55ead13647b..efb32c3ed7e 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -3726,6 +3726,39 @@ DEFUN ("w32-set-keyboard-layout", Fw32_set_keyboard_layout, return Fw32_get_keyboard_layout (); } +DEFUN ("w32-make-console-process", Fw32_make_console_process, + Sw32_make_console_process, 0, MANY, 0, + doc: /* Start a process wrapped in conhost.exe. + +This is similar to `make-process', which following extra arguments: + +:width WIDTH -- WIDTH is the initial width of the conhost.exe process. + +:width HEIGHT -- HEIGHT is the initial height of the conhost.exe process. + +The conhost.exe runs in pty mode, which acts like a pty devices in *NIX. With +following differences: + +1. The text going in and out from the stdin and the stdout of conhost.exe are +always encoded in UTF-8. + +2. The conhost.exe requires an extra pipe to send signals which causes the +console resize. This is implemented in this function. */) + (ptrdiff_t nargs, Lisp_Object *args) +{ + + Lisp_Object process; + int fds[2]; + + /* Create signal pipe for this process */ + if (emacs_pipe (fds) < 0) + report_file_error ("Creating signal pipe for console process", Qnil); + fd_info[ fds[1] ].hnd = (HANDLE) _get_osfhandle (fds[1]); + + process = make_console_with_pipe(nargs, args, fds); + return process; +} + /* Two variables to interface between get_lcid and the EnumLocales callback function below. */ #ifndef LOCALE_NAME_MAX_LENGTH @@ -3949,6 +3982,8 @@ syms_of_ntproc (void) defsubr (&Sw32_get_keyboard_layout); defsubr (&Sw32_set_keyboard_layout); + defsubr (&Sw32_make_console_process); + DEFVAR_LISP ("w32-quote-process-args", Vw32_quote_process_args, doc: /* Non-nil enables quoting of process arguments to ensure correct parsing. Because Windows does not directly pass argv arrays to child processes, -- 2.45.1 --=-=-=--