fzy

terminal fuzzy finder picker

git clone https://9o.is/git/fzy.git

tty.c

(3857B)


      1 #include <unistd.h>
      2 #include <fcntl.h>
      3 #include <stdlib.h>
      4 #include <stdarg.h>
      5 #include <termios.h>
      6 #include <sys/ioctl.h>
      7 #include <sys/select.h>
      8 #include <signal.h>
      9 #include <errno.h>
     10 
     11 #include "tty.h"
     12 
     13 #include "../config.h"
     14 
     15 void tty_reset(tty_t *tty) {
     16 	tcsetattr(tty->fdin, TCSANOW, &tty->original_termios);
     17 }
     18 
     19 void tty_close(tty_t *tty) {
     20 	tty_reset(tty);
     21 	fclose(tty->fout);
     22 	close(tty->fdin);
     23 }
     24 
     25 static void handle_sigwinch(int sig){
     26 	(void)sig;
     27 }
     28 
     29 void tty_init(tty_t *tty, const char *tty_filename) {
     30 	tty->fdin = open(tty_filename, O_RDONLY);
     31 	if (tty->fdin < 0) {
     32 		perror("Failed to open tty");
     33 		exit(EXIT_FAILURE);
     34 	}
     35 
     36 	tty->fout = fopen(tty_filename, "w");
     37 	if (!tty->fout) {
     38 		perror("Failed to open tty");
     39 		exit(EXIT_FAILURE);
     40 	}
     41 
     42 	if (setvbuf(tty->fout, NULL, _IOFBF, 16384)) {
     43 		perror("setvbuf");
     44 		exit(EXIT_FAILURE);
     45 	}
     46 
     47 	if (tcgetattr(tty->fdin, &tty->original_termios)) {
     48 		perror("tcgetattr");
     49 		exit(EXIT_FAILURE);
     50 	}
     51 
     52 	struct termios new_termios = tty->original_termios;
     53 
     54 	/*
     55 	 * Disable all of
     56 	 * ICANON  Canonical input (erase and kill processing).
     57 	 * ECHO    Echo.
     58 	 * ISIG    Signals from control characters
     59 	 * ICRNL   Conversion of CR characters into NL
     60 	 */
     61 	new_termios.c_iflag &= ~(ICRNL);
     62 	new_termios.c_lflag &= ~(ICANON | ECHO | ISIG);
     63 
     64 	if (tcsetattr(tty->fdin, TCSANOW, &new_termios))
     65 		perror("tcsetattr");
     66 
     67 	tty_getwinsz(tty);
     68 
     69 	tty_setnormal(tty);
     70 
     71 	signal(SIGWINCH, handle_sigwinch);
     72 }
     73 
     74 void tty_getwinsz(tty_t *tty) {
     75 	struct winsize ws;
     76 	if (ioctl(fileno(tty->fout), TIOCGWINSZ, &ws) == -1) {
     77 		tty->maxwidth = 80;
     78 		tty->maxheight = 25;
     79 	} else {
     80 		tty->maxwidth = ws.ws_col;
     81 		tty->maxheight = ws.ws_row;
     82 	}
     83 }
     84 
     85 char tty_getchar(tty_t *tty) {
     86 	char ch;
     87 	int size = read(tty->fdin, &ch, 1);
     88 	if (size < 0) {
     89 		perror("error reading from tty");
     90 		exit(EXIT_FAILURE);
     91 	} else if (size == 0) {
     92 		/* EOF */
     93 		exit(EXIT_FAILURE);
     94 	} else {
     95 		return ch;
     96 	}
     97 }
     98 
     99 int tty_input_ready(tty_t *tty, long int timeout, int return_on_signal) {
    100 	fd_set readfs;
    101 	FD_ZERO(&readfs);
    102 	FD_SET(tty->fdin, &readfs);
    103 
    104 	struct timespec ts = {timeout / 1000, (timeout % 1000) * 1000000};
    105 
    106 	sigset_t mask;
    107 	sigemptyset(&mask);
    108 	if (!return_on_signal)
    109 		sigaddset(&mask, SIGWINCH);
    110 
    111 	int err = pselect(
    112 			tty->fdin + 1,
    113 			&readfs,
    114 			NULL,
    115 			NULL,
    116 			timeout < 0 ? NULL : &ts,
    117 			return_on_signal ? NULL : &mask);
    118 
    119 	if (err < 0) {
    120 		if (errno == EINTR) {
    121 			return 0;
    122 		} else {
    123 			perror("select");
    124 			exit(EXIT_FAILURE);
    125 		}
    126 	} else {
    127 		return FD_ISSET(tty->fdin, &readfs);
    128 	}
    129 }
    130 
    131 static void tty_sgr(tty_t *tty, int code) {
    132 	tty_printf(tty, "%c%c%im", 0x1b, '[', code);
    133 }
    134 
    135 void tty_setfg(tty_t *tty, int fg) {
    136 	if (tty->fgcolor != fg) {
    137 		tty_sgr(tty, 30 + fg);
    138 		tty->fgcolor = fg;
    139 	}
    140 }
    141 
    142 void tty_setbold(tty_t *tty) {
    143 	tty_sgr(tty, 1);
    144 }
    145 
    146 void tty_unsetbold(tty_t *tty) {
    147 	tty_sgr(tty, 22);
    148 }
    149 
    150 void tty_setinvert(tty_t *tty) {
    151 	tty_sgr(tty, 7);
    152 }
    153 
    154 void tty_setunderline(tty_t *tty) {
    155 	tty_sgr(tty, 4);
    156 }
    157 
    158 void tty_setnormal(tty_t *tty) {
    159 	tty_sgr(tty, 0);
    160 	tty->fgcolor = 9;
    161 }
    162 
    163 void tty_setnowrap(tty_t *tty) {
    164 	tty_printf(tty, "%c%c?7l", 0x1b, '[');
    165 }
    166 
    167 void tty_setwrap(tty_t *tty) {
    168 	tty_printf(tty, "%c%c?7h", 0x1b, '[');
    169 }
    170 
    171 void tty_newline(tty_t *tty) {
    172 	tty_printf(tty, "%c%cK\n", 0x1b, '[');
    173 }
    174 
    175 void tty_clearline(tty_t *tty) {
    176 	tty_printf(tty, "%c%c2K\r", 0x1b, '[');
    177 }
    178 
    179 void tty_setcol(tty_t *tty, int col) {
    180 	tty_printf(tty, "%c%c%iG", 0x1b, '[', col + 1);
    181 }
    182 
    183 void tty_moveup(tty_t *tty, int i) {
    184 	tty_printf(tty, "%c%c%iA", 0x1b, '[', i);
    185 }
    186 
    187 void tty_printf(tty_t *tty, const char *fmt, ...) {
    188 	va_list args;
    189 	va_start(args, fmt);
    190 	vfprintf(tty->fout, fmt, args);
    191 	va_end(args);
    192 }
    193 
    194 void tty_putc(tty_t *tty, char c) {
    195 	fputc(c, tty->fout);
    196 }
    197 
    198 void tty_flush(tty_t *tty) {
    199 	fflush(tty->fout);
    200 }
    201 
    202 size_t tty_getwidth(tty_t *tty) {
    203 	return tty->maxwidth;
    204 }
    205 
    206 size_t tty_getheight(tty_t *tty) {
    207 	return tty->maxheight;
    208 }