shithub: femtolisp

Download patch

ref: 2479b2254aacacf40b210db48d8665f99a11ef02
parent: 10e8e99e07e8bfc3d2fc68efe95a572e8adc65a0
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sun Nov 3 15:03:09 EST 2024

add terminal-{enter,leave}-raw-mode and terminal-get-size

--- a/meson.build
+++ b/meson.build
@@ -77,6 +77,7 @@
 	'read.c',
 	'string.c',
 	'table.c',
+	'terminal_posix.c',
 	'time_posix.c',
 	'types.c',
 	'utf8.c',
--- /dev/null
+++ b/terminal_posix.c
@@ -1,0 +1,96 @@
+#include "llt.h"
+#include "flisp.h"
+#include <sys/ioctl.h>
+#include <termios.h>
+
+static bool inraw = false;
+static struct termios tios;
+
+static int
+termsetraw(bool raw)
+{
+	if(raw && !inraw){
+		if(tcgetattr(STDIN_FILENO, &tios) < 0)
+			return -1;
+		struct termios t;
+		memcpy(&t, &tios, sizeof(t));
+		t.c_iflag &= ~(BRKINT | ICRNL | IXON);
+		t.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
+		t.c_oflag &= ~(OPOST);
+		t.c_cc[VMIN] = 0;
+		if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) < 0)
+			return -1;
+		inraw = true;
+	}else if(!raw && inraw){
+		if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &tios) < 0)
+			return -1;
+		inraw = false;
+	}
+	return 0;
+}
+
+BUILTIN("terminal-enter-raw-mode", terminal_enter_raw_mode)
+{
+	USED(args);
+	argcount(nargs, 0);
+	return termsetraw(true) == 0 ? FL_T : FL_F;
+}
+
+BUILTIN("terminal-leave-raw-mode", terminal_leave_raw_mode)
+{
+	USED(args);
+	argcount(nargs, 0);
+	return termsetraw(false) == 0 ? FL_T : FL_F;
+}
+
+BUILTIN("terminal-get-size", terminal_get_size)
+{
+	USED(args);
+	argcount(nargs, 0);
+	struct winsize s;
+	if(ioctl(STDIN_FILENO, TIOCGWINSZ, &s) < 0)
+		return FL_F;
+	value_t v = mk_cons(), tex, pix;
+	car_(v) = tex = mk_cons();
+	car_(tex) = fixnum(s.ws_col);
+	cdr_(tex) = mk_cons(); car_(cdr_(tex)) = fixnum(s.ws_row); cdr_(cdr_(tex)) = NIL;
+	int x = s.ws_xpixel, y = s.ws_ypixel;
+	bool wasraw = inraw;
+	if((x == 0 || y == 0) && isatty(STDOUT_FILENO) && termsetraw(true) == 0){
+		// FIXME(sigrid): read everything out of stdin first
+		write(STDOUT_FILENO, "\x1b[14t", 5);
+		/* make sure not to hang if nothing is returned */
+		struct timeval t;
+		t.tv_sec = 0;
+		t.tv_usec = 100;
+		fd_set f;
+		FD_ZERO(&f);
+		FD_SET(STDIN_FILENO, &f);
+		int r;
+		while((r = select(STDIN_FILENO+1, &f, nil, nil, &t)) == EINTR);
+		if(r > 0 && FD_ISSET(STDIN_FILENO, &f)){
+			char buf[64];
+			if((r = read(STDIN_FILENO, buf, sizeof(buf)-1)) >= 8){
+				buf[r] = 0;
+				if(buf[0] == 0x1b && buf[1] == '[' && buf[2] == '4' && buf[3] == ';'){ /* CSI 4 */
+					x = atoi(buf+5);
+					char *s = strchr(buf+5, ';');
+					if(s != nil)
+						y = atoi(s+1);
+					while(strchr(buf, 't') == nil){
+						if((r = read(STDIN_FILENO, buf, sizeof(buf)-1)) <= 0)
+							break;
+						buf[r] = 0;
+					}
+				}
+			}
+		}
+		if(!wasraw)
+			termsetraw(false);
+	}
+	cdr_(v) = pix = mk_cons(); cdr_(pix) = NIL;
+	car_(pix) = mk_cons(); pix = car_(pix);
+	car_(pix) = fixnum(x);
+	cdr_(pix) = mk_cons(); car_(cdr_(pix)) = fixnum(y); cdr_(cdr_(pix)) = NIL;
+	return v;
+}