aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--elisp.h1
-rw-r--r--vterm-module.c167
-rw-r--r--vterm-module.h11
-rw-r--r--vterm.el88
5 files changed, 74 insertions, 194 deletions
diff --git a/README.md b/README.md
index b45f4ba..3f0d055 100644
--- a/README.md
+++ b/README.md
@@ -74,5 +74,4 @@ color you like:
# Limitations
- No support for scrolling (But you can use tmux/screen to emulate scrolling)
-- Hijacks SIGUSR1
- Mouse support is non-existing
diff --git a/elisp.h b/elisp.h
index 33e2e4c..35533d9 100644
--- a/elisp.h
+++ b/elisp.h
@@ -29,6 +29,7 @@ emacs_value Fgoto_char;
emacs_value Fput_text_property;
emacs_value Fset;
emacs_value Fvterm_face_color_hex;
+emacs_value Fvterm_flush_output;
// Utils
void bind_function(emacs_env *env, const char *name, emacs_value Sfun);
diff --git a/vterm-module.c b/vterm-module.c
index 91ff34a..6da78b9 100644
--- a/vterm-module.c
+++ b/vterm-module.c
@@ -1,19 +1,7 @@
#include "vterm-module.h"
#include "elisp.h"
-#include <fcntl.h>
-#ifdef __APPLE__
-#include <util.h>
-#else
-#include <pty.h>
-#endif
#include "utf8.h"
-#include <pthread.h>
-#include <signal.h>
#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <vterm.h>
@@ -185,17 +173,14 @@ static void term_setup_colors(struct Term *term, emacs_env *env) {
vterm_state_set_palette_color(state, 15, &bg);
}
-static void term_flush_output(struct Term *term) {
- size_t bufflen = vterm_output_get_buffer_current(term->vt);
- if (bufflen) {
- char buffer[bufflen];
- bufflen = vterm_output_read(term->vt, buffer, bufflen);
-
- // TODO: Make work with NON-Blocking io. (buffer in term)
- fcntl(term->masterfd, F_SETFL,
- fcntl(term->masterfd, F_GETFL) & ~O_NONBLOCK);
- write(term->masterfd, buffer, bufflen);
- fcntl(term->masterfd, F_SETFL, fcntl(term->masterfd, F_GETFL) | O_NONBLOCK);
+static void term_flush_output(struct Term *term, emacs_env *env) {
+ size_t len = vterm_output_get_buffer_current(term->vt);
+ if (len) {
+ char buffer[len];
+ len = vterm_output_read(term->vt, buffer, len);
+
+ emacs_value output = env->make_string(env, buffer, len);
+ env->funcall(env, Fvterm_flush_output, 1, (emacs_value[]){output});
}
}
@@ -275,8 +260,6 @@ static void term_put_caret(struct Term *term, emacs_env *env, int row, int col,
static void term_finalize(void *object) {
struct Term *term = (struct Term *)object;
- pthread_cancel(term->thread);
- pthread_join(term->thread, NULL);
vterm_free(term->vt);
free(term);
}
@@ -285,60 +268,8 @@ static emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs,
emacs_value args[], void *data) {
struct Term *term = malloc(sizeof(struct Term));
- ptrdiff_t len = string_bytes(env, args[0]);
- char shell[len];
- env->copy_string_contents(env, args[0], shell, &len);
-
- int rows = env->extract_integer(env, args[1]);
- int cols = env->extract_integer(env, args[2]);
-
- struct winsize size = {rows, cols, 0, 0};
-
- // Taken almost verbatim from https://bazaar.launchpad.net/~leonerd/pangoterm
- struct termios termios = {
- .c_iflag = ICRNL | IXON,
- .c_oflag = OPOST | ONLCR,
- .c_cflag = CS8 | CREAD,
- .c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK,
- /* c_cc later */
- };
-
- termios.c_iflag |= IUTF8;
- termios.c_oflag |= NL0;
- termios.c_oflag |= CR0;
- termios.c_oflag |= BS0;
- termios.c_oflag |= VT0;
- termios.c_oflag |= FF0;
- termios.c_lflag |= ECHOCTL;
- termios.c_lflag |= ECHOKE;
-
- cfsetspeed(&termios, 38400);
-
- termios.c_cc[VINTR] = 0x1f & 'C';
- termios.c_cc[VQUIT] = 0x1f & '\\';
- termios.c_cc[VERASE] = 0x7f;
- termios.c_cc[VKILL] = 0x1f & 'U';
- termios.c_cc[VEOF] = 0x1f & 'D';
- termios.c_cc[VEOL] = _POSIX_VDISABLE;
- termios.c_cc[VEOL2] = _POSIX_VDISABLE;
- termios.c_cc[VSTART] = 0x1f & 'Q';
- termios.c_cc[VSTOP] = 0x1f & 'S';
- termios.c_cc[VSUSP] = 0x1f & 'Z';
- termios.c_cc[VREPRINT] = 0x1f & 'R';
- termios.c_cc[VWERASE] = 0x1f & 'W';
- termios.c_cc[VLNEXT] = 0x1f & 'V';
- termios.c_cc[VMIN] = 1;
- termios.c_cc[VTIME] = 0;
-
- term->pid = forkpty(&term->masterfd, NULL, &termios, &size);
- fcntl(term->masterfd, F_SETFL, fcntl(term->masterfd, F_GETFL) | O_NONBLOCK);
-
- if (term->pid == 0) {
- setenv("TERM", "xterm", 1);
- char *args[2] = {shell, NULL};
- execvp(shell, args);
- exit(1);
- }
+ int rows = env->extract_integer(env, args[0]);
+ int cols = env->extract_integer(env, args[1]);
term->vt = vterm_new(rows, cols);
vterm_set_utf8(term->vt, 1);
@@ -348,8 +279,6 @@ static emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs,
VTermScreen *screen = vterm_obtain_screen(term->vt);
vterm_screen_reset(screen, 1);
- pthread_create(&term->thread, NULL, &event_loop, term);
-
return env->make_user_ptr(env, term_finalize, term);
}
@@ -357,12 +286,6 @@ static emacs_value Fvterm_update(emacs_env *env, ptrdiff_t nargs,
emacs_value args[], void *data) {
struct Term *term = env->get_user_ptr(env, args[0]);
- // Check if exited
- int status;
- if (waitpid(term->pid, &status, WNOHANG) > 0) {
- return Qnil;
- }
-
// Process keys
if (nargs > 1) {
ptrdiff_t len = string_bytes(env, args[1]);
@@ -378,46 +301,27 @@ static emacs_value Fvterm_update(emacs_env *env, ptrdiff_t nargs,
// Ignore the final zero byte
term_process_key(term, key, len - 1, modifier);
-
- // Flush output
- term_flush_output(term);
}
- VTermScreenCallbacks cb = {
- .settermprop = set_term_prop_cb,
- };
- VTermScreen *screen = vterm_obtain_screen(term->vt);
- vterm_screen_set_callbacks(screen, &cb, env);
-
- // Read input from masterfd
- char bytes[4096];
- int len;
- struct timeval start, end;
-
- gettimeofday(&start, NULL);
- while ((len = read(term->masterfd, bytes, 4096)) > 0) {
- vterm_input_write(term->vt, bytes, len);
-
- // Break after 40 milliseconds
- gettimeofday(&end, NULL);
- if (end.tv_usec - start.tv_usec > 40000) {
- break;
- }
- }
- vterm_screen_set_callbacks(screen, NULL, NULL);
+ // Flush output
+ term_flush_output(term, env);
term_redraw(term, env);
return env->make_integer(env, 0);
}
-static emacs_value Fvterm_kill(emacs_env *env, ptrdiff_t nargs,
- emacs_value args[], void *data) {
+static emacs_value Fvterm_write_input(emacs_env *env, ptrdiff_t nargs,
+ emacs_value args[], void *data) {
struct Term *term = env->get_user_ptr(env, args[0]);
- kill(term->pid, SIGKILL);
- int status;
- waitpid(term->pid, &status, 0);
- return Qnil;
+ ptrdiff_t len = string_bytes(env, args[1]);
+ char bytes[len];
+
+ env->copy_string_contents(env, args[1], bytes, &len);
+
+ vterm_input_write(term->vt, bytes, len);
+
+ return env->make_integer(env, 0);
}
static emacs_value Fvterm_set_size(emacs_env *env, ptrdiff_t nargs,
@@ -430,30 +334,12 @@ static emacs_value Fvterm_set_size(emacs_env *env, ptrdiff_t nargs,
vterm_get_size(term->vt, &old_rows, &old_cols);
if (cols != old_cols || rows != old_rows) {
- struct winsize size = {rows, cols, 0, 0};
- ioctl(term->masterfd, TIOCSWINSZ, &size);
vterm_set_size(term->vt, rows, cols);
}
return Qnil;
}
-static void *event_loop(void *arg) {
- struct Term *term = arg;
- fd_set rfds;
-
- while (1) {
- FD_ZERO(&rfds);
- FD_SET(term->masterfd, &rfds);
- if (select(term->masterfd + 1, &rfds, NULL, NULL, NULL) == 1) {
- kill(getpid(), SIGUSR1);
- usleep(20000);
- }
- }
-
- return NULL;
-}
-
int emacs_module_init(struct emacs_runtime *ert) {
emacs_env *env = ert->get_environment(ert);
@@ -482,6 +368,7 @@ int emacs_module_init(struct emacs_runtime *ert) {
Fput_text_property = env->intern(env, "put-text-property");
Fset = env->intern(env, "set");
Fvterm_face_color_hex = env->intern(env, "vterm--face-color-hex");
+ Fvterm_flush_output = env->intern(env, "vterm--flush-output");
// Faces
Qterm = env->intern(env, "vterm");
@@ -497,16 +384,16 @@ int emacs_module_init(struct emacs_runtime *ert) {
// Exported functions
emacs_value fun;
fun =
- env->make_function(env, 3, 3, Fvterm_new, "Allocates a new vterm.", NULL);
+ env->make_function(env, 2, 2, Fvterm_new, "Allocates a new vterm.", NULL);
bind_function(env, "vterm--new", fun);
fun = env->make_function(env, 1, 5, Fvterm_update,
"Process io and update the screen.", NULL);
bind_function(env, "vterm--update", fun);
- fun = env->make_function(env, 1, 1, Fvterm_kill,
- "Kill the the shell process.", NULL);
- bind_function(env, "vterm--kill", fun);
+ fun = env->make_function(env, 2, 2, Fvterm_write_input,
+ "Write input to vterm.", NULL);
+ bind_function(env, "vterm--write-input", fun);
fun = env->make_function(env, 3, 3, Fvterm_set_size,
"Sets the size of the terminal.", NULL);
diff --git a/vterm-module.h b/vterm-module.h
index 477ad01..64a5b20 100644
--- a/vterm-module.h
+++ b/vterm-module.h
@@ -11,9 +11,6 @@ int plugin_is_GPL_compatible;
struct Term {
VTerm *vt;
- int masterfd;
- pid_t pid;
- pthread_t thread;
};
// Faces
@@ -36,7 +33,7 @@ static int set_term_prop_cb(VTermProp prop, VTermValue *val, void *user_data);
static void term_redraw(struct Term *term, emacs_env *env);
static void term_setup_colors(struct Term *term, emacs_env *env);
-static void term_flush_output(struct Term *term);
+static void term_flush_output(struct Term *term, emacs_env *env);
static void term_process_key(struct Term *term, unsigned char *key, size_t len,
VTermModifier modifier);
static void term_put_caret(struct Term *term, emacs_env *env, int row, int col,
@@ -47,12 +44,6 @@ static emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs,
emacs_value args[], void *data);
static emacs_value Fvterm_update(emacs_env *env, ptrdiff_t nargs,
emacs_value args[], void *data);
-static emacs_value Fvterm_kill(emacs_env *env, ptrdiff_t nargs,
- emacs_value args[], void *data);
-static emacs_value Fvterm_set_size(emacs_env *env, ptrdiff_t nargs,
- emacs_value args[], void *data);
-
-static void *event_loop(void *arg);
int emacs_module_init(struct emacs_runtime *ert);
#endif /* VTERM_MODULE_H */
diff --git a/vterm.el b/vterm.el
index 8d37199..ed0acc4 100644
--- a/vterm.el
+++ b/vterm.el
@@ -72,18 +72,27 @@ be send to the terminal."
"Pointer to struct Term.")
(make-variable-buffer-local 'vterm--term)
-(defvar vterm--buffers nil
- "List of active vterm-buffers.")
+(defvar vterm--process nil
+ "Shell process of current term.")
+(make-variable-buffer-local 'vterm--term)
(define-derived-mode vterm-mode fundamental-mode "VTerm"
"Mayor mode for vterm buffer."
(buffer-disable-undo)
- (setq vterm--term (vterm--new vterm-shell (window-body-height) (window-body-width))
+ (setq vterm--term (vterm--new (window-body-height) (window-body-width))
buffer-read-only t)
(setq-local scroll-conservatively 101)
(setq-local scroll-margin 0)
- (add-hook 'kill-buffer-hook #'vterm--kill-buffer-hook t t)
- (add-hook 'window-size-change-functions #'vterm--window-size-change t t))
+ (add-hook 'window-size-change-functions #'vterm--window-size-change t t)
+ (let ((process-environment (nconc '("TERM=xterm") process-environment)))
+ (setq vterm--process (make-process
+ :name "vterm"
+ :buffer buffer
+ :command `("/bin/sh" "-c" ,(format "stty -nl sane iutf8 rows %d columns %d >/dev/null && exec %s" (window-body-height) (window-body-width) vterm-shell))
+ :coding 'no-conversion
+ :connection-type 'pty
+ :filter #'vterm--filter
+ :sentinel #'vterm--sentinel))))
;; Keybindings
(define-key vterm-mode-map [t] #'vterm--self-insert)
@@ -104,17 +113,16 @@ be send to the terminal."
(defun vterm--self-insert ()
"Sends invoking key to libvterm."
(interactive)
- (let* ((modifiers (event-modifiers last-input-event))
- (shift (memq 'shift modifiers))
- (meta (memq 'meta modifiers))
- (ctrl (memq 'control modifiers))
- (window (posn-window (event-end last-input-event))))
- (when-let ((key (key-description (vector (event-basic-type last-input-event))))
- (inhibit-redisplay t)
- (inhibit-read-only t))
- (when (equal modifiers '(shift))
- (setq key (upcase key)))
- (with-selected-window window
+ (when vterm--term
+ (let* ((modifiers (event-modifiers last-input-event))
+ (shift (memq 'shift modifiers))
+ (meta (memq 'meta modifiers))
+ (ctrl (memq 'control modifiers)))
+ (when-let ((key (key-description (vector (event-basic-type last-input-event))))
+ (inhibit-redisplay t)
+ (inhibit-read-only t))
+ (when (equal modifiers '(shift))
+ (setq key (upcase key)))
(vterm--update vterm--term key shift meta ctrl)))))
(defun vterm ()
@@ -123,7 +131,6 @@ be send to the terminal."
(let ((buffer (generate-new-buffer "vterm")))
(set-buffer buffer)
(vterm-mode)
- (add-to-list 'vterm--buffers buffer)
(switch-to-buffer buffer)))
(defun vterm-other-window ()
@@ -132,36 +139,31 @@ be send to the terminal."
(let ((buffer (generate-new-buffer "vterm")))
(set-buffer buffer)
(vterm-mode)
- (add-to-list 'vterm--buffers buffer)
(pop-to-buffer buffer)))
-(defun vterm--event ()
- "Update the vterm BUFFER."
- (interactive)
- (let ((inhibit-redisplay t)
- (inhibit-read-only t))
- (mapc (lambda (buffer)
- (with-current-buffer buffer
- (unless (vterm--update vterm--term)
- (kill-buffer-and-window)
- (message "Shell exited!"))))
- vterm--buffers)))
-
-(define-key special-event-map [sigusr1] #'vterm--event)
-
-(defun vterm--kill-buffer-hook ()
- "Kill the corresponding process of vterm."
- (when (eq major-mode 'vterm-mode)
- (setq vterm--buffers (remove (current-buffer) vterm--buffers))
- (vterm--kill vterm--term)))
+(defun vterm--flush-output (output)
+ (process-send-string vterm--process output))
+
+(defun vterm--filter (process input)
+ (with-current-buffer (process-buffer process)
+ (vterm--write-input vterm--term input)
+ (let ((inhibit-read-only t)
+ (inhibit-redisplay t))
+ (vterm--update vterm--term))))
+
+(defun vterm--sentinel (process event)
+ )
(defun vterm--window-size-change (frame)
- "Notify the vterm over size-change in FRAME."
- (dolist (window (window-list frame 1))
- (let ((buffer (window-buffer window)))
- (with-current-buffer buffer
- (when (eq major-mode 'vterm-mode)
- (vterm--set-size vterm--term (window-body-height) (window-body-width)))))))
+ (dolist (window (window-list frame))
+ (with-current-buffer (window-buffer window)
+ (when (and (processp vterm--process)
+ (process-live-p vterm--process))
+ (let ((height (window-body-height window))
+ (width (window-body-width window)))
+ (set-process-window-size vterm--process height width)
+ (message "%s %s" height width)
+ (vterm--set-size vterm--term height width))))))
(defun vterm--face-color-hex (face attr)
"Return the color of the FACE's ATTR as a hex string."