On Tue, Aug 8, 2023 at 8:42 PM Jesse Taube <mr.bossman075@xxxxxxxxx> wrote: > > From: Jesse Taube <mr.bossman075@xxxxxxxxx> > > Menuconfig has a feature where you can "press the key in the (#) prefix > to jump directly to that location. You will be returned to the current > search results after exiting this new menu." > > This commit adds this feature to nconfig, with almost identical code. > > Signed-off-by: Jesse Taube <Mr.Bossman075@xxxxxxxxx> > --- > v1->v2: > Add selected_conf to go to menu and select a specific option. > Use get_line instead of creating new function. > Use Masahiro Yamada's new jump search implementation. > v2->v3: > Change `start, end` to size_t and move scope to if > Removed redundant assignment of `again` to false. > v3->v4: > Remove unnecessary size_t cast > Use ncurses to find line index in selected_conf @randy can you please test this as well. Thanks, Jesse Taube > --- > scripts/kconfig/nconf.c | 113 ++++++++++++++++++++++++++++++++---- > scripts/kconfig/nconf.gui.c | 37 ++++++++++-- > scripts/kconfig/nconf.h | 5 ++ > 3 files changed, 140 insertions(+), 15 deletions(-) > > diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c > index 3ba8b1af390f..143a2c351d57 100644 > --- a/scripts/kconfig/nconf.c > +++ b/scripts/kconfig/nconf.c > @@ -220,7 +220,7 @@ search_help[] = > "Location:\n" > " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" > " -> PCI support (PCI [ = y])\n" > -" -> PCI access mode (<choice> [ = y])\n" > +"(1) -> PCI access mode (<choice> [ = y])\n" > "Selects: LIBCRC32\n" > "Selected by: BAR\n" > "-----------------------------------------------------------------\n" > @@ -231,9 +231,13 @@ search_help[] = > "o The 'Depends on:' line lists symbols that need to be defined for\n" > " this symbol to be visible and selectable in the menu.\n" > "o The 'Location:' lines tell, where in the menu structure this symbol\n" > -" is located. A location followed by a [ = y] indicates that this is\n" > -" a selectable menu item, and the current value is displayed inside\n" > -" brackets.\n" > +" is located.\n" > +" A location followed by a [ = y] indicates that this is\n" > +" a selectable menu item, and the current value is displayed inside\n" > +" brackets.\n" > +" Press the key in the (#) prefix to jump directly to that\n" > +" location. You will be returned to the current search results\n" > +" after exiting this new menu.\n" > "o The 'Selects:' line tells, what symbol will be automatically selected\n" > " if this symbol is selected (y or m).\n" > "o The 'Selected by' line tells what symbol has selected this symbol.\n" > @@ -275,7 +279,9 @@ static const char *current_instructions = menu_instructions; > > static char *dialog_input_result; > static int dialog_input_result_len; > +static int jump_key_char; > > +static void selected_conf(struct menu *menu, struct menu *active_menu); > static void conf(struct menu *menu); > static void conf_choice(struct menu *menu); > static void conf_string(struct menu *menu); > @@ -685,6 +691,57 @@ static int do_exit(void) > return 0; > } > > +struct search_data { > + struct list_head *head; > + struct menu *target; > +}; > + > +static int next_jump_key(int key) > +{ > + if (key < '1' || key > '9') > + return '1'; > + > + key++; > + > + if (key > '9') > + key = '1'; > + > + return key; > +} > + > +static int handle_search_keys(int key, size_t start, size_t end, void *_data) > +{ > + struct search_data *data = _data; > + struct jump_key *pos; > + int index = 0; > + > + if (key < '1' || key > '9') > + return 0; > + > + list_for_each_entry(pos, data->head, entries) { > + index = next_jump_key(index); > + > + if (pos->offset < start) > + continue; > + > + if (pos->offset >= end) > + break; > + > + if (key == index) { > + data->target = pos->target; > + return 1; > + } > + } > + > + return 0; > +} > + > +int get_jump_key_char(void) > +{ > + jump_key_char = next_jump_key(jump_key_char); > + > + return jump_key_char; > +} > > static void search_conf(void) > { > @@ -692,7 +749,8 @@ static void search_conf(void) > struct gstr res; > struct gstr title; > char *dialog_input; > - int dres; > + int dres, vscroll = 0, hscroll = 0; > + bool again; > > title = str_new(); > str_printf( &title, "Enter (sub)string or regexp to search for " > @@ -721,11 +779,28 @@ static void search_conf(void) > dialog_input += strlen(CONFIG_); > > sym_arr = sym_re_search(dialog_input); > - res = get_relations_str(sym_arr, NULL); > + > + do { > + LIST_HEAD(head); > + struct search_data data = { > + .head = &head, > + .target = NULL, > + }; > + jump_key_char = 0; > + res = get_relations_str(sym_arr, &head); > + dres = show_scroll_win_ext(main_window, > + "Search Results", str_get(&res), > + &vscroll, &hscroll, > + handle_search_keys, &data); > + again = false; > + if (dres >= '1' && dres <= '9') { > + assert(data.target != NULL); > + selected_conf(data.target->parent, data.target); > + again = true; > + } > + str_free(&res); > + } while (again); > free(sym_arr); > - show_scroll_win(main_window, > - "Search Results", str_get(&res)); > - str_free(&res); > str_free(&title); > } > > @@ -1062,10 +1137,15 @@ static int do_match(int key, struct match_state *state, int *ans) > } > > static void conf(struct menu *menu) > +{ > + selected_conf(menu, NULL); > +} > + > +static void selected_conf(struct menu *menu, struct menu *active_menu) > { > struct menu *submenu = NULL; > struct symbol *sym; > - int res; > + int i, res; > int current_index = 0; > int last_top_row = 0; > struct match_state match_state = { > @@ -1081,6 +1161,19 @@ static void conf(struct menu *menu) > if (!child_count) > break; > > + if (active_menu != NULL) { > + for (i = 0; i < items_num; i++) { > + struct mitem *mcur; > + > + mcur = (struct mitem *) item_userptr(curses_menu_items[i]); > + if ((struct menu *) mcur->usrptr == active_menu) { > + current_index = i; > + break; > + } > + } > + active_menu = NULL; > + } > + > show_menu(menu_get_prompt(menu), menu_instructions, > current_index, &last_top_row); > keypad((menu_win(curses_menu)), TRUE); > diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c > index 9aedf40f1dc0..25a7263ef3c8 100644 > --- a/scripts/kconfig/nconf.gui.c > +++ b/scripts/kconfig/nconf.gui.c > @@ -497,10 +497,17 @@ void refresh_all_windows(WINDOW *main_window) > refresh(); > } > > -/* layman's scrollable window... */ > void show_scroll_win(WINDOW *main_window, > const char *title, > const char *text) > +{ > + (void)show_scroll_win_ext(main_window, title, (char *)text, NULL, NULL, NULL, NULL); > +} > + > +/* layman's scrollable window... */ > +int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text, > + int *vscroll, int *hscroll, > + extra_key_cb_fn extra_key_cb, void *data) > { > int res; > int total_lines = get_line_no(text); > @@ -514,6 +521,12 @@ void show_scroll_win(WINDOW *main_window, > WINDOW *win; > WINDOW *pad; > PANEL *panel; > + bool done = false; > + > + if (hscroll) > + start_x = *hscroll; > + if (vscroll) > + start_y = *vscroll; > > getmaxyx(stdscr, lines, columns); > > @@ -549,8 +562,7 @@ void show_scroll_win(WINDOW *main_window, > panel = new_panel(win); > > /* handle scrolling */ > - do { > - > + while (!done) { > copywin(pad, win, start_y, start_x, 2, 2, text_lines, > text_cols, 0); > print_in_middle(win, > @@ -593,8 +605,18 @@ void show_scroll_win(WINDOW *main_window, > case 'l': > start_x++; > break; > + default: > + if (extra_key_cb) { > + size_t start = (get_line(text, start_y) - text); > + size_t end = (get_line(text, start_y + text_lines) - text); > + > + if (extra_key_cb(res, start, end, data)) { > + done = true; > + break; > + } > + } > } > - if (res == 10 || res == 27 || res == 'q' || > + if (res == 0 || res == 10 || res == 27 || res == 'q' || > res == KEY_F(F_HELP) || res == KEY_F(F_BACK) || > res == KEY_F(F_EXIT)) > break; > @@ -606,9 +628,14 @@ void show_scroll_win(WINDOW *main_window, > start_x = 0; > if (start_x >= total_cols-text_cols) > start_x = total_cols-text_cols; > - } while (res); > + } > > + if (hscroll) > + *hscroll = start_x; > + if (vscroll) > + *vscroll = start_y; > del_panel(panel); > delwin(win); > refresh_all_windows(main_window); > + return res; > } > diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h > index 6f925bc74eb3..ab836d582664 100644 > --- a/scripts/kconfig/nconf.h > +++ b/scripts/kconfig/nconf.h > @@ -67,6 +67,8 @@ typedef enum { > > void set_colors(void); > > +typedef int (*extra_key_cb_fn)(int, size_t, size_t, void *); > + > /* this changes the windows attributes !!! */ > void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs); > int get_line_length(const char *line); > @@ -78,6 +80,9 @@ int dialog_inputbox(WINDOW *main_window, > const char *title, const char *prompt, > const char *init, char **resultp, int *result_len); > void refresh_all_windows(WINDOW *main_window); > +int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text, > + int *vscroll, int *hscroll, > + extra_key_cb_fn extra_key_cb, void *data); > void show_scroll_win(WINDOW *main_window, > const char *title, > const char *text); > -- > 2.40.0 >