diff options
| author | Louis Burda <dev@sinitax.com> | 2025-12-05 00:00:44 +0100 |
|---|---|---|
| committer | Louis Burda <dev@sinitax.com> | 2025-12-05 00:00:44 +0100 |
| commit | 7502163644d73c7b2b5e69bd05219b316dc02f11 (patch) | |
| tree | d0eecba7e7e2991e46a1ecd9319bca810596ec8d | |
| parent | e90ed4703ef8453f50c47b5acdc0d1486da17380 (diff) | |
| download | tmenu-7502163644d73c7b2b5e69bd05219b316dc02f11.tar.gz tmenu-7502163644d73c7b2b5e69bd05219b316dc02f11.zip | |
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | tmenu.c | 145 |
2 files changed, 114 insertions, 32 deletions
@@ -2,6 +2,7 @@ PREFIX ?= /usr/local BINDIR ?= /bin CFLAGS = -g -Wunused-variable -Wunused-function -Wconversion +LDLIBS = -lcurses all: tmenu @@ -1,4 +1,8 @@ +#include <ncurses.h> + #include <sys/ioctl.h> +#include <sys/wait.h> + #include <signal.h> #include <unistd.h> #include <termios.h> @@ -51,14 +55,14 @@ enum { }; enum { - KEY_NONE = 0, - KEY_DEL = 0x7f, - KEY_UP = 0x100, - KEY_DOWN, - KEY_LEFT, - KEY_RIGHT, - KEY_PGUP, - KEY_PGDN, + TKEY_NONE = 0, + TKEY_DEL = 0x7f, + TKEY_UP = 0x100, + TKEY_DOWN, + TKEY_LEFT, + TKEY_RIGHT, + TKEY_PGUP, + TKEY_PGDN, }; struct mode { @@ -128,7 +132,6 @@ static size_t entries_cap = 0; static size_t entries_cnt = 0; static ssize_t selected = -1; -static const char *entry = NULL; static size_t entry_off = 0; static char searchbuf[1024]; @@ -147,6 +150,10 @@ static bool verbose = false; static bool show_prompt = true; static bool top_prompt = false; +static const char *run_argv[3] = { NULL }; +static bool run_cmd = false; +static bool run_io = false; + static char delim = '\n'; static char vis_delim = '|'; @@ -238,24 +245,24 @@ readkey(FILE *f) return c; if (fgetc(f) != '[') - return KEY_NONE; + return TKEY_NONE; switch (fgetc(f)) { case 'A': - return KEY_UP; + return TKEY_UP; case 'B': - return KEY_DOWN; + return TKEY_DOWN; case 'C': - return KEY_RIGHT; + return TKEY_RIGHT; case 'D': - return KEY_LEFT; + return TKEY_LEFT; case '5': - return fgetc(f) == '~' ? KEY_PGUP : KEY_NONE; + return fgetc(f) == '~' ? TKEY_PGUP : TKEY_NONE; case '6': - return fgetc(f) == '~' ? KEY_PGDN : KEY_NONE; + return fgetc(f) == '~' ? TKEY_PGDN : TKEY_NONE; } - return KEY_NONE; + return TKEY_NONE; } static int @@ -296,6 +303,7 @@ static void browse_prompt(void) { size_t linew, entlen; + const char *entry; ssize_t i; if (selected < 0) selected = 0; @@ -356,25 +364,25 @@ browse_handlekey(int c) break; case 'q': return true; - case KEY_PGUP: + case TKEY_PGUP: cnt = fwdctx + bwdctx + 1; if (selected > cnt) selected -= (ssize_t) cnt; else selected = 0; break; - case KEY_PGDN: + case TKEY_PGDN: cnt = fwdctx + bwdctx + 1; if (selected < entries_cnt - cnt) selected += (ssize_t) cnt; else selected = (ssize_t) entries_cnt - 1; break; - case KEY_UP: + case TKEY_UP: if (selected != 0) selected--; break; - case KEY_DOWN: + case TKEY_DOWN: if (selected != entries_cnt - 1) selected++; break; @@ -399,6 +407,7 @@ search_prompt(void) { size_t linew, off, entlen; ssize_t i, index; + const char *entry; if (selected < 0) selected = 0; @@ -480,27 +489,27 @@ search_handlekey(int c) case KEY_CTRL('I'): searchcase ^= 1; break; - case KEY_PGUP: + case TKEY_PGUP: cnt = fwdctx + bwdctx + 1; selected = search_match(selected, BWD, cnt, selected, true, true); break; - case KEY_PGDN: + case TKEY_PGDN: cnt = fwdctx + bwdctx + 1; selected = search_match(selected, FWD, cnt, selected, true, true); break; case KEY_CTRL('K'): - case KEY_UP: + case TKEY_UP: selected = search_match(selected, BWD, 1, selected, true, true); break; case KEY_CTRL('L'): - case KEY_DOWN: + case TKEY_DOWN: selected = search_match(selected, FWD, 1, selected, true, true); break; case 0x20 ... 0x7e: if (searchlen < sizeof(searchbuf) - 1) searchbuf[searchlen++] = (char) (c & 0xff); break; - case KEY_DEL: + case TKEY_DEL: if (searchlen) searchlen--; break; } @@ -545,7 +554,7 @@ static ssize_t search_match_substr(ssize_t start, int dir, size_t cnt, ssize_t fallback, bool new, bool closest) { - const char *end, *bp; + const char *end, *bp, *entry; size_t i, found; ssize_t index, prev; @@ -581,7 +590,7 @@ static ssize_t search_match_fuzzy(ssize_t start, int dir, size_t cnt, ssize_t fallback, bool new, bool closest) { - const char *end, *pos, *c; + const char *end, *pos, *c, *entry; size_t i, found; ssize_t index, prev; @@ -666,7 +675,68 @@ load(int fd) } static void -run(void) +invoke(const char **argv, pid_t *pid, int *fd, bool in, bool out, bool err) +{ + int out_pipe[2]; + + if (fd) { + if (*fd >= 0) { + close(*fd); + *fd = -1; + } + if (pipe(out_pipe)) + die("pipe:"); + } + + *pid = fork(); + if (*pid < 0) die("fork:"); + if (!*pid) { + if (!in || !out || !err) { + int zfd = open("/dev/null", O_RDWR); + if (zfd < 0) die("open /dev/null"); + if (!in) dup2(zfd, 0); + if (!out) dup2(zfd, 1); + if (!err) dup2(zfd, 2); + close(zfd); + } + if (fd) { + if (out) dup2(out_pipe[1], 1); + close(out_pipe[0]); + close(out_pipe[1]); + } + execvp(argv[0], (char *const *) argv); + die("execv '%s':", argv[0]); + } else { + if (fd) { + *fd = out_pipe[0]; + close(out_pipe[1]); + } + } +} + +static void +run(char *input) +{ + if (run_io) { + def_prog_mode(); + endwin(); + } + + int status, pid; + run_argv[1] = input; + invoke((const char **)run_argv, &pid, NULL, run_io, run_io, run_io); + do { + int rc = waitpid(pid, &status, 0); + if (rc != pid) die("waitpid:"); + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + + if (run_io) { + reset_prog_mode(); + } +} + +static void +loop(void) { struct termios prevterm, newterm = { 0 }; int c; @@ -716,9 +786,11 @@ run(void) case KEY_CTRL('J'): case '\r': if (selected < 0) break; - entry = full_entry((size_t) selected); modes[mode].cleanup(); - puts(entry); + if (run_cmd) + run(full_entry((size_t) selected)); + else + puts(full_entry((size_t) selected)); if (!multiout) goto exit; break; default: @@ -785,6 +857,15 @@ parseopt(const char *flag, const char **args) if (args[0][0] && args[0][1]) die("bad -d arg"); vis_delim = **args; return 1; + case 'e': + run_argv[0] = *args; + run_cmd = true; + return 1; + case 'E': + run_argv[0] = *args; + run_cmd = true; + run_io = true; + return 1; case 't': top_prompt = true; return 0; @@ -825,5 +906,5 @@ main(int argc, const char **argv) die("freopen tty:"); } - run(); + loop(); } |
