diff options
| author | Lukas Fürmetz <fuermetz@mailbox.org> | 2017-05-29 14:37:47 +0700 |
|---|---|---|
| committer | Lukas Fürmetz <fuermetz@mailbox.org> | 2017-05-29 14:37:47 +0700 |
| commit | 77a4e08574dfb956299233fa742516888ae0b55d (patch) | |
| tree | 35f135bf2e470ac64c16166645fd09a148ffa496 | |
| parent | e99ea810a4fb161e4da9dbb29f8b551429abb726 (diff) | |
Another approach
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | Makefile | 8 | ||||
| -rw-r--r-- | emacs-libvterm.c | 262 | ||||
| -rw-r--r-- | vterm-module.c | 82 | ||||
| -rw-r--r-- | vterm.el | 30 |
5 files changed, 117 insertions, 267 deletions
@@ -1 +1 @@ -emacs-libvterm.so +vterm-module.so @@ -1,6 +1,6 @@ # path to the emacs source dir # (you can provide it here or on the command line) -EMACS-SRC = /home/lukas/.local/aur/emacs/emacs-25.1 +EMACS-SRC = /home/lukas/.local/aur/emacs/emacs-25.2 LIBVTERM = /usr/include CC = gcc LD = gcc @@ -9,7 +9,7 @@ LDFLAGS = ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) -all: emacs-libvterm.so +all: vterm-module.so # make shared library out of the object file %.so: %.o @@ -19,5 +19,5 @@ all: emacs-libvterm.so %.o: %.c $(CC) $(CFLAGS) -I$(EMACS-SRC)/src -I/ -fPIC -c $< -run: emacs-libvterm.so - emacs -L $(ROOT) --eval "(require 'emacs-libvterm)" # --eval '(insert "(vterm-new)")' +run: vterm-module.so + emacs -L $(ROOT) --eval "(require 'vterm)" # --eval '(insert "(vterm-new)")' diff --git a/emacs-libvterm.c b/emacs-libvterm.c deleted file mode 100644 index 7ff5e19..0000000 --- a/emacs-libvterm.c +++ /dev/null @@ -1,262 +0,0 @@ -#include <emacs-module.h> -#include <string.h> -#include <vterm.h> -#include <vterm_keycodes.h> -#include <pty.h> -#include <unistd.h> -#include <pthread.h> -#include <poll.h> -#include <semaphore.h> -#include <signal.h> - -/* Declare mandatory GPL symbol. */ -int plugin_is_GPL_compatible; - -struct Term { - int masterfd; - struct VTerm *vt; - sem_t mutex_cells; - char cells[24][80]; - char buffer[4096]; - int read_size; -}; - -/* Bind NAME to FUN. */ -static void -bind_function (emacs_env *env, const char *name, emacs_value Sfun) -{ - /* Set the function cell of the symbol named NAME to SFUN using - the 'fset' function. */ - - /* Convert the strings to symbols by interning them */ - emacs_value Qfset = env->intern (env, "fset"); - emacs_value Qsym = env->intern (env, name); - - /* Prepare the arguments array */ - emacs_value args[] = { Qsym, Sfun }; - - /* Make the call (2 == nb of arguments) */ - env->funcall (env, Qfset, 2, args); -} - -/* Provide FEATURE to Emacs. */ -static void -provide (emacs_env *env, const char *feature) -{ - /* call 'provide' with FEATURE converted to a symbol */ - - emacs_value Qfeat = env->intern (env, feature); - emacs_value Qprovide = env->intern (env, "provide"); - emacs_value args[] = { Qfeat }; - - env->funcall (env, Qprovide, 1, args); -} - -static void -insert(emacs_env *env, const char c) -{ - char string[1] = {c}; - emacs_value Qinsert = env->intern(env, "insert"); - emacs_value Qstring = env->make_string(env, string, 1); - emacs_value args[] = { Qstring }; - - env->funcall(env, Qinsert, 1, args); -} - -static void *io_loop(void *arg) { - struct Term *t = (struct Term *)arg; - - int i, j; - for (i = 0; i < 24; i++) { - for (j = 0; j < 80; j++) { - t->cells[i][j] = '0'; - } - } - - while (1) { - /* struct pollfd p = { t->masterfd, (0 | POLLIN), 0}; */ - /* poll(&p, 1, 10); */ - /* if ((p.revents & POLLIN) == POLLIN) { */ - ssize_t size; - char buffer[4096]; - while ((size = read(t->masterfd, buffer, sizeof buffer)) > 0) { - sem_wait(&t->mutex_cells); - vterm_input_write(t->vt, buffer, size); - sem_post(&t->mutex_cells); - } - - /* } */ - - size_t bufflen = vterm_output_get_buffer_current(t->vt); - if(bufflen) { - char buffer[bufflen]; - bufflen = vterm_output_read(t->vt, buffer, bufflen); - write(t->masterfd, buffer, bufflen); - } - } -} - -static emacs_value -Fvterm_get_output (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data) { - struct Term *t = (struct Term*) data; - sem_wait(&t->mutex_cells); - - int i, j; - int rows, cols; - VTermScreen *screen = vterm_obtain_screen(t->vt); - vterm_get_size(t->vt, &rows, &cols); - insert(env, rows); - insert(env, '\n'); - insert(env, cols); - insert(env, '\n'); - insert(env, t->read_size); - insert(env, '\n'); - for (i = 0; i < rows; i++) { - for (j = 0; j < cols; j++) { - VTermPos pos = { .row = i, .col = j}; - VTermScreenCell cell; - vterm_screen_get_cell(screen, pos, &cell); - insert(env, cell.chars[0]); - } - } - sem_post(&t->mutex_cells); - - return env->make_integer(env, 0); -} - -/* New emacs lisp function. All function exposed to Emacs must have this prototype. */ -static emacs_value -Fvterm_new (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data) -{ - int rows = 24; - int columns = 80; - - struct winsize size = { rows, columns, 0, 0}; - - struct termios termios = { - .c_iflag = ICRNL|IXON, - .c_oflag = OPOST|ONLCR -#ifdef TAB0 - |TAB0 -#endif - , - .c_cflag = CS8|CREAD, - .c_lflag = ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK, - /* c_cc later */ - }; - -#ifdef IUTF8 - termios.c_iflag |= IUTF8; -#endif -#ifdef NL0 - termios.c_oflag |= NL0; -#endif -#ifdef CR0 - termios.c_oflag |= CR0; -#endif -#ifdef BS0 - termios.c_oflag |= BS0; -#endif -#ifdef VT0 - termios.c_oflag |= VT0; -#endif -#ifdef FF0 - termios.c_oflag |= FF0; -#endif -#ifdef ECHOCTL - termios.c_lflag |= ECHOCTL; -#endif -#ifdef ECHOKE - termios.c_lflag |= ECHOKE; -#endif - - 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; - - VTerm *vt = vterm_new(rows, columns); - vterm_set_utf8(vt, 1); - -/* VTermScreen *screen = vterm_obtain_screen(vt); */ -/* /\* VTermScreenCallbacks callbacks = { *\/ */ -/* /\* . *\/ */ -/* /\* } *\/ */ -/* vterm_screen_set_callbacks(screen, callbacks, NULL); */ - - struct Term *t = malloc(sizeof(struct Term)); - t->vt = vt; - t->read_size = 0; - sem_init(&t->mutex_cells, 0, 1); - - pid_t pid = forkpty(&t->masterfd, NULL, &termios, &size); - if (pid == 0) { - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGSTOP, SIG_DFL); - signal(SIGCONT, SIG_DFL); - - putenv("TERM=xterm"); - - char *shell = getenv("SHELL"); - char *args[2] = { shell, NULL }; - execvp(shell, args); - exit(1); - } - - char buffer[4096]; - ssize_t bytes = read(t->masterfd, buffer, sizeof buffer); - vterm_input_write(vt, buffer, bytes); - insert(env, '\n'); - insert(env, bytes); - insert(env, '\n'); - - emacs_value fun = env->make_function (env, - 0, /* min. number of arguments */ - 0, /* max. number of arguments */ - Fvterm_get_output, /* actual function pointer */ - "doc", /* docstring */ - t /* user pointer of your choice (data param in Fmymod_test) */ - ); - bind_function (env, "vterm_get_output", fun); - - pthread_t thread; - // TODO: Error handling - int ret = pthread_create(&thread, NULL, io_loop, t); - - return env->make_integer(env, ret); -} - -int -emacs_module_init (struct emacs_runtime *ert) -{ - emacs_env *env = ert->get_environment (ert); - - emacs_value fun; - fun = env->make_function (env, - 0, /* min. number of arguments */ - 0, /* max. number of arguments */ - Fvterm_new, /* actual function pointer */ - "doc", /* docstring */ - NULL /* user pointer of your choice (data param in Fmymod_test) */ - ); - bind_function (env, "vterm_new", fun); - - provide (env, "emacs-libvterm"); - - /* loaded successfully */ - return 0; -} diff --git a/vterm-module.c b/vterm-module.c new file mode 100644 index 0000000..c8487a9 --- /dev/null +++ b/vterm-module.c @@ -0,0 +1,82 @@ +#include <emacs-module.h> +#include <vterm.h> + +/* Declare mandatory GPL symbol. */ +int plugin_is_GPL_compatible; + +/* Bind NAME to FUN. */ +static void +bind_function (emacs_env *env, const char *name, emacs_value Sfun) +{ + /* Set the function cell of the symbol named NAME to SFUN using + the 'fset' function. */ + + /* Convert the strings to symbols by interning them */ + emacs_value Qfset = env->intern (env, "fset"); + emacs_value Qsym = env->intern (env, name); + + /* Prepare the arguments array */ + emacs_value args[] = { Qsym, Sfun }; + + /* Make the call (2 == nb of arguments) */ + env->funcall (env, Qfset, 2, args); +} + +/* Provide FEATURE to Emacs. */ +static void +provide (emacs_env *env, const char *feature) +{ + /* call 'provide' with FEATURE converted to a symbol */ + + emacs_value Qfeat = env->intern (env, feature); + emacs_value Qprovide = env->intern (env, "provide"); + emacs_value args[] = { Qfeat }; + + env->funcall (env, Qprovide, 1, args); +} + +static int +string_len (emacs_env *env, emacs_value string) +{ + ptrdiff_t size = 0; + env->copy_string_contents (env, string, NULL, &size); + return size; +} + +static emacs_value +Fvterm_input_write (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data) +{ + int rows = 24; + int columns = 80; + + VTerm *vt = vterm_new(rows, columns); + vterm_set_utf8(vt, 1); + + ptrdiff_t len = string_len(env, args[0]); + char buffer[len]; + int ret = env->copy_string_contents(env, args[0], buffer, &len); + + vterm_input_write(vt, buffer, len); + + return env->make_integer(env, len); +} + +int +emacs_module_init (struct emacs_runtime *ert) +{ + emacs_env *env = ert->get_environment (ert); + + emacs_value fun; + fun = env->make_function (env, + 1, + 1, + Fvterm_input_write, + "Writes input to libvterm", + NULL + ); + bind_function (env, "vterm-input-write", fun); + + provide (env, "vterm-module"); + + return 0; +} diff --git a/vterm.el b/vterm.el new file mode 100644 index 0000000..49e03bf --- /dev/null +++ b/vterm.el @@ -0,0 +1,30 @@ +(require 'vterm-module) + +(defvar vterm-process nil + "The shell process.") + +(define-derived-mode vterm-mode fundamental-mode "VTerm" + "TODO: Documentation.") + +(defun vterm-new () + (interactive) + (let ((buffer (generate-new-buffer "vterm"))) + (with-current-buffer buffer + (vterm-mode) + (setq vterm-process + (make-process :name "vterm-shell" + :buffer buffer + :command (list (getenv "SHELL")) + :coding 'utf-8 + :connection-type 'pipe + :filter #'vterm-process-filter + :sentinel #'vterm-process-sentinel))) + (pop-to-buffer buffer))) + +(defun vterm-process-filter (process output) + (vterm-input-write output)) + +(defun vterm-process-sentinel (process event) + ) + +(provide 'vterm) |
