Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,20 @@ else()
file(MAKE_DIRECTORY ${LIBVTERM_INCLUDE_DIR})
endif()

# Build conpty-proxy
if(WIN32)
ExternalProject_add(conpty-proxy
GIT_REPOSITORY https://github.com/xhcoding/conpty-proxy.git
GIT_TAG v1.0.1
INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}
INSTALL_COMMAND
COMMAND ${CMAKE_COMMAND} -E copy
<BINARY_DIR>/conpty_proxy.exe
<INSTALL_DIR>/conpty_proxy.exe
)

endif()

add_library(vterm STATIC IMPORTED)
set_target_properties(vterm PROPERTIES IMPORTED_LOCATION ${LIBVTERM_LIBRARY})
target_include_directories(vterm INTERFACE ${LIBVTERM_INCLUDE_DIR})
Expand Down
72 changes: 72 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,57 @@ function vterm_printf;
end
```


## vterm and Windows

VTerm on Windows relies on ConPTY (Windows Console Pseudo-Terminal), which requires:

- Windows 10 Insider Preview build 17733 or later, OR

- Windows 10 version 1903 (May 2019 Update) or later

### Compile vterm

Building VTerm requires the MSYS2 environment with appropriate toolchains.

#### Installing MSYS2

Download and install from https://www.msys2.org/ or use a package manager:

Using the official installer:

- Download the executable from the MSYS2 website

- Follow the installation wizard

Using Scoop (alternative method):

```sh
scoop install msys2
```

#### Installing Required Tools and Libraries

Open the UCRT64 shell in MSYS2 and install the necessary packages:

```sh
pacman -S --noconfirm \
mingw-w64-ucrt-x86_64-toolchain \
mingw-w64-ucrt-x86_64-cmake \
mingw-w64-ucrt-x86_64-libvterm
```

Alternative shells: You can also use MINGW64 shell, but UCRT64 is recommended for better compatibility with modern Windows versions.

#### Build vterm

Open the UCRT64 shell in MSYS2:

```sh
cmake -S . -Bbuild
cmake --build build
```

# Debugging and testing

If you have successfully built the module, you can test it by executing the
Expand Down Expand Up @@ -510,6 +561,27 @@ Examples:
Use tramp's default shell for all other methods.
`'(("ssh" login-shell "/bin/bash") ("scp" login-shell "/bin/bash"))`

## `vterm-decode-coding-system`

Controls the character encoding for decoding vterm output.

Default Value: `locale-coding-system`

**Important Note for Windows Users**:
If your Windows system's default encoding is not UTF-8, you must set this variable to utf-8 to ensure proper display of international characters and symbols in vterm.

## `vterm-conpty-proxy-path`

Specifies the file path to conpty_proxy.exe on Windows systems.

When set to nil, vterm automatically searches for the executable in:

1. System PATH environment variable

2 Vterm package installation directory

When set to a custom path, use the full absolute path to the executable

## Keybindings

If you want a key to be sent to the terminal, bind it to `vterm--self-insert`,
Expand Down
14 changes: 13 additions & 1 deletion vterm-module.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
#include <limits.h>
#include <stdio.h>
#include <string.h>

#ifndef _WIN32
#include <termios.h>
#endif

#include <unistd.h>
#include <vterm.h>

