summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Burda <dev@sinitax.com>2025-12-04 01:10:59 +0100
committerLouis Burda <dev@sinitax.com>2025-12-04 01:10:59 +0100
commite90ed4703ef8453f50c47b5acdc0d1486da17380 (patch)
tree4ed69142eaf86de43de174c9ee88d4bb33981806
parent4f7b4022bfe76c4f8d38327cca695a595f00ca11 (diff)
downloadtmenu-e90ed4703ef8453f50c47b5acdc0d1486da17380.tar.gz
tmenu-e90ed4703ef8453f50c47b5acdc0d1486da17380.zip
Add option for visual delim for entries
-rw-r--r--tmenu.c126
1 files changed, 79 insertions, 47 deletions
diff --git a/tmenu.c b/tmenu.c
index 72bed71..d5a0fd6 100644
--- a/tmenu.c
+++ b/tmenu.c
@@ -72,6 +72,11 @@ struct searchmode {
ssize_t (*match)(ssize_t, int, size_t, ssize_t, bool, bool);
};
+struct entry {
+ size_t full;
+ size_t visible;
+};
+
static void browse_prompt(void);
static bool browse_handlekey(int c);
static void browse_cleanup(void);
@@ -117,13 +122,13 @@ static char *input = NULL;
static size_t input_len = 0;
static size_t input_cap = 0;
-static size_t *delims = NULL;
-static size_t delims_cnt = 0;
-static size_t delims_cap = 0;
+static struct entry *entries = NULL;
+static size_t entries_len = 0;
+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_max = 0;
static size_t entry_off = 0;
static char searchbuf[1024];
@@ -143,6 +148,7 @@ static bool show_prompt = true;
static bool top_prompt = false;
static char delim = '\n';
+static char vis_delim = '|';
static void
die(const char *fmt, ...)
@@ -203,15 +209,23 @@ lower(char c)
}
static size_t
-entry_len(size_t index)
+vis_entry_len(size_t index)
+{
+ if (index == entries_cnt-1)
+ return input_len - entries[index].visible;
+ return entries[index+1].visible-1 - entries[index].visible;
+}
+
+static inline char *
+vis_entry(size_t index)
{
- return delims[index] - (index > 0 ? delims[index-1] + 1 : 0);
+ return input + entries[index].visible;
}
static inline char *
-get_entry(size_t index)
+full_entry(size_t index)
{
- return input + (index > 0 ? delims[index-1] + 1 : 0);
+ return input + entries[index].full;
}
static int
@@ -307,9 +321,9 @@ browse_prompt(void)
linew = termw;
}
- if (selected >= 0 && i >= 0 && i < delims_cnt) {
- entry = get_entry((size_t) i);
- entlen = entry_len((size_t) i);
+ if (selected >= 0 && i >= 0 && i < entries_cnt) {
+ entry = vis_entry((size_t) i);
+ entlen = vis_entry_len((size_t) i);
if (entlen > linew) {
EPRINTF(" ..%.*s\n", (int) (linew - 3),
entry + entlen - (linew - 3));
@@ -338,7 +352,7 @@ browse_handlekey(int c)
selected = 0;
break;
case 'G':
- selected = (ssize_t) delims_cnt - 1;
+ selected = (ssize_t) entries_cnt - 1;
break;
case 'q':
return true;
@@ -351,17 +365,17 @@ browse_handlekey(int c)
break;
case KEY_PGDN:
cnt = fwdctx + bwdctx + 1;
- if (selected < delims_cnt - cnt)
+ if (selected < entries_cnt - cnt)
selected += (ssize_t) cnt;
else
- selected = (ssize_t) delims_cnt - 1;
+ selected = (ssize_t) entries_cnt - 1;
break;
case KEY_UP:
if (selected != 0)
selected--;
break;
case KEY_DOWN:
- if (selected != delims_cnt - 1)
+ if (selected != entries_cnt - 1)
selected++;
break;
}
@@ -443,8 +457,8 @@ search_prompt(void)
if (index < 0) {
EPRINTF("\n");
} else {
- entlen = entry_len((size_t) index);
- entry = get_entry((size_t) index);
+ entlen = vis_entry_len((size_t) index);
+ entry = vis_entry((size_t) index);
off = entlen >= linew ? entlen - linew : 0;
off = MIN(entry_off, off);
EPRINTF("%.*s\n", (int) linew, entry + off);
@@ -521,8 +535,8 @@ search_match_linear(ssize_t start, int dir,
index = start + dir * (ssize_t) (new + cnt - 1);
if (index < 0) return closest ? 0 : fallback;
- if (index >= delims_cnt)
- return closest ? (ssize_t) delims_cnt - 1 : fallback;
+ if (index >= entries_cnt)
+ return closest ? (ssize_t) entries_cnt - 1 : fallback;
return index;
}
@@ -541,13 +555,13 @@ search_match_substr(ssize_t start, int dir,
prev = -1;
found = 0;
- for (i = new; i < delims_cnt; i++) {
+ for (i = new; i < entries_cnt; i++) {
index = start + dir * (ssize_t) i;
- if (index < 0 || index >= delims_cnt)
+ if (index < 0 || index >= entries_cnt)
break;
- entry = get_entry((size_t) index);
- end = entry + entry_len((size_t) index);
+ entry = vis_entry((size_t) index);
+ end = entry + vis_entry_len((size_t) index);
for (bp = entry; *bp; bp++) {
if (searchlen > end - bp) continue;
@@ -577,13 +591,13 @@ search_match_fuzzy(ssize_t start, int dir,
prev = -1;
found = 0;
- for (i = new; i < delims_cnt; i++) {
+ for (i = new; i < entries_cnt; i++) {
index = start + dir * (ssize_t) i;
- if (index < 0 || index >= delims_cnt)
+ if (index < 0 || index >= entries_cnt)
break;
- entry = get_entry((size_t) index);
- end = entry + entry_len((size_t) index);
+ entry = vis_entry((size_t) index);
+ end = entry + vis_entry_len((size_t) index);
pos = entry;
for (c = searchbuf; c - searchbuf < searchlen; c++) {
@@ -608,34 +622,47 @@ load(int fd)
size_t i;
char *c;
+ if (!entries_cap)
+ entries = addcap(entries, sizeof(struct entry), 1, &entries_cap);
+
+ if (!entries_len) {
+ entries[0].full = 0;
+ entries[0].visible = 0;
+ entries_len = 1;
+ }
+
while (1) {
- input = addcap(input, 1, input_len + BUFSIZ, &input_cap);
+ input = addcap(input, 1, input_len + BUFSIZ + 1, &input_cap);
nread = read(fd, input + input_len, BUFSIZ);
if (nread <= 0) break;
c = input + input_len;
- for (i = 0; i < (size_t) nread; i++, c++) {
- 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));
+ for (i = input_len; i < input_len + (size_t) nread; i++, c++) {
+ if (*c == vis_delim) {
+ entries[entries_len-1].visible = i + 1;
+ } else if (*c == delim) {
+ *c = '\0';
+ entries = addcap(entries, sizeof(struct entry),
+ entries_len + 1, &entries_cap);
+ entries[entries_len].full = i + 1;
+ entries[entries_len].visible = i + 1;
+ entries_len++;
+ }
}
-
input_len += (size_t) nread;
}
+ input[input_len] = '\0';
- if (!delims_cnt && input_len
- || delims_cnt && delims[delims_cnt-1] != input_len-1) {
- 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));
+ entries_cnt = 0;
+ if (entries_len) {
+ if (input_len <= entries[entries_len-1].full)
+ entries_cnt = entries_len-1;
+ else
+ entries_cnt = entries_len;
}
if (verbose)
- EPRINTF("Loaded %lu entries\n", delims_cnt);
+ EPRINTF("Loaded %lu entries\n", entries_cnt);
}
static void
@@ -644,7 +671,7 @@ run(void)
struct termios prevterm, newterm = { 0 };
int c;
- if (!delims_cnt) return;
+ if (!entries_cnt) return;
if (tcgetattr(0, &prevterm))
die("tcgetattr:");
@@ -689,9 +716,9 @@ run(void)
case KEY_CTRL('J'):
case '\r':
if (selected < 0) break;
- entry = get_entry((size_t) selected);
+ entry = full_entry((size_t) selected);
modes[mode].cleanup();
- printf("%.*s\n", (int) entry_len((size_t) selected), entry);
+ puts(entry);
if (!multiout) goto exit;
break;
default:
@@ -753,11 +780,16 @@ parseopt(const char *flag, const char **args)
if (args[0][0] && args[0][1]) die("bad -d arg");
delim = **args;
return 1;
+ case 'D':
+ if (!*args) die("missing -d arg");
+ if (args[0][0] && args[0][1]) die("bad -d arg");
+ vis_delim = **args;
+ return 1;
case 't':
top_prompt = true;
return 0;
case 'h':
- printf("Usage: tmenu [-h] [-m] [-a LINES] [-b LINES]");
+ printf("Usage: tmenu [-h] [-m] [-d DELIM] [-D DELIM] [-a LINES] [-b LINES]");
exit(0);
default:
die("unknown opt '%s'", *flag);