diff options
author | Phil Jones <philj56@gmail.com> | 2022-08-03 12:48:00 +0100 |
---|---|---|
committer | Phil Jones <philj56@gmail.com> | 2022-08-03 12:48:00 +0100 |
commit | 04731d5dd4172c94d7d33fb5fdc5dd2a74cfe754 (patch) | |
tree | 1ab8464e8e126156306ac0ff734737a261b38ae5 | |
parent | 02497d8e31876e6269f8686c44ec4f23a09cf5eb (diff) |
Add pagination of results.
-rw-r--r-- | src/entry.h | 1 | ||||
-rw-r--r-- | src/entry_backend/harfbuzz.c | 19 | ||||
-rw-r--r-- | src/entry_backend/pango.c | 11 | ||||
-rw-r--r-- | src/main.c | 82 |
4 files changed, 86 insertions, 27 deletions
diff --git a/src/entry.h b/src/entry.h index 562c085..5ee4cd6 100644 --- a/src/entry.h +++ b/src/entry.h @@ -34,6 +34,7 @@ struct entry { uint32_t input_mb_length; uint32_t selection; + uint32_t page; struct string_vec results; struct string_vec commands; struct desktop_vec apps; diff --git a/src/entry_backend/harfbuzz.c b/src/entry_backend/harfbuzz.c index e3217a7..45d5961 100644 --- a/src/entry_backend/harfbuzz.c +++ b/src/entry_backend/harfbuzz.c @@ -242,11 +242,22 @@ void entry_backend_harfbuzz_update(struct entry *entry) break; } + + size_t index = i + entry->num_results * entry->page; + /* + * We may be on the last page, which could have fewer results + * than expected, so check and break if necessary. + */ + if (index >= entry->results.count) { + break; + } + + const char *result = entry->results.buf[index].string; /* If this isn't the selected result, just print as normal. */ if (i != entry->selection) { hb_buffer_clear_contents(buffer); setup_hb_buffer(buffer); - hb_buffer_add_utf8(buffer, entry->results.buf[i].string, -1, 0, -1); + hb_buffer_add_utf8(buffer, result, -1, 0, -1); hb_shape(entry->harfbuzz.hb_font, buffer, NULL, 0); width = render_hb_buffer(cr, buffer); } else { @@ -268,15 +279,15 @@ void entry_backend_harfbuzz_update(struct entry *entry) * postmatch chunks, and drawing each separately. */ size_t prematch_len; - char *prematch = xstrdup(entry->results.buf[i].string); + char *prematch = xstrdup(result); char *match = NULL; char *postmatch = NULL; uint32_t subwidth; if (entry->input_mb_length > 0 && entry->selection_highlight_color.a != 0) { char *match_pos = strcasestr(prematch, entry->input_mb); if (match_pos != NULL) { - match = xstrdup(entry->results.buf[i].string); - postmatch = xstrdup(entry->results.buf[i].string); + match = xstrdup(result); + postmatch = xstrdup(result); prematch_len = (match_pos - prematch); prematch[prematch_len] = '\0'; match[entry->input_mb_length + prematch_len] = '\0'; diff --git a/src/entry_backend/pango.c b/src/entry_backend/pango.c index c182e4c..41d8301 100644 --- a/src/entry_backend/pango.c +++ b/src/entry_backend/pango.c @@ -90,9 +90,18 @@ void entry_backend_pango_update(struct entry *entry) } else if (i >= entry->num_results) { break; } + size_t index = i + entry->num_results * entry->page; + /* + * We may be on the last page, which could have fewer results + * than expected, so check and break if necessary. + */ + if (index >= entry->results.count) { + break; + } + const char *str; if (i < entry->results.count) { - str = entry->results.buf[i].string; + str = entry->results.buf[index].string; } else { str = ""; } @@ -158,7 +158,7 @@ static void handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) sizeof(buf)); wchar_t ch; mbtowc(&ch, buf, sizeof(buf)); - if (len > 0 && iswprint(ch) && (tofi->window.entry.drun || !iswblank(ch))) { + if (len > 0 && iswprint(ch) && (entry->drun || !iswblank(ch))) { if (entry->input_length < N_ELEM(entry->input) - 1) { entry->input[entry->input_length] = ch; entry->input_length++; @@ -167,7 +167,7 @@ static void handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) buf, N_ELEM(buf)); entry->input_mb_length += len; - if (tofi->window.entry.drun) { + if (entry->drun) { struct string_vec results = desktop_vec_filter(&entry->apps, entry->input_mb); string_vec_destroy(&entry->results); entry->results = results; @@ -188,7 +188,7 @@ static void handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) NULL); entry->input_mb_length = siz; string_vec_destroy(&entry->results); - if (tofi->window.entry.drun) { + if (entry->drun) { entry->results = desktop_vec_filter(&entry->apps, entry->input_mb); } else { entry->results = string_vec_filter(&entry->commands, entry->input_mb); @@ -209,11 +209,27 @@ static void handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) return; } - uint32_t num_results = tofi->window.entry.num_results; - if (num_results == 0) { - num_results = tofi->window.entry.num_results_drawn; + /* + * If 0 was passed to num-results, use the number we've managed to fit + * in the window from now on. + */ + if (entry->num_results == 0) { + entry->num_results = entry->num_results_drawn; + } + /* Number of pages of results available. */ + uint32_t n_pages = ceil(entry->results.count / (double)entry->num_results); + uint32_t page_size; + + /* There may be fewer than num-results entries on the last page. */ + if (entry->page == n_pages - 1) { + page_size = entry->results.count % entry->num_results; + if (page_size == 0) { + page_size = entry->num_results; + } + } else { + page_size = entry->num_results; } - uint32_t nsel = MAX(MIN(num_results, tofi->window.entry.results.count), 1); + uint32_t nsel = MAX(MIN(page_size, entry->results.count), 1); if (sym == XKB_KEY_Up || sym == XKB_KEY_Left || (sym == XKB_KEY_k && xkb_state_mod_name_is_active( @@ -222,9 +238,26 @@ static void handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) XKB_STATE_MODS_EFFECTIVE) ) ) { - tofi->window.entry.selection += nsel; - tofi->window.entry.selection--; - tofi->window.entry.selection %= nsel; + if (entry->selection > 0) { + entry->selection--; + } else { + if (entry->page > 0) { + entry->page--; + entry->selection = entry->num_results - 1; + } else { + /* + * We're about to wrap around to the last + * result, so we need to calculate the size of + * the last page. + */ + entry->page = n_pages - 1; + page_size = entry->results.count % entry->num_results; + if (page_size == 0) { + page_size = entry->num_results; + } + entry->selection = page_size - 1; + } + } } else if (sym == XKB_KEY_Down || sym == XKB_KEY_Right || sym == XKB_KEY_Tab || (sym == XKB_KEY_j && xkb_state_mod_name_is_active( @@ -233,10 +266,15 @@ static void handle_keypress(struct tofi *tofi, xkb_keycode_t keycode) XKB_STATE_MODS_EFFECTIVE) ) ) { - tofi->window.entry.selection++; - tofi->window.entry.selection %= nsel; + entry->selection++; + if (entry->selection >= nsel) { + entry->selection -= nsel; + entry->page++; + entry->page %= n_pages; + } } else { - tofi->window.entry.selection = 0; + entry->selection = 0; + entry->page = 0; } entry_update(&tofi->window.entry); tofi->window.surface.redraw = true; @@ -897,16 +935,17 @@ static void parse_args(struct tofi *tofi, int argc, char *argv[]) static void do_submit(struct tofi *tofi) { - uint32_t selection = tofi->window.entry.selection; - char *res = tofi->window.entry.results.buf[selection].string; - if (tofi->window.entry.drun) { + struct entry *entry = &tofi->window.entry; + uint32_t selection = entry->selection + entry->num_results * entry->page; + char *res = entry->results.buf[selection].string; + if (entry->drun) { /* * TODO: This is ugly. The list of apps needs to be sorted * alphabetically for bsearch to find the selected entry, but * we previously sorted by history count. This needs fixing. */ - desktop_vec_sort(&tofi->window.entry.apps); - struct desktop_entry *app = desktop_vec_find(&tofi->window.entry.apps, res); + desktop_vec_sort(&entry->apps); + struct desktop_entry *app = desktop_vec_find(&entry->apps, res); if (app == NULL) { log_error("Couldn't find application file! This shouldn't happen.\n"); return; @@ -931,10 +970,9 @@ static void do_submit(struct tofi *tofi) } if (tofi->use_history) { history_add( - &tofi->window.entry.history, - tofi->window.entry.results.buf[selection].string); - history_save(&tofi->window.entry.history, - tofi->window.entry.drun); + &entry->history, + entry->results.buf[selection].string); + history_save(&entry->history, entry->drun); } } |