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 }