aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Fürmetz <fuermetz@mailbox.org>2017-05-29 14:37:47 +0700
committerLukas Fürmetz <fuermetz@mailbox.org>2017-05-29 14:37:47 +0700
commit77a4e08574dfb956299233fa742516888ae0b55d (patch)
tree35f135bf2e470ac64c16166645fd09a148ffa496
parente99ea810a4fb161e4da9dbb29f8b551429abb726 (diff)
Another approach
-rw-r--r--.gitignore2
-rw-r--r--Makefile8
-rw-r--r--emacs-libvterm.c262
-rw-r--r--vterm-module.c82
-rw-r--r--vterm.el30
5 files changed, 117 insertions, 267 deletions
diff --git a/.gitignore b/.gitignore
index 10530e0..6c6b294 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-emacs-libvterm.so
+vterm-module.so
diff --git a/Makefile b/Makefile
index 81c53d4..b5021d1 100644
--- a/Makefile
+++ b/Makefile
@@ -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)