ref: 9db91979e51a69f53edca7b46f84f73ae95454f9
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;
}