Skip to content

Commit

Permalink
Ensure correctness while typing a query fast
Browse files Browse the repository at this point in the history
Typing a query fast enough to trigger the poll check in filter_choices()
could yield a wrong set of choices. Since filter_choices() is
interrupted, all choices have yet not been examined and potential
matches could still be left unexamined. Calling print_choices() in this
state causes the unexamined choices to never be reconsidered as
potential matches since they will have a score = 0. The solution is to
never call print_choices() if filter_choices() was interrupted.

Problem reported and partial solution provided by Jenz Guenther in
GitHub issue #268.
  • Loading branch information
mptre committed Dec 30, 2017
1 parent f553d4a commit fa4d551
Showing 1 changed file with 17 additions and 17 deletions.
34 changes: 17 additions & 17 deletions pick.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ struct choice {
static int choicecmp(const void *, const void *);
static void delete_between(char *, size_t, size_t, size_t);
static char *eager_strpbrk(const char *, const char *);
static void filter_choices(size_t);
static int filter_choices(size_t, int);
static char *get_choices(void);
static enum key get_key(const char **);
static void handle_sigwinch(int);
Expand Down Expand Up @@ -325,8 +325,11 @@ selected_choice(void)
choices_count = choices.length;
query_grew = 0;
if (dofilter) {
filter_choices(choices_count);
dofilter = selection = yscroll = 0;
dofilter = 0;
if (filter_choices(choices_count, query_length > 0))
selection = yscroll = 0;
else
dochoices = 0;
}

tty_putp(cursor_invisible, 0);
Expand Down Expand Up @@ -530,12 +533,14 @@ selected_choice(void)
}

/*
* Filter choices using the current query while there is no new user input
* available.
* The first nchoices number of choices will be filtered.
* Filter the first nchoices number of choices using the current query.
* If intr is non-zero, regularly check for new user input and abort the
* filtering. This improves the performance when the cardinality of the choices
* is large.
* Returns non-zero if the filtering was not aborted.
*/
void
filter_choices(size_t nchoices)
int
filter_choices(size_t nchoices, int intr)
{
struct choice *c;
struct pollfd pfd;
Expand All @@ -555,23 +560,18 @@ filter_choices(size_t nchoices)
c->score = (double)query_length/match_length/c->length;
}

/*
* Regularly check if there is any new user input available. If
* true, abort filtering since the currently used query is
* outdated. This improves the performance when the cardinality
* of the choices is large.
*/
if (i > 0 && i % 50 == 0) {
if (intr && i > 0 && i % 50 == 0) {
pfd.fd = fileno(tty_in);
pfd.events = POLLIN;
if ((nready = poll(&pfd, 1, 0)) == -1)
err(1, "poll");
if (nready == 1 && pfd.revents & (POLLIN | POLLHUP))
break;
return 0;
}
}

qsort(choices.v, nchoices, sizeof(struct choice), choicecmp);

return 1;
}

int
Expand Down

0 comments on commit fa4d551

Please sign in to comment.