added -s option - 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 173b8e981c29a274af7398f08c76b9e07562e6de DIR parent f85d89ea704e25328a41b5c4ba3d115d1c997131 HTML Author: Josuah Demangeon <mail@josuah.net> Date: Tue, 11 Apr 2017 23:51:22 +0200 added -s option Diffstat: M iomenu.1 | 47 +++++++++++++++++++++++++++++-- M iomenu.c | 65 +++++++++++++++++++++++++------ 2 files changed, 99 insertions(+), 13 deletions(-) --- DIR diff --git a/iomenu.1 b/iomenu.1 @@ -2,24 +2,33 @@ .Dt IOMENU 1 .Os . +. .Sh NAME . +. .Nm iomenu .Nd interactive selection menu . +. .Sh SYNOPSIS . +. .Nm .Op Fl l Ar lines .Op Fl p Ar prompt .Op Fl b +.Op Fl s .Op Fl t . +. .Sh DESCRIPTION . +. .Nm is an interactive filtering and selection tool for the terminal. +. .Pp +. It reads lines from standard input, and prompt for a selection. The selected line(s) is(are) printed to standard output. .Bl -tag -width XXXXXXXXXXXXXXXX @@ -39,8 +48,16 @@ lines. Set the prompt to display at the beginning of the input to .Ar prompt . . +.It Fl t +If a line starts with +.Li # , +.Nm +will interprete it as a header, which always matches, and can not be +printed. +. .It Fl t / Fl b -Print the menu at the top / bottom rather than at current cursor position. +Print the menu at the top / bottom rather than at current cursor +position. Reset the cursor postition afterward. .El . @@ -82,56 +99,82 @@ Remove the whole input string. Fill the input with current selection. .El . +. .Sh EXIT STATUS . +. .Ex -std . +. .Sh EXAMPLES . +. Open a bookmark from a list in a text file: +. .Bd -literal -offset XX iomenu < bookmarks-urls.txt | xargs firefox .Ed +. .Pp +. Go to a subdirectory: +. .Bd -literal -offset XX cd "$(find . -type d | iomenu)" .Ed +. .Pp +. Edit a file located in .Ev HOME : +. .Bd -literal -offset XX EDITOR "$(find "$HOME" -type f | iomenu -l 255)" .Ed +. .Pp +. Play an audio file: +. .Bd -literal -offset XX mplayer "$(find ~/Music | iomenu)" .Ed +. .Pp +. Select a background job to attach to: +. .Bd -literal -offset XX fg "%$(jobs | iomenu | cut -c 2)" .Ed +. .Pp +. Filter "ps" output and print a process ID +. .Bd -literal -offset XX -ps ax | tail -n +2 | iomenu -l 255 | sed -r 's/ *([0-9]*).*/\1/' +{ printf '# '; ps ax; } | iomenu -l 255 -s | sed -r 's/ *([0-9]*).*/\1/' .Ed . +. .Sh SEE ALSO . +. .Xr dmenu 1 , .Xr slmenu 1 , .Xr vis-menu 1 . +. .Sh BUGS . +. .Nm currently only support ASCII characters. . +. .Sh AUTORS . +. .Nm was written from scratch by .An Josuah Demangeon Aq Mt mail@josuah.net DIR diff --git a/iomenu.c b/iomenu.c @@ -17,7 +17,6 @@ #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) - static struct winsize ws; static struct termios termios; int tty_fd; @@ -27,7 +26,7 @@ static int linec = 0, matchc = 0; static char **linev = NULL, **matchv = NULL; static char input[BUFSIZ], formatted[BUFSIZ * 8]; static int opt_l = 0, opt_tb = 0; -static char *opt_p = ""; +static char *opt_p = "", opt_s = '\0'; static void @@ -130,7 +129,7 @@ read_lines(void) die("realloc"); } - linev[linec] = matchv[matchc] = malloc(len); + linev[linec] = matchv[matchc] = malloc(len + 1); if (linev[linec] == NULL) die("malloc"); @@ -165,8 +164,12 @@ format(char *str, int cols) if (str[i] == '\t') { for (int t = (j + 7) % 8 + 1; t > 0 && j < cols; t--) formatted[j++] = ' '; - } else { + + } else if (isprint(str[i])) { formatted[j++] = str[i]; + + } else { + formatted[j++] = '?'; } } @@ -177,10 +180,17 @@ format(char *str, int cols) static void -print_string(char *str, int current) +print_string(char *str, int iscurrent) { - fputs(current ? "\033[30;47m" : "", stderr); + extern int opt_l; + extern char opt_s; + + fputs(iscurrent ? "\033[30;47m" : "", stderr); fputs(opt_l ? "\033[K " : " ", stderr); + + if (opt_s && str[0] == '#') + fputs("\033[1;30m", stderr); + fputs(format(str, ws.ws_col - 2), stderr); fputs(" \033[m", stderr); } @@ -289,6 +299,9 @@ print_screen(void) static int match_line(char *line, char **tokv, int tokc) { + if (opt_s && line[0] == opt_s) + return 2; + for (int i = 0; i < tokc; i++) if (strstr(line, tokv[i]) == NULL) return 0; @@ -298,6 +311,21 @@ match_line(char *line, char **tokv, int tokc) static void +move_line(signed int count) +{ + extern int current; + extern char **matchv; + + for (int i = current + count; 0 <= i && i < matchc; i += count) { + if (!opt_s || matchv[i][0] != opt_s) { + current = i; + break; + } + } +} + + +static void filter_lines(void) { char **tokv = NULL, *s, buffer[sizeof (input)]; @@ -325,6 +353,9 @@ filter_lines(void) matchv[matchc++] = linev[i]; free(tokv); + + if (opt_s && matchv[current][0] == opt_s) + move_line(+1); } @@ -361,9 +392,16 @@ add_character(char key) static void print_selection(void) { + extern int current; + extern char **matchv, input[BUFSIZ]; + fputs("\r\033[K", stderr); - fputs(matchc > 0 ? matchv[current] : input, stdout); - fputc('\n', stdout); + + if (matchc == 0 || (opt_s && matchv[current][0] == opt_s)) { + puts(input); + } else { + puts(matchv[current]); + } } @@ -393,11 +431,11 @@ input_key(void) break; case CONTROL('N'): - current += current < matchc - 1 ? 1 : 0; + move_line(+1); break; case CONTROL('P'): - current -= current > 0 ? 1 : 0; + move_line(-1); break; case CONTROL('I'): /* tab */ @@ -446,7 +484,7 @@ input_get(void) static void usage(void) { - fputs("usage: iomenu [-b] [-t] [-l lines] [-p prompt]\n", stderr); + fputs("usage: iomenu [-b] [-t] [-s] [-l lines] [-p prompt]\n", stderr); exit(EXIT_FAILURE); } @@ -478,6 +516,10 @@ main(int argc, char *argv[]) opt_p = argv[i]; break; + case 's': + opt_s = '#'; + break; + default: usage(); } @@ -485,6 +527,7 @@ main(int argc, char *argv[]) setlocale(LC_ALL, ""); read_lines(); + filter_lines(); if (!freopen("/dev/tty", "r", stdin) || !freopen("/dev/tty", "w", stderr))