added a -t / -b option to set the menu at the top / bottom of the screen - 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 0bf49abb280f7bdbc6e13f12a84a844e119061db DIR parent 1035fe68e4071585215a146fd1d31a914534c89d HTML Author: Josuah Demangeonā ā µ <mail@josuah.net> Date: Fri, 31 Mar 2017 19:24:39 +0200 added a -t / -b option to set the menu at the top / bottom of the screen Diffstat: M iomenu.1 | 6 ++++++ M iomenu.c | 61 +++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 19 deletions(-) --- DIR diff --git a/iomenu.1 b/iomenu.1 @@ -11,6 +11,8 @@ . .Nm .Op Fl l Ar lines +.Op Fl b +.Op Fl t . .Sh DESCRIPTION . @@ -31,6 +33,10 @@ the items are displayed in an horizontal list. Otherwise, in a vertical list of at most .Ar lines lines. +. +.It Fl t / Fl b +Print the menu at the top / bottom rather than at current cursor position. +Reset the cursor postition afterward. .El . .Ss Selection control DIR diff --git a/iomenu.c b/iomenu.c @@ -27,7 +27,7 @@ static int current = 0, offset = 0, prev = 0, next = 0; static int linec = 0, matchc = 0; static wchar_t **linev = NULL, **matchv = NULL; static wchar_t input[BUFSIZ], formatted[BUFSIZ * 8]; -static int opt_l = 0; +static int opt_l = 0, opt_tb = 0; static void @@ -59,18 +59,50 @@ set_terminal(void) { struct termios new; + /* get window size */ + if (ioctl(tty_fd, TIOCGWINSZ, &ws) < 0) + die("ioctl"); + + /* save cursor postition */ + fputws(L"\033[s", stderr); + + /* put cursor at the top / bottom */ + switch (opt_tb) { + case 't': fputws(L"\033[H", stderr); break; + case 'b': fwprintf(stderr, L"\033[%dH", ws.ws_row - opt_l); break; + } + + /* save attributes to `termios` */ if (tcgetattr(tty_fd, &termios) < 0 || tcgetattr(tty_fd, &new) < 0) { perror("tcgetattr"); exit(EXIT_FAILURE); } + /* change to raw mode */ new.c_lflag &= ~(ICANON | ECHO | IGNBRK); - tcsetattr(tty_fd, TCSANOW, &new); } static void +reset_terminal(void) +{ + extern struct termios termios; + extern struct winsize ws; + + /* clear terminal */ + for (int i = 0; i < opt_l + 1; i++) + fputws(L"\r\033[K\n", stderr); + + /* reset cursor position */ + fputws(L"\033[u", stderr); + + /* set terminal back to normal mode */ + tcsetattr(tty_fd, TCSANOW, &termios); +} + + +static void read_lines(void) { wchar_t buffer[BUFSIZ]; @@ -215,9 +247,6 @@ print_screen(void) { int count; - if (ioctl(tty_fd, TIOCGWINSZ, &ws) < 0) - die("ioctl"); - count = MIN(opt_l, ws.ws_row - 2); fputws(L"\r\033[K", stderr); @@ -239,15 +268,6 @@ print_screen(void) } -static void -clear(int lines) -{ - for (int i = 0; i < lines + 1; i++) - fputws(L"\r\033[K\n", stderr); - fwprintf(stderr, L"\033[%dA", lines + 1); -} - - static int match_line(wchar_t *line, wchar_t **tokv, int tokc) { @@ -340,7 +360,6 @@ input_key(void) switch (key) { case CONTROL('C'): - clear(opt_l); return EXIT_FAILURE; case CONTROL('U'): @@ -399,6 +418,7 @@ input_get(void) input[0] = '\0'; + print_screen(); while ((exit_code = input_key()) == CONTINUE) print_screen(); @@ -431,6 +451,10 @@ main(int argc, char *argv[]) if (++i >= argc || sscanf(argv[i], "%d", &opt_l) <= 0) usage(); break; + + case 't': opt_tb = 't'; break; + case 'b': opt_tb = 'b'; break; + default: usage(); } @@ -442,15 +466,14 @@ main(int argc, char *argv[]) if (!freopen("/dev/tty", "r", stdin) || !freopen("/dev/tty", "w", stderr)) die("freopen"); tty_fd = open("/dev/tty", O_RDWR); - set_terminal(); - print_screen(); + /* main loop */ exit_code = input_get(); - tcsetattr(tty_fd, TCSANOW, &termios); - clear(opt_l); + reset_terminal(); close(tty_fd); + free_all(); return exit_code;