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;
+}