menuconfig: Assign jump keys per-page instead of globally
At the moment, keys 1-9 are assigned to the first 9 search results. This patch
makes them assigned to the first 9 results per-page instead. We are much less
likely to run out of keys that way.
Signed-off-by: Benjamin Poirier <bpoirier@suse.de>
Signed-off-by: Michal Marek <mmarek@suse.cz>
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 52f4246..bd2e098 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -12,6 +12,7 @@
#include <assert.h>
#include <stdio.h>
+#include <sys/queue.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
@@ -173,6 +174,14 @@
#define MENU_CHANGED 0x0001
#define MENU_ROOT 0x0002
+struct jump_key {
+ CIRCLEQ_ENTRY(jump_key) entries;
+ size_t offset;
+ struct menu *target;
+ int index;
+};
+CIRCLEQ_HEAD(jk_head, jump_key);
+
#define JUMP_NB 9
extern struct file *file_list;
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 946c2cb3..1d1c085 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -21,10 +21,10 @@
P(menu_get_parent_menu,struct menu *,(struct menu *menu));
P(menu_has_help,bool,(struct menu *menu));
P(menu_get_help,const char *,(struct menu *menu));
-P(get_symbol_str, int, (struct gstr *r, struct symbol *sym, struct menu
- **jumps, int jump_nb));
-P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct menu
- **jumps));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct jk_head
+ *head));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct jk_head
+ *head));
P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
/* symbol.c */
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index 2a01cdf..ee17a52 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -210,8 +210,13 @@
int dialog_yesno(const char *title, const char *prompt, int height, int width);
int dialog_msgbox(const char *title, const char *prompt, int height,
int width, int pause);
-int dialog_textbox(const char *title, const char *file, int height, int width,
- int *keys, int *_vscroll, int *_hscroll);
+
+
+typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
+ *_data);
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+ int initial_width, int *keys, int *_vscroll, int *_hscroll,
+ update_text_fn update_text, void *data);
int dialog_menu(const char *title, const char *prompt,
const void *selected, int *s_scroll);
int dialog_checklist(const char *title, const char *prompt, int height,
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
index 3b3c5c4..a48bb93 100644
--- a/scripts/kconfig/lxdialog/textbox.c
+++ b/scripts/kconfig/lxdialog/textbox.c
@@ -22,23 +22,25 @@
#include "dialog.h"
static void back_lines(int n);
-static void print_page(WINDOW * win, int height, int width);
-static void print_line(WINDOW * win, int row, int width);
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+ update_text, void *data);
+static void print_line(WINDOW *win, int row, int width);
static char *get_line(void);
static void print_position(WINDOW * win);
static int hscroll;
static int begin_reached, end_reached, page_length;
-static const char *buf;
-static const char *page;
+static char *buf;
+static char *page;
/*
* refresh window content
*/
static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
- int cur_y, int cur_x)
+ int cur_y, int cur_x, update_text_fn update_text,
+ void *data)
{
- print_page(box, boxh, boxw);
+ print_page(box, boxh, boxw, update_text, data);
print_position(dialog);
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
wrefresh(dialog);
@@ -49,9 +51,11 @@
* Display text from a file in a dialog box.
*
* keys is a null-terminated array
+ * update_text() may not add or remove any '\n' or '\0' in tbuf
*/
-int dialog_textbox(const char *title, const char *tbuf, int initial_height,
- int initial_width, int *keys, int *_vscroll, int *_hscroll)
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+ int initial_width, int *keys, int *_vscroll, int *_hscroll,
+ update_text_fn update_text, void *data)
{
int i, x, y, cur_x, cur_y, key = 0;
int height, width, boxh, boxw;
@@ -131,7 +135,8 @@
/* Print first page of text */
attr_clear(box, boxh, boxw, dlg.dialog.atr);
- refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
+ data);
while (!done) {
key = wgetch(dialog);
@@ -150,7 +155,8 @@
begin_reached = 1;
page = buf;
refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ cur_y, cur_x, update_text,
+ data);
}
break;
case 'G': /* Last page */
@@ -160,8 +166,8 @@
/* point to last char in buf */
page = buf + strlen(buf);
back_lines(boxh);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case 'K': /* Previous line */
case 'k':
@@ -171,7 +177,7 @@
back_lines(page_length + 1);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
- cur_x);
+ cur_x, update_text, data);
break;
case 'B': /* Previous page */
case 'b':
@@ -180,8 +186,8 @@
if (begin_reached)
break;
back_lines(page_length + boxh);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case 'J': /* Next line */
case 'j':
@@ -191,7 +197,7 @@
back_lines(page_length - 1);
refresh_text_box(dialog, box, boxh, boxw, cur_y,
- cur_x);
+ cur_x, update_text, data);
break;
case KEY_NPAGE: /* Next page */
case ' ':
@@ -200,8 +206,8 @@
break;
begin_reached = 0;
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case '0': /* Beginning of line */
case 'H': /* Scroll left */
@@ -216,8 +222,8 @@
hscroll--;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case 'L': /* Scroll right */
case 'l':
@@ -227,8 +233,8 @@
hscroll++;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
- refresh_text_box(dialog, box, boxh, boxw,
- cur_y, cur_x);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y,
+ cur_x, update_text, data);
break;
case KEY_ESC:
if (on_key_esc(dialog) == KEY_ESC)
@@ -301,12 +307,23 @@
}
/*
- * Print a new page of text. Called by dialog_textbox().
+ * Print a new page of text.
*/
-static void print_page(WINDOW * win, int height, int width)
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+ update_text, void *data)
{
int i, passed_end = 0;
+ if (update_text) {
+ char *end;
+
+ for (i = 0; i < height; i++)
+ get_line();
+ end = page;
+ back_lines(height);
+ update_text(buf, page - buf, end - buf, data);
+ }
+
page_length = 0;
for (i = 0; i < height; i++) {
print_line(win, i, width);
@@ -319,7 +336,7 @@
}
/*
- * Print a new line of text. Called by dialog_textbox() and print_page().
+ * Print a new line of text.
*/
static void print_line(WINDOW * win, int row, int width)
{
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 6f40974..48f6744 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -286,8 +286,9 @@
static void conf_string(struct menu *menu);
static void conf_load(void);
static void conf_save(void);
-static int show_textbox_ext(const char *title, const char *text, int r, int c,
- int *keys, int *vscroll, int *hscroll);
+static int show_textbox_ext(const char *title, char *text, int r, int c,
+ int *keys, int *vscroll, int *hscroll,
+ update_text_fn update_text, void *data);
static void show_textbox(const char *title, const char *text, int r, int c);
static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu);
@@ -310,6 +311,39 @@
}
+struct search_data {
+ struct jk_head *head;
+ struct menu **targets;
+ int *keys;
+};
+
+static void update_text(char *buf, size_t start, size_t end, void *_data)
+{
+ struct search_data *data = _data;
+ struct jump_key *pos;
+ int k = 0;
+
+ CIRCLEQ_FOREACH(pos, data->head, entries) {
+ if (pos->offset >= start && pos->offset < end) {
+ char header[4];
+
+ if (k < JUMP_NB) {
+ int key = '0' + (pos->index % JUMP_NB) + 1;
+
+ sprintf(header, "(%c)", key);
+ data->keys[k] = key;
+ data->targets[k] = pos->target;
+ k++;
+ } else {
+ sprintf(header, " ");
+ }
+
+ memcpy(buf + pos->offset, header, sizeof(header) - 1);
+ }
+ }
+ data->keys[k] = 0;
+}
+
static void search_conf(void)
{
struct symbol **sym_arr;
@@ -341,18 +375,24 @@
sym_arr = sym_re_search(dialog_input);
do {
- struct menu *jumps[JUMP_NB] = {0};
- int keys[JUMP_NB + 1] = {0}, i;
+ struct jk_head head = CIRCLEQ_HEAD_INITIALIZER(head);
+ struct menu *targets[JUMP_NB];
+ int keys[JUMP_NB + 1], i;
+ struct search_data data = {
+ .head = &head,
+ .targets = targets,
+ .keys = keys,
+ };
- 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);
+ res = get_relations_str(sym_arr, &head);
+ dres = show_textbox_ext(_("Search Results"), (char *)
+ str_get(&res), 0, 0, keys, &vscroll,
+ &hscroll, &update_text, (void *)
+ &data);
again = false;
- for (i = 0; i < JUMP_NB && jumps[i]; i++)
+ for (i = 0; i < JUMP_NB && keys[i]; i++)
if (dres == keys[i]) {
- conf(jumps[i]->parent, jumps[i]);
+ conf(targets[i]->parent, targets[i]);
again = true;
}
str_free(&res);
@@ -642,16 +682,19 @@
}
}
-static int show_textbox_ext(const char *title, const char *text, int r, int c,
- int *keys, int *vscroll, int *hscroll)
+static int show_textbox_ext(const char *title, char *text, int r, int c, int
+ *keys, int *vscroll, int *hscroll, update_text_fn
+ update_text, void *data)
{
dialog_clear();
- return dialog_textbox(title, text, r, c, keys, vscroll, hscroll);
+ return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
+ update_text, data);
}
static void show_textbox(const char *title, const char *text, int r, int c)
{
- show_textbox_ext(title, text, r, c, (int []) {0}, NULL, NULL);
+ show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
+ NULL, NULL);
}
static void show_helptext(const char *title, const char *text)
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index a524185..a3cade6 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -507,12 +507,12 @@
return "";
}
-static int get_prompt_str(struct gstr *r, struct property *prop, struct menu
- **jumps, int jump_nb)
+static void get_prompt_str(struct gstr *r, struct property *prop,
+ struct jk_head *head)
{
int i, j;
- char header[4];
struct menu *submenu[8], *menu, *location = NULL;
+ struct jump_key *jump;
str_printf(r, _("Prompt: %s\n"), _(prop->text));
str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name,
@@ -530,7 +530,9 @@
if (location == NULL && accessible)
location = menu;
}
- if (jumps && jump_nb < JUMP_NB && location) {
+ if (head && location) {
+ jump = malloc(sizeof(struct jump_key));
+
if (menu_is_visible(prop->menu)) {
/*
* There is not enough room to put the hint at the
@@ -538,19 +540,26 @@
* last "Location" line even when it would belong on
* the former.
*/
- jumps[jump_nb] = prop->menu;
+ jump->target = prop->menu;
} else
- jumps[jump_nb] = location;
- snprintf(header, 4, "(%d)", jump_nb + 1);
- } else
- location = NULL;
+ jump->target = location;
+
+ if (CIRCLEQ_EMPTY(head))
+ jump->index = 0;
+ else
+ jump->index = CIRCLEQ_LAST(head)->index + 1;
+
+ CIRCLEQ_INSERT_TAIL(head, jump, entries);
+ }
if (i > 0) {
str_printf(r, _(" Location:\n"));
- for (j = 1; --i >= 0; j += 2) {
+ for (j = 4; --i >= 0; j += 2) {
menu = submenu[i];
- str_printf(r, "%s%*c-> %s", menu == location ? header
- : " ", j, ' ', _(menu_get_prompt(menu)));
+ if (head && location && menu == location)
+ jump->offset = r->len - 1;
+ str_printf(r, "%*c-> %s", j, ' ',
+ _(menu_get_prompt(menu)));
if (menu->sym) {
str_printf(r, " (%s [=%s])", menu->sym->name ?
menu->sym->name : _("<choice>"),
@@ -559,20 +568,15 @@
str_append(r, "\n");
}
}
-
- return location ? 1 : 0;
}
/*
- * jumps is optional and may be NULL
- * returns the number of jumps inserted
+ * head is optional and may be NULL
*/
-int get_symbol_str(struct gstr *r, struct symbol *sym, struct menu **jumps,
- int jump_nb)
+void get_symbol_str(struct gstr *r, struct symbol *sym, struct jk_head *head)
{
bool hit;
struct property *prop;
- int i = 0;
if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
@@ -588,7 +592,7 @@
}
}
for_all_prompts(sym, prop)
- i += get_prompt_str(r, prop, jumps, jump_nb + i);
+ get_prompt_str(r, prop, head);
hit = false;
for_all_properties(sym, prop, P_SELECT) {
if (!hit) {
@@ -606,18 +610,16 @@
str_append(r, "\n");
}
str_append(r, "\n\n");
-
- return i;
}
-struct gstr get_relations_str(struct symbol **sym_arr, struct menu **jumps)
+struct gstr get_relations_str(struct symbol **sym_arr, struct jk_head *head)
{
struct symbol *sym;
struct gstr res = str_new();
- int i, jump_nb = 0;
+ int i;
for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
- jump_nb += get_symbol_str(&res, sym, jumps, jump_nb);
+ get_symbol_str(&res, sym, head);
if (!i)
str_append(&res, _("No matches found.\n"));
return res;
@@ -636,5 +638,5 @@
}
str_printf(help, "%s\n", _(help_text));
if (sym)
- get_symbol_str(help, sym, NULL, 0);
+ get_symbol_str(help, sym, NULL);
}