ref: 76aec5fa7a058f6a9f69570efe13dff3cb957e76
dir: /terminal_posix.c/
#include "flisp.h" #include <sys/ioctl.h> #include <termios.h> static bool inraw = false; static bool cursorvisible = true; static bool atexitset = false; static struct termios tios; static void termreset(void); static int termsetraw(bool raw, bool showcursor) { if(!atexitset){ atexit(termreset); atexitset = true; } if(showcursor && !cursorvisible){ write(STDOUT_FILENO, "\x1b[?25h", 6); cursorvisible = true; }else if(!showcursor && cursorvisible){ write(STDOUT_FILENO, "\x1b[?25l", 6); cursorvisible = false; } if(raw && !inraw){ if(tcgetattr(STDIN_FILENO, &tios) < 0) return -1; struct termios t; memcpy(&t, &tios, sizeof(t)); t.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | 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; } static void termreset(void) { termsetraw(false, true); } BUILTIN("terminal-enter-raw-mode", terminal_enter_raw_mode) { USED(args); argcount(nargs, 0); return termsetraw(true, cursorvisible) == 0 ? FL_t : FL_f; } BUILTIN("terminal-leave-raw-mode", terminal_leave_raw_mode) { USED(args); argcount(nargs, 0); return termsetraw(false, cursorvisible) == 0 ? FL_t : FL_f; } BUILTIN("terminal-show-cursor", terminal_show_cursor) { USED(args); argcount(nargs, 0); return termsetraw(inraw, true) == 0 ? FL_t : FL_f; } BUILTIN("terminal-hide-cursor", terminal_hide_cursor) { USED(args); argcount(nargs, 0); return termsetraw(inraw, 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)) = FL_nil; int x = s.ws_xpixel, y = s.ws_ypixel; bool wasraw = inraw; if((x == 0 || y == 0) && isatty(STDOUT_FILENO) && termsetraw(true, cursorvisible) == 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, cursorvisible); } cdr_(v) = pix = mk_cons(); cdr_(pix) = FL_nil; car_(pix) = mk_cons(); pix = car_(pix); car_(pix) = fixnum(x); cdr_(pix) = mk_cons(); car_(cdr_(pix)) = fixnum(y); cdr_(cdr_(pix)) = FL_nil; return v; }