Expand Down Expand Up @@ -901,9 +905,13 @@ static void term_process_key(Term *term, emacs_env *env, unsigned char *key,
if (is_key(key, len, "<clear_scrollback>")) {
term_clear_scrollback(term, env);
} else if (is_key(key, len, "<start>")) {
#ifndef _WIN32
tcflow(term->pty_fd, TCOON);
#endif
} else if (is_key(key, len, "<stop>")) {
#ifndef _WIN32
tcflow(term->pty_fd, TCOOFF);
#endif
} else if (is_key(key, len, "<start_paste>")) {
vterm_keyboard_start_paste(term->vt);
} else if (is_key(key, len, "<end_paste>")) {
Expand Down Expand Up @@ -1382,7 +1390,8 @@ emacs_value Fvterm_set_size(emacs_env *env, ptrdiff_t nargs, emacs_value args[],

emacs_value Fvterm_set_pty_name(emacs_env *env, ptrdiff_t nargs,
emacs_value args[], void *data) {
Term *term = env->get_user_ptr(env, args[0]);
#ifndef _WIN32
Term *term = env->get_user_ptr(env, args[0]);

if (nargs > 1) {
ptrdiff_t len = string_bytes(env, args[1]);
Expand All @@ -1392,6 +1401,7 @@ emacs_value Fvterm_set_pty_name(emacs_env *env, ptrdiff_t nargs,

term->pty_fd = open(filename, O_RDONLY);
}
#endif
return Qnil;
}
emacs_value Fvterm_get_pwd(emacs_env *env, ptrdiff_t nargs, emacs_value args[],
Expand All @@ -1406,6 +1416,7 @@ emacs_value Fvterm_get_pwd(emacs_env *env, ptrdiff_t nargs, emacs_value args[],

emacs_value Fvterm_get_icrnl(emacs_env *env, ptrdiff_t nargs,
emacs_value args[], void *data) {
#ifndef _WIN32
Term *term = env->get_user_ptr(env, args[0]);

if (term->pty_fd > 0) {
Expand All @@ -1417,6 +1428,7 @@ emacs_value Fvterm_get_icrnl(emacs_env *env, ptrdiff_t nargs,
else
return Qnil;
}
#endif
return Qnil;
}

Expand Down
118 changes: 90 additions & 28 deletions vterm.el
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,25 @@ copy-mode and set to nil on leaving."
:type 'boolean
:group 'vterm)

(defcustom vterm-decode-coding-system (if (eq system-type 'windows-nt)
'utf-8
locale-coding-system)
"The coding system used for decoding."
:type 'symbol
:group 'vterm)

(defcustom vterm-conpty-proxy-path nil
"Path to conpty_proxy.exe.

If set to nil, search for the executable in the following order:
1. In the system PATH environment variable
2. In the vterm package installation directory

Set this to the full path if you have conpty_proxy.exe in a custom location."
:type '(choice (const :tag "Auto-detect" nil)
(file :tag "Custom path"))
:group 'vterm)

;;; Faces

(defface vterm-color-black
Expand Down Expand Up @@ -790,33 +809,35 @@ Exceptions are defined by `vterm-keymap-exceptions'."
(local 'filter-buffer-substring-function)
#'vterm--filter-buffer-substring)
(setq vterm--process
(make-process
:name "vterm"
:buffer (current-buffer)
:command
`("/bin/sh" "-c"
,(format
"stty -nl sane %s erase ^? rows %d columns %d >/dev/null && exec %s"
;; Some stty implementations (i.e. that of *BSD) do not
;; support the iutf8 option. to handle that, we run some
;; heuristics to work out if the system supports that
;; option and set the arg string accordingly. This is a
;; gross hack but FreeBSD doesn't seem to want to fix it.
;;
;; See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=220009
(if (eq system-type 'berkeley-unix) "" "iutf8")
(window-body-height)
width (vterm--get-shell)))
;; :coding 'no-conversion
:connection-type 'pty
:file-handler t
:filter #'vterm--filter
;; The sentinel is needed if there are exit functions or if
;; vterm-kill-buffer-on-exit is set to t. In this latter case,
;; vterm--sentinel will kill the buffer
:sentinel (when (or vterm-exit-functions
vterm-kill-buffer-on-exit)
#'vterm--sentinel))))
(if (eq system-type 'windows-nt)
(vterm--conpty-proxy-make-process width (window-body-height))
(make-process
:name "vterm"
:buffer (current-buffer)
:command
`("/bin/sh" "-c"
,(format
"stty -nl sane %s erase ^? rows %d columns %d >/dev/null && exec %s"
;; Some stty implementations (i.e. that of *BSD) do not
;; support the iutf8 option. to handle that, we run some
;; heuristics to work out if the system supports that
;; option and set the arg string accordingly. This is a
;; gross hack but FreeBSD doesn't seem to want to fix it.
;;
;; See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=220009
(if (eq system-type 'berkeley-unix) "" "iutf8")
(window-body-height)
width (vterm--get-shell)))
;; :coding 'no-conversion
:connection-type 'pty
:file-handler t
:filter #'vterm--filter
;; The sentinel is needed if there are exit functions or if
;; vterm-kill-buffer-on-exit is set to t. In this latter case,
;; vterm--sentinel will kill the buffer
:sentinel (when (or vterm-exit-functions
vterm-kill-buffer-on-exit)
#'vterm--sentinel)))))

;; Change major-mode is not allowed
;; Vterm interfaces with an underlying process. Changing the major
Expand Down Expand Up @@ -1452,6 +1473,45 @@ Search Manipulate Selection Data in
(message "kill-ring is updated by vterm OSC 52(Manipulate Selection Data)"))
))

;;; conpty-proxy
(defun vterm--conpty-proxy-path ()
"Path of conpty_proxy.exe.
If `vterm-conpty-proxy-path' is set, use that value.
Otherwise, search in PATH for 'conpty_proxy.exe'.
If not found in PATH, look in the vterm.el directory."
(or vterm-conpty-proxy-path
(executable-find "conpty_proxy.exe")
(expand-file-name "conpty_proxy.exe"
(file-name-directory (locate-library "vterm.el" t)))))

(defun vterm--conpty-proxy-make-process (width height)
"Make conpty proxy process."
(let* ((conpty-id (format "econpty_%s_%s" (format-time-string "%s") (emacs-pid)))
conpty-process)
(setq conpty-process
(make-process
:name "vterm"
:buffer (current-buffer)
:command `(,(vterm--conpty-proxy-path) "new"
,conpty-id ,(int-to-string width) ,(int-to-string height) ,(vterm--get-shell))
:coding 'no-conversion
:file-handler t
:filter #'vterm--filter
;; The sentinel is needed if there are exit functions or if
;; vterm-kill-buffer-on-exit is set to t. In this latter case,
;; vterm--sentinel will kill the buffer
:sentinel (when (or vterm-exit-functions
vterm-kill-buffer-on-exit)
#'vterm--sentinel)))

(process-put conpty-process 'conpty-id conpty-id)
conpty-process))

(defun vterm--conpty-proxy-resize(width height)
"Call conpty proxy resize command."
(let ((conpty-id (process-get vterm--process 'conpty-id)))
(shell-command-to-string (format "%s resize %s %s %s" (vterm--conpty-proxy-path) conpty-id width height))))

;;; Entry Points

;;;###autoload
Expand Down Expand Up @@ -1583,7 +1643,7 @@ Then triggers a redraw from the module."
(setq decoded-substring
(decode-coding-string
(substring input i funny)
locale-coding-system t))
vterm-decode-coding-system t))
;; Check for multibyte characters that ends
;; before end of string, and save it for
;; next time.
Expand Down Expand Up @@ -1656,6 +1716,8 @@ Argument EVENT process event."
(> width 0)
(> height 0))
(vterm--set-size vterm--term height width)
(when (eq system-type 'windows-nt)
(vterm--conpty-proxy-resize width height))
(cons width height)))))

(defun vterm--get-margin-width ()
Expand Down