tmenu

Terminal menu for selecting items from stdin
git clone https://git.sinitax.com/sinitax/tmenu
Log | Files | Refs | README | LICENSE | sfeed.txt

commit 4f7b4022bfe76c4f8d38327cca695a595f00ca11
parent f2fe0c0dc5a4ba4fa80f6798e29c3637e98727eb
Author: Louis Burda <quent.burda@gmail.com>
Date:   Tue, 20 Jun 2023 16:59:13 +0200

Fix PGUP/PGDN seeking

Diffstat:
Mtmenu.c | 78++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
1 file changed, 46 insertions(+), 32 deletions(-)

diff --git a/tmenu.c b/tmenu.c @@ -69,7 +69,7 @@ struct mode { struct searchmode { char c; - ssize_t (*match)(ssize_t, int, bool, size_t, ssize_t); + ssize_t (*match)(ssize_t, int, size_t, ssize_t, bool, bool); }; static void browse_prompt(void); @@ -81,11 +81,11 @@ static bool search_handlekey(int c); static void search_cleanup(void); static ssize_t search_match(ssize_t start, int dir, - bool new, size_t cnt, ssize_t fallback); + size_t cnt, ssize_t fallback, bool new, bool closest); static ssize_t search_match_substr(ssize_t start, int dir, - bool new, size_t cnt, ssize_t fallback); + size_t cnt, ssize_t fallback, bool new, bool closest); static ssize_t search_match_fuzzy(ssize_t start, int dir, - bool new, size_t cnt, ssize_t fallback); + size_t cnt, ssize_t fallback, bool new, bool closest); static const struct searchmode searchmodes[] = { [SEARCH_SUBSTR] = { @@ -388,11 +388,11 @@ search_prompt(void) if (selected < 0) selected = 0; - index = search_match(selected, FWD, 0, 1, -1); + index = search_match(selected, FWD, 1, -1, false, true); if (index != -1) { selected = index; } else { - selected = search_match(selected, BWD, 1, 1, -1); + selected = search_match(selected, BWD, 1, -1, true, true); } if (show_prompt && top_prompt) { @@ -408,12 +408,12 @@ search_prompt(void) if (selected >= 0) { if (i < 0) { index = search_match(selected, - BWD, 1, (size_t) -i, -1); + BWD, (size_t) -i, -1, true, false); } else if (i == 0) { index = selected; } else if (i > 0) { index = search_match(selected, - FWD, 1, (size_t) i, -1); + FWD, (size_t) i, -1, true, false); } } else { index = -1; @@ -468,19 +468,19 @@ search_handlekey(int c) break; case KEY_PGUP: cnt = fwdctx + bwdctx + 1; - selected = search_match(selected, BWD, 1, cnt, selected); + selected = search_match(selected, BWD, cnt, selected, true, true); break; case KEY_PGDN: cnt = fwdctx + bwdctx + 1; - selected = search_match(selected, FWD, 1, cnt, selected); + selected = search_match(selected, FWD, cnt, selected, true, true); break; case KEY_CTRL('K'): case KEY_UP: - selected = search_match(selected, BWD, 1, 1, selected); + selected = search_match(selected, BWD, 1, selected, true, true); break; case KEY_CTRL('L'): case KEY_DOWN: - selected = search_match(selected, FWD, 1, 1, selected); + selected = search_match(selected, FWD, 1, selected, true, true); break; case 0x20 ... 0x7e: if (searchlen < sizeof(searchbuf) - 1) @@ -506,26 +506,40 @@ search_cleanup(void) } static ssize_t -search_match(ssize_t start, int dir, bool new, size_t cnt, ssize_t fallback) +search_match(ssize_t start, int dir, + size_t cnt, ssize_t fallback, bool new, bool closest) { - return searchmodes[searchmode].match(start, dir, new, cnt, fallback); + return searchmodes[searchmode].match(start, dir, + cnt, fallback, new, closest); +} + +static ssize_t +search_match_linear(ssize_t start, int dir, + size_t cnt, ssize_t fallback, bool new, bool closest) +{ + ssize_t index; + + 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; + + return index; } static ssize_t search_match_substr(ssize_t start, int dir, - bool new, size_t cnt, ssize_t fallback) + size_t cnt, ssize_t fallback, bool new, bool closest) { const char *end, *bp; size_t i, found; - ssize_t index; + ssize_t index, prev; - if (!searchlen) { - index = start + dir * (ssize_t) (new + cnt - 1); - if (index < 0 || index >= delims_cnt) - return fallback; - return index; - } + if (!searchlen) + return search_match_linear(start, dir, + cnt, fallback, new, closest); + prev = -1; found = 0; for (i = new; i < delims_cnt; i++) { index = start + dir * (ssize_t) i; @@ -540,29 +554,28 @@ search_match_substr(ssize_t start, int dir, if (search_eq(bp, searchbuf, searchlen)) { if (++found == cnt) return index; + prev = index; break; } } } - return fallback; + return closest ? prev : fallback; } static ssize_t search_match_fuzzy(ssize_t start, int dir, - bool new, size_t cnt, ssize_t fallback) + size_t cnt, ssize_t fallback, bool new, bool closest) { const char *end, *pos, *c; size_t i, found; - ssize_t index; + ssize_t index, prev; - if (!searchlen) { - index = start + dir * (ssize_t) (new + cnt - 1); - if (index < 0 || index >= delims_cnt) - return fallback; - return index; - } + if (!searchlen) + return search_match_linear(start, dir, + cnt, fallback, new, closest); + prev = -1; found = 0; for (i = new; i < delims_cnt; i++) { index = start + dir * (ssize_t) i; @@ -581,10 +594,11 @@ search_match_fuzzy(ssize_t start, int dir, if (c == searchbuf + searchlen) { if (++found == cnt) return index; + prev = index; } } - return fallback; + return closest ? prev : fallback; } static void