commit f2fe0c0dc5a4ba4fa80f6798e29c3637e98727eb
parent 15c8e7fb77a4e9211618c0b5471d1b3e79da1f07
Author: Louis Burda <quent.burda@gmail.com>
Date: Tue, 20 Jun 2023 16:42:41 +0200
Make prompt smaller and add top_prompt option
Diffstat:
M | tmenu.c | | | 160 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
1 file changed, 97 insertions(+), 63 deletions(-)
diff --git a/tmenu.c b/tmenu.c
@@ -1,4 +1,5 @@
#include <sys/ioctl.h>
+#include <signal.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
@@ -25,6 +26,8 @@
#define CSI_STYLE_BOLD "\x1b[1m"
#define CSI_STYLE_RESET "\x1b[0m"
#define CSI_CLEAR_SCREEN "\x1b[2J"
+#define CSI_STYLE_ULINE "\x1b[4m"
+#define CSI_STYLE_NULINE "\x1b[24m"
#define CSI_CUR_GOTO "\x1b[%i%iH"
enum {
@@ -65,7 +68,7 @@ struct mode {
};
struct searchmode {
- const char *sh;
+ char c;
ssize_t (*match)(ssize_t, int, bool, size_t, ssize_t);
};
@@ -84,16 +87,13 @@ static ssize_t search_match_substr(ssize_t start, int dir,
static ssize_t search_match_fuzzy(ssize_t start, int dir,
bool new, size_t cnt, ssize_t fallback);
-static const char *usage = \
- "Usage: tmenu [-h] [-m] [-a LINES] [-b LINES]";
-
static const struct searchmode searchmodes[] = {
[SEARCH_SUBSTR] = {
- .sh = "SUB",
+ .c = 'S',
.match = search_match_substr,
},
[SEARCH_FUZZY] = {
- .sh = "FUZ",
+ .c = 'F',
.match = search_match_fuzzy,
}
};
@@ -111,6 +111,8 @@ static const struct mode modes[] = {
}
};
+static bool init = false;
+
static char *input = NULL;
static size_t input_len = 0;
static size_t input_cap = 0;
@@ -121,6 +123,8 @@ static size_t delims_cap = 0;
static ssize_t selected = -1;
static const char *entry = NULL;
+static size_t entry_max = 0;
+static size_t entry_off = 0;
static char searchbuf[1024];
static size_t searchlen = 0;
@@ -135,7 +139,8 @@ static size_t termw = 80;
static bool multiout = false;
static bool verbose = false;
-static bool prompt = true;
+static bool show_prompt = true;
+static bool top_prompt = false;
static char delim = '\n';
@@ -158,6 +163,24 @@ die(const char *fmt, ...)
exit(1);
}
+static void
+prompt(void)
+{
+ struct winsize ws = { 0 };
+
+ if (ioctl(2, TIOCGWINSZ, &ws) != -1)
+ termw = ws.ws_col;
+
+ modes[mode].prompt();
+}
+
+static void
+sigwinch(int sig)
+{
+ if (init) prompt();
+ signal(SIGWINCH, sigwinch);
+}
+
static void *
addcap(void *alloc, size_t dsize, size_t min, size_t *cap)
{
@@ -222,21 +245,20 @@ readkey(FILE *f)
}
static int
-search_cmp(const char *a, const char *b, size_t size)
+search_eq(const char *a, const char *b, size_t size)
{
size_t i;
for (i = 0; i < size; i++) {
if (searchcase == CASE_SENSITIVE) {
- if (a[i] != b[i])
- return a[i] - b[i];
+ if (a[i] != b[i]) return false;
} else {
if (lower(a[i]) != lower(b[i]))
- return lower(a[i]) - lower(b[i]);
+ return false;
}
}
- return 0;
+ return true;
}
static const char*
@@ -259,14 +281,13 @@ search_find(const char *a, char c, size_t size)
static void
browse_prompt(void)
{
- static const char promptstr[] = "(browse): ";
size_t linew, entlen;
ssize_t i;
if (selected < 0) selected = 0;
- linew = termw;
- if (prompt) linew -= ARRLEN(promptstr) - 1;
+ if (show_prompt && top_prompt)
+ EPRINTF(CSI_STYLE_BOLD "[B] " CSI_STYLE_RESET "\n");
i = (ssize_t) selected - (ssize_t) bwdctx;
for (; i <= (ssize_t) selected + (ssize_t) fwdctx; i++) {
@@ -275,12 +296,15 @@ browse_prompt(void)
if (i == selected)
EPRINTF(CSI_STYLE_BOLD);
- if (prompt) {
+ if (show_prompt && !top_prompt) {
+ linew = termw - 4;
if (i == selected) {
- EPRINTF("(browse): ");
+ EPRINTF("[B] ");
} else {
- EPRINTF("%*.s", 10, " ");
+ EPRINTF(" ");
}
+ } else {
+ linew = termw;
}
if (selected >= 0 && i >= 0 && i < delims_cnt) {
@@ -300,7 +324,7 @@ browse_prompt(void)
EPRINTF(CSI_STYLE_RESET);
}
- for (i = 0; i < bwdctx + fwdctx + 1; i++)
+ for (i = 0; i < bwdctx + fwdctx + 1 + show_prompt * top_prompt; i++)
EPRINTF(CSI_CUR_UP);
}
@@ -359,10 +383,8 @@ browse_cleanup(void)
static void
search_prompt(void)
{
- char promptbuf[256];
+ size_t linew, off, entlen;
ssize_t i, index;
- ssize_t len, entlen;
- size_t linew;
if (selected < 0) selected = 0;
@@ -373,15 +395,16 @@ search_prompt(void)
selected = search_match(selected, BWD, 1, 1, -1);
}
- len = snprintf(promptbuf, sizeof(promptbuf), "(search[%c:%s]) %.*s",
- (searchcase == CASE_SENSITIVE) ? 'I' : 'i',
- searchmodes[searchmode].sh, (int) searchlen, searchbuf);
- if (len < 0) die("snprintf:");
-
- linew = termw;
- if (prompt) linew -= (size_t) len + 3;
+ if (show_prompt && top_prompt) {
+ EPRINTF(CSI_STYLE_BOLD "[%c] " CSI_STYLE_ULINE "%.*s"
+ CSI_STYLE_NULINE "%.*s\n" CSI_STYLE_RESET,
+ (searchcase == CASE_SENSITIVE ?
+ searchmodes[searchmode].c
+ : lower(searchmodes[searchmode].c)),
+ (int) searchlen, searchbuf, (int) termw, " ");
+ }
- for (i = -(ssize_t) bwdctx; i <= fwdctx; i++) {
+ for (i = -(ssize_t) bwdctx; i <= (ssize_t) fwdctx; i++) {
if (selected >= 0) {
if (i < 0) {
index = search_match(selected,
@@ -400,31 +423,37 @@ search_prompt(void)
if (i == 0) EPRINTF(CSI_STYLE_BOLD);
- if (prompt) {
+ if (show_prompt && !top_prompt) {
if (i == 0) {
- EPRINTF("%s : ", promptbuf);
+ EPRINTF("[%c] " CSI_STYLE_ULINE "%.*s"
+ CSI_STYLE_NULINE " ",
+ (searchcase == CASE_SENSITIVE ?
+ searchmodes[searchmode].c
+ : lower(searchmodes[searchmode].c)),
+ (int) searchlen, searchbuf);
} else {
- EPRINTF("%*.s", (int) (len + 3), " ");
+ EPRINTF("%*.s", (int) (4 + searchlen + 1), " ");
}
+ linew = (size_t) MAX(0, (ssize_t) termw
+ - (ssize_t) searchlen - 5);
+ } else {
+ linew = termw;
}
if (index < 0) {
EPRINTF("\n");
} else {
- entlen = (ssize_t) entry_len((size_t) index);
+ entlen = entry_len((size_t) index);
entry = get_entry((size_t) index);
- if (entlen > linew) {
- EPRINTF(" ..%.*s\n", (int) (linew - 3), entry
- + MAX(0, (size_t) entlen - (linew - 3)));
- } else {
- EPRINTF("%.*s\n", (int) linew, entry);
- }
+ off = entlen >= linew ? entlen - linew : 0;
+ off = MIN(entry_off, off);
+ EPRINTF("%.*s\n", (int) linew, entry + off);
}
if (i == 0) EPRINTF(CSI_STYLE_RESET);
}
- for (i = 0; i < bwdctx + fwdctx + 1; i++)
+ for (i = 0; i < bwdctx + fwdctx + 1 + show_prompt * top_prompt; i++)
EPRINTF(CSI_CUR_UP);
}
@@ -487,7 +516,7 @@ search_match_substr(ssize_t start, int dir,
bool new, size_t cnt, ssize_t fallback)
{
const char *end, *bp;
- size_t i, found, len;
+ size_t i, found;
ssize_t index;
if (!searchlen) {
@@ -507,8 +536,8 @@ search_match_substr(ssize_t start, int dir,
end = entry + entry_len((size_t) index);
for (bp = entry; *bp; bp++) {
- len = MIN(searchlen, (size_t) (end - bp));
- if (!search_cmp(bp, searchbuf, len)) {
+ if (searchlen > end - bp) continue;
+ if (search_eq(bp, searchbuf, searchlen)) {
if (++found == cnt)
return index;
break;
@@ -572,12 +601,12 @@ load(int fd)
c = input + input_len;
for (i = 0; i < (size_t) nread; i++, c++) {
- if (*c == delim) {
- *c = '\0';
- delims = addcap(delims, sizeof(size_t),
- delims_cnt + 1, &delims_cap);
- delims[delims_cnt++] = input_len + i;
- }
+ if (*c != delim) continue;
+ *c = '\0';
+ delims = addcap(delims, sizeof(size_t),
+ delims_cnt + 1, &delims_cap);
+ delims[delims_cnt++] = input_len + i;
+ entry_max = MAX(entry_max, entry_len(delims_cnt-1));
}
input_len += (size_t) nread;
@@ -588,6 +617,7 @@ load(int fd)
delims = addcap(delims, sizeof(size_t),
delims_cnt + 1, &delims_cap);
delims[delims_cnt++] = input_len;
+ entry_max = MAX(entry_max, entry_len(delims_cnt-1));
}
if (verbose)
@@ -598,7 +628,6 @@ static void
run(void)
{
struct termios prevterm, newterm = { 0 };
- struct winsize ws = { 0 };
int c;
if (!delims_cnt) return;
@@ -613,13 +642,11 @@ run(void)
EPRINTF(CSI_CUR_HIDE);
+ init = true;
selected = 0;
searchlen = 0;
do {
- if (ioctl(2, TIOCGWINSZ, &ws) != -1)
- termw = ws.ws_col;
-
- modes[mode].prompt();
+ prompt();
switch ((c = readkey(stdin))) {
case KEY_CTRL('C'):
@@ -688,35 +715,41 @@ parseopt(const char *flag, const char **args)
case 's':
mode = MODE_SEARCH;
searchmode = SEARCH_SUBSTR;
- prompt = false;
+ return 0;
+ case 'n':
+ show_prompt = false;
return 0;
case 'a':
if (!*args) die("missing -a arg");
fwdctx = strtoull(*args, &end, 10);
- if (end && *end) goto badint;
+ if (end && *end) die("bad -a arg '%s'", *args);
return 1;
case 'b':
if (!*args) die("missing -b arg");
bwdctx = strtoull(*args, &end, 10);
- if (end && *end) goto badint;
+ if (end && *end) die("bad -b arg '%s'", *args);
+ return 1;
+ case 'c':
+ if (!*args) die("missing -c arg");
+ fwdctx = bwdctx = strtoull(*args, &end, 10);
+ if (end && *end) die("bad -c arg '%s'", *args);
return 1;
case 'd':
if (!*args) die("missing -d arg");
if (args[0][0] && args[0][1]) die("bad -d arg");
delim = **args;
return 1;
+ case 't':
+ top_prompt = true;
+ return 0;
case 'h':
- printf("%s\n", usage);
+ printf("Usage: tmenu [-h] [-m] [-a LINES] [-b LINES]");
exit(0);
default:
die("unknown opt '%s'", *flag);
}
return 0;
-
-badint:
- EPRINTF("Invalid int: %s\n", *args);
- exit(1);
}
int
@@ -725,6 +758,7 @@ main(int argc, const char **argv)
const char **arg;
int fd;
+ signal(SIGWINCH, sigwinch);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);