iomenu.c: horizontal mode with -l 0 - 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 695c25f7dc0613e9aa3e9057b333ec22c0e580f9 DIR parent 5ac10691e817e4bfb903449a99614a1184d03a7e HTML Author: Josuah Demangeon <josuah.demangeon@gandi.net> Date: Sun, 3 Sep 2017 20:09:12 +0200 iomenu.c: horizontal mode with -l 0 Diffstat: M iomenu.c | 215 +++++++++++++++++++------------ 1 file changed, 135 insertions(+), 80 deletions(-) --- DIR diff --git a/iomenu.c b/iomenu.c @@ -14,6 +14,7 @@ #include "utf8.h" #define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */ +#define MARGIN 30 /* space for the input before the horizontal list */ #define CTL(char) (char ^ 0x40) #define ALT(char) (char + 0x80) @@ -53,6 +54,34 @@ die(const char *s) } static void +read_lines(void) +{ + int size = 0; + size_t len; + + do { + if (linec >= size) { + size += BUFSIZ; + linev = realloc(linev, sizeof (char **) * size); + matchv = realloc(matchv, sizeof (char **) * size); + if (!linev || !matchv) + die("realloc"); + } + + linev[linec] = malloc(LINE_MAX + 1); + if (!(fgets(linev[linec], LINE_MAX, stdin))) { + free(linev[linec]); + break; + } + + len = strlen(linev[linec]); + if (len > 0 && linec[linev][len - 1] == '\n') + linev[linec][len - 1] = '\0'; + + } while (++linec, ++matchc); +} + +static void set_terminal(void) { struct termios new; @@ -83,48 +112,73 @@ reset_terminal(void) /* reset cursor position */ fputs("\033[u", stderr); - /* set terminal back to normal mode */ tcsetattr(ttyfd, TCSANOW, &termios); } -static void -read_lines(void) +static size_t +str_width(char *s) { - int size = 0; - size_t len; + int width = 0; - do { - if (linec >= size) { - size += BUFSIZ; - linev = realloc(linev, sizeof (char **) * size); - matchv = realloc(matchv, sizeof (char **) * size); - if (!linev || !matchv) - die("realloc"); - } + while (*s) { + if (*s++ == '\t') + width += (width + 7) % 8; + else + width++; + } - linev[linec] = malloc(LINE_MAX + 1); - if (!(fgets(linev[linec], LINE_MAX, stdin))) { - free(linev[linec]); - break; - } + return width; +} - len = strlen(linev[linec]); - if (len > 0 && linec[linev][len - 1] == '\n') - linev[linec][len - 1] = '\0'; +static int +prev_page(int pos, int cols) +{ + int col; - } while (++linec, ++matchc); + pos -= pos > 0 ? 1 : 0; + for (col = 0; pos > 0; pos--) + if ((col += str_width(matchv[pos]) + 2) > cols) + return pos + 1; + return pos; } -static size_t -string_width(char *s) +static int +next_page(int pos, int cols) { - int width = 0; + int col; - while (*s) - if (*s++ == '\t') - width += (width + 7) % 8; + for (col = 0; pos < matchc; pos++) + if ((col += str_width(matchv[pos]) + 2) > cols) + return pos; + return pos; +} - return width; +static void +move(signed int sign) +{ + int i; + + for (i = current + sign; 0 <= i && i < matchc; i += sign) { + if (!opt['#'] || matchv[i][0] != '#') { + current = i; + break; + } + } +} + +static void +move_page(signed int sign) +{ + int i = current - current % rows + rows * sign; + + if (!opt['l']) + return; + + if (0 > i || i > matchc) + return; + + current = i - 1; + move(+1); } static char * @@ -149,10 +203,10 @@ format(char *str, int cols) *fmt++ = *str++; col++; - } else { - *fmt++ = '?'; - col++; - str++; + } else { + *fmt++ = '?'; + col++; + str++; } } *fmt = '\0'; @@ -165,22 +219,51 @@ print_lines(void) { int printed = 0, i = current - current % rows; - while (printed < rows && i < matchc) { + for (; printed < rows && i < matchc; i++, printed++) { + fprintf(stderr, + opt['#'] && matchv[i][0] == '#' ? + "\n\033[1m\033[K %s\033[m" : + i == current ? + "\n\033[47;30m\033[K %s\033[m" : + "\n\033[K %s", + format(matchv[i], ws.ws_col - 1) + ); + } + + while (printed++ < rows) + fputs("\n\033[K", stderr); +} - char *s = format(matchv[i], ws.ws_col - 1); +static void +print_segments(void) +{ + int i; - if (opt['#'] && matchv[i][0] == '#') - fprintf(stderr, "\n\033[1m\033[K %s\033[m", s); - else if (i == current) - fprintf(stderr, "\n\033[30;47m\033[K %s\033[m", s); - else - fprintf(stderr, "\n\033[K %s", s); + if (current < offset) { + next = offset; + offset = prev_page(offset, ws.ws_col - MARGIN - 4); - i++; printed++; + } else if (current >= next) { + offset = next; + next = next_page(offset, ws.ws_col - MARGIN - 4); } - while (printed++ < rows) - fputs("\n\033[K", stderr); + fprintf(stderr, "\r\033[K\033[%dC", MARGIN); + fputs(offset > 0 ? "< " : " ", stderr); + + for (i = offset; i < next && i < matchc; i++) { + fprintf(stderr, + opt['#'] && matchv[i][0] == '#' ? "\033[1m %s \033[m" : + i == current ? "\033[7m %s \033[m" : + " %s ", + format(matchv[i], ws.ws_col - 1) + ); + } + + if (next < matchc) + fprintf(stderr, "\033[%dC\b>", ws.ws_col - MARGIN); + + fputc('\r', stderr); } static void @@ -188,10 +271,12 @@ print_screen(void) { int cols = ws.ws_col - 1; - fputs("\r\033[K", stderr); - - print_lines(); - fprintf(stderr, "\033[%dA\r", rows); + if (opt['l'] > 0) { + print_lines(); + fprintf(stderr, "\033[%dA\r", rows); + } else { + print_segments(); + } if (*prompt) { format(prompt, cols - 2); @@ -219,34 +304,6 @@ match_line(char *line, char **tokv, int tokc) } static void -move(signed int sign) -{ - int i; - - for (i = current + sign; 0 <= i && i < matchc; i += sign) { - if (!opt['#'] || matchv[i][0] != '#') { - current = i; - break; - } - } -} - -static void -move_page(signed int sign) -{ - int i = current - current % rows + rows * sign; - - if (!opt['l']) - return; - - if (0 > i || i > matchc) - return; - - current = i - 1; - move(+1); -} - -static void filter(void) { char **tokv = NULL, *s, buffer[sizeof (input)]; @@ -333,10 +390,8 @@ print_selection(void) } static int -key(void) +key(int key) { - int key = fgetc(stdin); - top: switch (key) { @@ -485,7 +540,7 @@ main(int argc, char *argv[]) sigwinch(); input[0] = '\0'; - while ((exit_code = key()) == CONTINUE) + while ((exit_code = key(fgetc(stdin))) == CONTINUE) print_screen(); print_screen();