diff --git a/src/bfu/menu.c b/src/bfu/menu.c index 0f114114..393e6f8d 100644 --- a/src/bfu/menu.c +++ b/src/bfu/menu.c @@ -270,6 +270,11 @@ scroll_menu(struct menu *menu, int steps, int wrap) int pos, start; int s = steps ? steps/abs(steps) : 1; /* Selectable item search direction. */ + /* menu->selected sometimes became -2 and caused infinite loops. + * That should no longer be possible. */ + assert(menu->selected >= -1); + if_assert_failed return; + if (menu->size <= 0) { no_item: /* Menu is empty. */ @@ -280,7 +285,13 @@ no_item: start = pos = menu->selected; - if (!steps) steps = 1, --pos; + if (!steps) { + /* The caller wants us to check that menu->selected is + * actually selectable, and correct it if not. */ + steps = 1; + if (pos >= 0) + --pos; + } while (steps) { pos += s, steps -= s; @@ -610,8 +621,7 @@ menu_mouse_handler(struct menu *menu, struct term_event *ev) if (sel >= 0 && sel < menu->size && mi_is_selectable(&menu->items[sel])) { - menu->selected = sel; - scroll_menu(menu, 0, 1); + set_menu_selection(menu, sel); display_menu(win->term, menu); select_menu(win->term, menu); } @@ -696,6 +706,7 @@ menu_search_handler(struct input_line *line, int action_id) unsigned char *buffer = line->buffer; struct window *win; int pos = menu->selected; + int start; int direction; switch (action_id) { @@ -728,6 +739,7 @@ menu_search_handler(struct input_line *line, int action_id) pos %= menu->size; + start = pos; do { struct menu_item *item = &menu->items[pos]; @@ -741,7 +753,7 @@ menu_search_handler(struct input_line *line, int action_id) if (pos == menu->size) pos = 0; else if (pos < 0) pos = menu->size - 1; - } while (pos != menu->selected); + } while (pos != start); return INPUT_LINE_CANCEL; } @@ -867,8 +879,10 @@ menu_handler(struct window *win, struct term_event *ev) case EVENT_REDRAW: get_parent_ptr(win, &menu->parent_x, &menu->parent_y); count_menu_size(win->term, menu); - menu->selected--; - scroll_menu(menu, 1, 1); + /* do_menu sets menu->selected = 0. If that + * item isn't actually selectable, correct + * menu->selected here. */ + scroll_menu(menu, 0, 1); display_menu(win->term, menu); break;