menuconfig: Add jump keys to search results

makes it possible to jump directly to the menu for a configuration entry after
having searched for it with '/'. If this menu is not currently accessible we
jump to the nearest accessible parent instead. After exiting this menu, the
user is returned to the search results where he may jump further in or
elsewhere.

Signed-off-by: Benjamin Poirier <bpoirier@suse.de>
Signed-off-by: Michal Marek <mmarek@suse.cz>
This commit is contained in:
Benjamin Poirier 2012-08-23 14:55:06 -04:00 committed by Michal Marek
parent 1d1e2caebb
commit 5e609addb1
5 changed files with 94 additions and 35 deletions

View file

@ -173,6 +173,8 @@ struct menu {
#define MENU_CHANGED 0x0001 #define MENU_CHANGED 0x0001
#define MENU_ROOT 0x0002 #define MENU_ROOT 0x0002
#define JUMP_NB 9
extern struct file *file_list; extern struct file *file_list;
extern struct file *current_file; extern struct file *current_file;
struct file *lookup_file(const char *name); struct file *lookup_file(const char *name);

View file

@ -21,8 +21,10 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu));
P(menu_get_parent_menu,struct menu *,(struct menu *menu)); P(menu_get_parent_menu,struct menu *,(struct menu *menu));
P(menu_has_help,bool,(struct menu *menu)); P(menu_has_help,bool,(struct menu *menu));
P(menu_get_help,const char *,(struct menu *menu)); P(menu_get_help,const char *,(struct menu *menu));
P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); P(get_symbol_str, int, (struct gstr *r, struct symbol *sym, struct menu
P(get_relations_str, struct gstr, (struct symbol **sym_arr)); **jumps, int jump_nb));
P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct menu
**jumps));
P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
/* symbol.c */ /* symbol.c */

View file

