* bug#71472: [PATCH] Add pty support by using ConPTY on Windows
@ 2024-06-10 10:26 Ke Wu
2024-06-10 15:40 ` Eli Zaretskii
0 siblings, 1 reply; 5+ messages in thread
From: Ke Wu @ 2024-06-10 10:26 UTC (permalink / raw)
To: 71472
[-- Attachment #1: Type: text/plain, Size: 619 bytes --]
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'
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-pty-support-by-using-ConPTY-on-Windows.patch --]
[-- Type: text/patch, Size: 12105 bytes --]
From 99bdacc3d6b9e6ea1ddcb0ae31b44afffe0ff697 Mon Sep 17 00:00:00 2001
From: Ke Wu <ellpih@zohomail.jp>
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))))
\f
;;; 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
^ permalink raw reply related [flat|nested] 5+ messages in thread
* bug#71472: [PATCH] Add pty support by using ConPTY on Windows
2024-06-10 10:26 bug#71472: [PATCH] Add pty support by using ConPTY on Windows Ke Wu
@ 2024-06-10 15:40 ` Eli Zaretskii
[not found] ` <190055cd3c0.5289e49215028.2058921479589116968@zohomail.jp>
0 siblings, 1 reply; 5+ messages in thread
From: Eli Zaretskii @ 2024-06-10 15:40 UTC (permalink / raw)
To: Ke Wu; +Cc: 71472
> From: Ke Wu <ellpih@zohomail.jp>
> Date: Mon, 10 Jun 2024 18:26:46 +0800
>
> 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.
Thanks. It's a pity you didn't discuss this before working on the
code, because ConPTY is not very useful on MS-Windows due to the
limitations of its encoding. See this issue I opened 3 years ago, and
which they meanwhile closed (I guess they don't plan on fixing this
anytime soon). See
https://github.com/microsoft/terminal/issues/9174
If we must use UTF-8 as the only encoding to talk to sub-processes via
ConPTY, that makes the number of applications that can be used this
way very small, since most programs we are used to run as
subprocesses, in particularly ports of GNU software like GCC, GDB,
Grep, Find, and many others, cannot reliably talk to Emacs in UTF-8
encoding on MS-Windows. And without that, what would we use this
feature for?
So unfortunately, I don't think we should install these patches.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-06-11 8:42 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-10 10:26 bug#71472: [PATCH] Add pty support by using ConPTY on Windows Ke Wu
2024-06-10 15:40 ` Eli Zaretskii
[not found] ` <190055cd3c0.5289e49215028.2058921479589116968@zohomail.jp>
2024-06-11 7:27 ` Eli Zaretskii
2024-06-11 8:24 ` Ke Wu
2024-06-11 8:42 ` Eli Zaretskii
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).