cleaner page next/prev and global window dimension property - iomenu - interactive terminal-based selection menu HTML git clone git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- DIR commit 62853eb76762d6adfac4bd5cbcc410e96ebc955f DIR parent a74019ac53549e4017a2aa36bd377c1e0c2c9fc7 HTML Author: Josuah Demangeonā ā µ <mail@josuah.net> Date: Sun, 19 Mar 2017 11:49:25 +0100 cleaner page next/prev and global window dimension property Diffstat: M iomenu.c | 199 ++++++++++++++++--------------- 1 file changed, 103 insertions(+), 96 deletions(-) --- DIR diff --git a/iomenu.c b/iomenu.c @@ -17,15 +17,18 @@ #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) -char input[BUFSIZ]; -int current = 0, offset = 0, prev = 0, next = 0; -int linec = 0, matchc = 0; -char **linev = NULL, **matchv = NULL; -char *opt_prompt = ""; -int opt_lines = 0; +static struct winsize winsize; +static struct termios termios; +static char input[BUFSIZ]; +static int current = 0, offset = 0, prev = 0, next = 0; +static int linec = 0, matchc = 0; +static char **linev = NULL, **matchv = NULL; +static char *opt_prompt = ""; +static int opt_lines = 0; -void + +static void free_v(char **v, int c) { for (; c > 0; c--) @@ -35,7 +38,7 @@ free_v(char **v, int c) } -void +static void die(const char *s) { /* tcsetattr(STDIN_FILENO, TCSANOW, &termio_old); */ @@ -44,25 +47,21 @@ die(const char *s) } -struct termios +static void set_terminal(int tty_fd) { - struct termios termio_old; - struct termios termio_new; - - if (tcgetattr(tty_fd, &termio_old) < 0) - die("Can not get terminal attributes with tcgetattr()."); - - termio_new = termio_old; - termio_new.c_lflag &= ~(ICANON | ECHO | IGNBRK); + if (tcgetattr(tty_fd, &termios) < 0) { + perror("tcgetattr"); + exit(EXIT_FAILURE); + } - tcsetattr(tty_fd, TCSANOW, &termio_new); + termios.c_lflag &= ~(ICANON | ECHO | IGNBRK); - return termio_old; + tcsetattr(tty_fd, TCSANOW, &termios); } -void +static void read_lines(void) { char buffer[BUFSIZ]; @@ -99,7 +98,7 @@ read_lines(void) } -int +static int match_line(char *line, char **tokv, int tokc) { for (int i = 0; i < tokc; i++) @@ -110,38 +109,7 @@ match_line(char *line, char **tokv, int tokc) } -void -filter_lines(void) -{ - char **tokv = NULL, *s, buffer[sizeof (input)]; - int tokc = 0, n = 0; - - current = offset = prev = next = 0; - - /* tokenize input from space characters, this comes from dmenu */ - strcpy(buffer, input); - for (s = strtok(buffer, " "); s; s = strtok(NULL, " "), tokc++) { - - if (tokc >= n) { - tokv = realloc(tokv, ++n * sizeof (*tokv)); - - if (tokv == NULL) - die("realloc"); - } - - tokv[tokc] = s; - } - - matchc = 0; - for (int i = 0; i < linec; i++) - if (match_line(linev[i], tokv, tokc)) - matchv[matchc++] = linev[i]; - - free(tokv); -} - - -void +static void print_string(char *str, int current) { fputs(current ? "\033[30;47m" : "", stderr); @@ -150,8 +118,8 @@ print_string(char *str, int current) } -void -print_lines(int count, int cols) +static void +print_lines(int count) { int p = 0; /* amount of lines printed */ offset = current / count * count; @@ -166,86 +134,92 @@ print_lines(int count, int cols) } -void -update_pages(int pos, int cols) +static int +prev_page(int pos, int cols) { - int col; + pos--; + for (int col = 0; pos > 0; pos--) + if ((col += strlen(matchv[pos]) + 2) > cols) + return pos + 1; - for (prev = pos, col = 0; prev > 0; prev--) - if ((col += strlen(matchv[prev]) + 2) > cols) - break; + return pos; +} - for (next = pos, col = 0; next <= matchc; next++) - if ((col += strlen(matchv[next]) + 2) > cols) - break; - next++; - next--; +static int +next_page(int pos, int cols) +{ + for (int col = 0; pos < matchc; pos++) + if ((col += strlen(matchv[pos]) + 2) > cols) + return pos - 1; + + return pos; } -void -print_columns(int cols) +static void +print_columns(void) { if (current < offset) { + next = offset; offset = prev; - update_pages(offset, cols - 30 - 1); + prev = prev_page(offset, winsize.ws_col - 30 - 1); } else if (current >= next) { + prev = offset; offset = next; - update_pages(offset, cols - 30 - 1); + next = next_page(offset, winsize.ws_col - 30 - 1); } + fputs(offset > 0 ? "< " : " ", stderr); + for (int i = offset; i < next && i < matchc; i++) print_string(matchv[i], i == current); - if (next < matchc) - fprintf(stderr, "\033[%dC>", cols); + fprintf(stderr, "\033[%dC>", winsize.ws_col - 30); } -void -print_prompt(int cols) +static void +print_prompt(void) { - int limit = opt_lines ? cols : 30; + int limit = opt_lines ? winsize.ws_col : 30 - 2; fputc('\r', stderr); - for (int i = 0; i < limit - 2; i++) + for (int i = 0; i < limit; i++) fputc(' ', stderr); - fputs(offset > 0 ? "< " : " ", stderr); - fprintf(stderr, "\r%s %s", opt_prompt, input); } -void +static void print_screen(int tty_fd) { - struct winsize w; int count; - if (ioctl(tty_fd, TIOCGWINSZ, &w) < 0) - die("could not get terminal size"); + if (ioctl(tty_fd, TIOCGWINSZ, &winsize) < 0) + die("ioctl"); - count = MIN(opt_lines, w.ws_row - 2); + count = MIN(opt_lines, winsize.ws_row - 2); fputs("\r\033[K", stderr); if (opt_lines) { - print_lines(count, w.ws_col); + print_lines(count); fprintf(stderr, "\033[%dA", count + 1); + } else { fputs("\033[30C", stderr); - print_columns(w.ws_col); + print_columns(); } - print_prompt(w.ws_col); + print_prompt(); } -void +static void print_clear(int lines) { for (int i = 0; i < lines + 1; i++) @@ -254,7 +228,40 @@ print_clear(int lines) } -void +static void +filter_lines(void) +{ + char **tokv = NULL, *s, buffer[sizeof (input)]; + int tokc = 0, n = 0; + + current = offset = prev = next = 0; + + strcpy(buffer, input); + + for (s = strtok(buffer, " "); s; s = strtok(NULL, " "), tokc++) { + + if (tokc >= n) { + tokv = realloc(tokv, ++n * sizeof (*tokv)); + + if (tokv == NULL) + die("realloc"); + } + + tokv[tokc] = s; + } + + matchc = 0; + for (int i = 0; i < linec; i++) + if (match_line(linev[i], tokv, tokc)) + matchv[matchc++] = linev[i]; + + free(tokv); + + next = next_page(0, winsize.ws_col - 30 - 1); +} + + +static void remove_word_input() { int len = strlen(input) - 1; @@ -270,7 +277,7 @@ remove_word_input() } -void +static void add_character(char key) { int len = strlen(input); @@ -287,7 +294,7 @@ add_character(char key) /* * Send the selection to stdout. */ -void +static void print_selection(void) { fputs("\r\033[K", stderr); @@ -303,7 +310,7 @@ print_selection(void) /* * Perform action associated with key */ -int +static int input_key(FILE *tty_fp) { char key = fgetc(tty_fp); @@ -359,20 +366,20 @@ input_key(FILE *tty_fp) /* * Listen for the user input and call the appropriate functions. */ -int +static int input_get(int tty_fd) { FILE *tty_fp = fopen("/dev/tty", "r"); int exit_code; - struct termios termio_old = set_terminal(tty_fd); input[0] = '\0'; + set_terminal(tty_fd); + while ((exit_code = input_key(tty_fp)) == CONTINUE) print_screen(tty_fd); - /* resets the terminal to the previous state. */ - tcsetattr(tty_fd, TCSANOW, &termio_old); + set_terminal(tty_fd); fclose(tty_fp); @@ -380,7 +387,7 @@ input_get(int tty_fd) } -void +static void usage(void) { fputs("usage: iomenu [-l lines] [-p prompt]\n", stderr);