@ -236,16 +236,19 @@ search_help[] = N_(
"Result:\n" "Result:\n"
"-----------------------------------------------------------------\n" "-----------------------------------------------------------------\n"
"Symbol: FOO [=m]\n" "Symbol: FOO [=m]\n"
"Type : tristate\n"
"Prompt: Foo bus is used to drive the bar HW\n" "Prompt: Foo bus is used to drive the bar HW\n"
"Defined at drivers/pci/Kconfig:47\n" " Defined at drivers/pci/Kconfig:47\n"
"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" " Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
"Location:\n" " Location:\n"
" -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
" -> PCI support (PCI [=y])\n" " -> PCI support (PCI [=y])\n"
" -> PCI access mode (<choice> [=y])\n" "(1) -> PCI access mode (<choice> [=y])\n"
"Selects: LIBCRC32\n" " Selects: LIBCRC32\n"
"Selected by: BAR\n" " Selected by: BAR\n"
"-----------------------------------------------------------------\n" "-----------------------------------------------------------------\n"
"o The line 'Type:' shows the type of the configuration option for\n"
" this symbol (boolean, tristate, string, ...)\n"
"o The line 'Prompt:' shows the text used in the menu structure for\n" "o The line 'Prompt:' shows the text used in the menu structure for\n"
" this symbol\n" " this symbol\n"
"o The 'Defined at' line tell at what file / line number the symbol\n" "o The 'Defined at' line tell at what file / line number the symbol\n"
@ -254,8 +257,12 @@ search_help[] = N_(
" this symbol to be visible in the menu (selectable)\n" " this symbol to be visible in the menu (selectable)\n"
"o The 'Location:' lines tell where in the menu structure this symbol\n" "o The 'Location:' lines tell where in the menu structure this symbol\n"
" is located\n" " is located\n"
" A location followed by a [=y] indicate that this is a selectable\n" " A location followed by a [=y] indicates that this is a\n"
" menu item - and current value is displayed inside brackets.\n" " 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 tell what symbol will be automatically\n" "o The 'Selects:' line tell what symbol will be automatically\n"
" selected if this symbol is selected (y or m)\n" " selected if this symbol is selected (y or m)\n"
"o The 'Selected by' line tell what symbol has selected this symbol\n" "o The 'Selected by' line tell what symbol has selected this symbol\n"
@ -274,7 +281,7 @@ static int child_count;
static int single_menu_mode; static int single_menu_mode;
static int show_all_options; static int show_all_options;
static void conf(struct menu *menu); static void conf(struct menu *menu, struct menu *active_menu);
static void conf_choice(struct menu *menu); static void conf_choice(struct menu *menu);
static void conf_string(struct menu *menu); static void conf_string(struct menu *menu);
static void conf_load(void); static void conf_load(void);
@ -308,7 +315,9 @@ static void search_conf(void)
struct symbol **sym_arr; struct symbol **sym_arr;
struct gstr res; struct gstr res;
char *dialog_input; char *dialog_input;
int dres; int dres, vscroll = 0, hscroll = 0;
bool again;
again: again:
dialog_clear(); dialog_clear();
dres = dialog_inputbox(_("Search Configuration Parameter"), dres = dialog_inputbox(_("Search Configuration Parameter"),
@ -331,10 +340,24 @@ again:
dialog_input += strlen(CONFIG_); dialog_input += strlen(CONFIG_);
sym_arr = sym_re_search(dialog_input); sym_arr = sym_re_search(dialog_input);
res = get_relations_str(sym_arr); do {
struct menu *jumps[JUMP_NB] = {0};
int keys[JUMP_NB + 1] = {0}, i;
res = get_relations_str(sym_arr, jumps);
for (i = 0; i < JUMP_NB && jumps[i]; i++)
keys[i] = '1' + i;
dres = show_textbox_ext(_("Search Results"), str_get(&res), 0,
0, keys, &vscroll, &hscroll);
again = false;
for (i = 0; i < JUMP_NB && jumps[i]; i++)
if (dres == keys[i]) {
conf(jumps[i]->parent, jumps[i]);
again = true;
}
str_free(&res);
} while (again);
free(sym_arr); free(sym_arr);
show_textbox(_("Search Results"), str_get(&res), 0, 0);
str_free(&res);
} }
static void build_conf(struct menu *menu) static void build_conf(struct menu *menu)
@ -515,12 +538,11 @@ conf_childs:
indent -= doint; indent -= doint;
} }
static void conf(struct menu *menu) static void conf(struct menu *menu, struct menu *active_menu)
{ {
struct menu *submenu; struct menu *submenu;
const char *prompt = menu_get_prompt(menu); const char *prompt = menu_get_prompt(menu);
struct symbol *sym; struct symbol *sym;
struct menu *active_menu = NULL;
int res; int res;
int s_scroll = 0; int s_scroll = 0;
@ -563,13 +585,13 @@ static void conf(struct menu *menu)
if (single_menu_mode) if (single_menu_mode)
submenu->data = (void *) (long) !submenu->data; submenu->data = (void *) (long) !submenu->data;
else else
conf(submenu); conf(submenu, NULL);
break; break;
case 't': case 't':
if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
conf_choice(submenu); conf_choice(submenu);
else if (submenu->prompt->type == P_MENU) else if (submenu->prompt->type == P_MENU)
conf(submenu); conf(submenu, NULL);
break; break;
case 's': case 's':
conf_string(submenu); conf_string(submenu);
@ -608,7 +630,7 @@ static void conf(struct menu *menu)
if (item_is_tag('t')) if (item_is_tag('t'))
sym_toggle_tristate_value(sym); sym_toggle_tristate_value(sym);
else if (item_is_tag('m')) else if (item_is_tag('m'))
conf(submenu); conf(submenu, NULL);
break; break;
case 7: case 7:
search_conf(); search_conf();
@ -877,7 +899,7 @@ int main(int ac, char **av)
set_config_filename(conf_get_configname()); set_config_filename(conf_get_configname());
do { do {
conf(&rootmenu); conf(&rootmenu, NULL);
res = handle_exit(); res = handle_exit();
} while (res == KEY_ESC); } while (res == KEY_ESC);

View file

@ -507,10 +507,12 @@ const char *menu_get_help(struct menu *menu)
return ""; return "";
} }
static void get_prompt_str(struct gstr *r, struct property *prop) static int get_prompt_str(struct gstr *r, struct property *prop, struct menu
**jumps, int jump_nb)
{ {
int i, j; int i, j;
struct menu *submenu[8], *menu; char header[4];
struct menu *submenu[8], *menu, *location = NULL;
str_printf(r, _("Prompt: %s\n"), _(prop->text)); str_printf(r, _("Prompt: %s\n"), _(prop->text));
str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
@ -521,13 +523,34 @@ static void get_prompt_str(struct gstr *r, struct property *prop)
str_append(r, "\n"); str_append(r, "\n");
} }
menu = prop->menu->parent; menu = prop->menu->parent;
for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
bool accessible = menu_is_visible(menu);
submenu[i++] = menu; submenu[i++] = menu;
if (location == NULL && accessible)
location = menu;
}
if (jumps && jump_nb < JUMP_NB && location) {
if (menu_is_visible(prop->menu)) {
/*
* There is not enough room to put the hint at the
* beginning of the "Prompt" line. Put the hint on the
* last "Location" line even when it would belong on
* the former.
*/
jumps[jump_nb] = prop->menu;
} else
jumps[jump_nb] = location;
snprintf(header, 4, "(%d)", jump_nb + 1);
} else
location = NULL;
if (i > 0) { if (i > 0) {
str_printf(r, _(" Location:\n")); str_printf(r, _(" Location:\n"));
for (j = 4; --i >= 0; j += 2) { for (j = 1; --i >= 0; j += 2) {
menu = submenu[i]; menu = submenu[i];
str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu))); str_printf(r, "%s%*c-> %s", menu == location ? header
: " ", j, ' ', _(menu_get_prompt(menu)));
if (menu->sym) { if (menu->sym) {
str_printf(r, " (%s [=%s])", menu->sym->name ? str_printf(r, " (%s [=%s])", menu->sym->name ?
menu->sym->name : _("<choice>"), menu->sym->name : _("<choice>"),
@ -536,12 +559,20 @@ static void get_prompt_str(struct gstr *r, struct property *prop)
str_append(r, "\n"); str_append(r, "\n");
} }
} }
return location ? 1 : 0;
} }
void get_symbol_str(struct gstr *r, struct symbol *sym) /*
* jumps is optional and may be NULL
* returns the number of jumps inserted
*/
int get_symbol_str(struct gstr *r, struct symbol *sym, struct menu **jumps,
int jump_nb)
{ {
bool hit; bool hit;
struct property *prop; struct property *prop;
int i = 0;
if (sym && sym->name) { if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name, str_printf(r, "Symbol: %s [=%s]\n", sym->name,
@ -557,7 +588,7 @@ void get_symbol_str(struct gstr *r, struct symbol *sym)
} }
} }
for_all_prompts(sym, prop) for_all_prompts(sym, prop)
get_prompt_str(r, prop); i += get_prompt_str(r, prop, jumps, jump_nb + i);
hit = false; hit = false;
for_all_properties(sym, prop, P_SELECT) { for_all_properties(sym, prop, P_SELECT) {
if (!hit) { if (!hit) {
@ -575,16 +606,18 @@ void get_symbol_str(struct gstr *r, struct symbol *sym)
str_append(r, "\n"); str_append(r, "\n");
} }
str_append(r, "\n\n"); str_append(r, "\n\n");
return i;
} }
struct gstr get_relations_str(struct symbol **sym_arr) struct gstr get_relations_str(struct symbol **sym_arr, struct menu **jumps)
{ {
struct symbol *sym; struct symbol *sym;
struct gstr res = str_new(); struct gstr res = str_new();
int i; int i, jump_nb = 0;
for (i = 0; sym_arr && (sym = sym_arr[i]); i++) for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
get_symbol_str(&res, sym); jump_nb += get_symbol_str(&res, sym, jumps, jump_nb);
if (!i) if (!i)
str_append(&res, _("No matches found.\n")); str_append(&res, _("No matches found.\n"));
return res; return res;
@ -603,5 +636,5 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help)
} }
str_printf(help, "%s\n", _(help_text)); str_printf(help, "%s\n", _(help_text));
if (sym) if (sym)
get_symbol_str(help, sym); get_symbol_str(help, sym, NULL, 0);
} }

View file

@ -721,7 +721,7 @@ again:
dialog_input += strlen(CONFIG_); dialog_input += strlen(CONFIG_);
sym_arr = sym_re_search(dialog_input); sym_arr = sym_re_search(dialog_input);
res = get_relations_str(sym_arr); res = get_relations_str(sym_arr, NULL);
free(sym_arr); free(sym_arr);
show_scroll_win(main_window, show_scroll_win(main_window,
_("Search Results"), str_get(&res)); _("Search Results"), str_get(&res));