[RFC v6 1/1] mconf: global i-search in menu structure

2018-06-15 Thread Dirk Gouders
This patch implements an i-search navigation concept for mconf based
on an idea of Sam Ravnborg:

* mconf now distinguishes if the focus is on the menu items or the
  buttons below it.

* At startup focus is on the menu items and printable characters
  (details see below) entered are used to form a string that is
  searched for.

This patch implements a global cyclic i-search in the complete menu
tree.  For ease of cyclic searches, the menu tree is serialized into
an array at startup.  For example, the following tree

a1 - b1 - c1 - d1 - e1
 | |
 b2d2 - d3
   |
   d4

is serialized to

a1 - b1 - b2 - c1 - d1 - d2 - d4 - d3 - e1

Operation
-
The TAB key is reserved to toggle the focus between menu and bottons.

When the focus is on the buttons, mconf operates as before with the
exception of the TAB key.

When the focus is on the menu, mconf operates in i-search mode and the
following input has special meaning:

* <\> (backslash) can be used to search for other occurences of an
  already entered string.  On empty search strings, nothing happens.

* Any other printable character than backslash is appended to the
  current search string and a match is searched for.

* BACKSPACE is used to remove the last character of the search string.

* DEL clears the search string.

* ENTER can be used to enter a submenu.

* ESC ESC exits the current isearch.

* Horizontal arrow keys still cycle between the buttons but also
  switch focus to the buttons.

* Vertical arroy keys navigate the menu items.

At any time, only one i-search is active and the navigation path to
the current menu is displayed in the subtitle, the second line in the
menu window.

Navigation example:

To navigate to options concerning NFS file systems, simply type 'n',
'f' and 's'.

Hint: use the 'z' key with focus on buttons to search for invisible
  prompts.

Signed-off-by: Dirk Gouders 
Suggested-by: Sam Ravnborg 
---
 scripts/kconfig/lxdialog/checklist.c |   2 +-
 scripts/kconfig/lxdialog/dialog.h|   3 +-
 scripts/kconfig/lxdialog/inputbox.c  |   2 +-
 scripts/kconfig/lxdialog/menubox.c   | 177 +-
 scripts/kconfig/lxdialog/util.c  |  37 ++-
 scripts/kconfig/lxdialog/yesno.c |   2 +-
 scripts/kconfig/mconf.c  | 181 +--
 7 files changed, 364 insertions(+), 40 deletions(-)

diff --git a/scripts/kconfig/lxdialog/checklist.c 
b/scripts/kconfig/lxdialog/checklist.c
index 2e96323ad11b..2a8bd877af72 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -160,7 +160,7 @@ int dialog_checklist(const char *title, const char *prompt, 
int height,
print_title(dialog, title, width);
 
wattrset(dialog, dlg.dialog.atr);
-   print_autowrap(dialog, prompt, width - 2, 1, 3);
+   print_autowrap(dialog, prompt, width - 2, 3, 1, 3);
 
list_width = width - 6;
box_y = height - list_height - 5;
diff --git a/scripts/kconfig/lxdialog/dialog.h 
b/scripts/kconfig/lxdialog/dialog.h
index 0b00be5abaa6..9396ed2122f9 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -214,7 +214,8 @@ void set_dialog_subtitles(struct subtitle_list *subtitles);
 void end_dialog(int x, int y);
 void attr_clear(WINDOW * win, int height, int width, chtype attr);
 void dialog_clear(void);
-void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_autowrap(WINDOW * win, const char *prompt,
+   int width, int height, int y, int x);
 void print_button(WINDOW * win, const char *label, int y, int x, int selected);
 void print_title(WINDOW *dialog, const char *title, int width);
 void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
diff --git a/scripts/kconfig/lxdialog/inputbox.c 
b/scripts/kconfig/lxdialog/inputbox.c
index fe82ff6d744e..121ac6b810f3 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -82,7 +82,7 @@ int dialog_inputbox(const char *title, const char *prompt, 
int height, int width
print_title(dialog, title, width);
 
wattrset(dialog, dlg.dialog.atr);
-   print_autowrap(dialog, prompt, width - 2, 1, 3);
+   print_autowrap(dialog, prompt, width - 2, 2, 1, 3);
 
/* Draw the input field box */
box_width = width - 6;
diff --git a/scripts/kconfig/lxdialog/menubox.c 
b/scripts/kconfig/lxdialog/menubox.c
index d70cab36137e..18de050a7dcc 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -58,21 +58,38 @@
 
 #include "dialog.h"
 
+#define ISEARCH_LEN 32
+char isearch_str[ISEARCH_LEN] = "";
+
 static int menu_width, item_x;
 
+int focus_on_buttons;
+
+static const char isearch_instructions[] =
+   "I-search: Arrow keys navigate the menu.  "
+   " selects submenus and/or clears i-search string.  "
+   "Type any character to search for 

[RFC v6 1/1] mconf: global i-search in menu structure

2018-06-15 Thread Dirk Gouders
This patch implements an i-search navigation concept for mconf based
on an idea of Sam Ravnborg:

* mconf now distinguishes if the focus is on the menu items or the
  buttons below it.

* At startup focus is on the menu items and printable characters
  (details see below) entered are used to form a string that is
  searched for.

This patch implements a global cyclic i-search in the complete menu
tree.  For ease of cyclic searches, the menu tree is serialized into
an array at startup.  For example, the following tree

a1 - b1 - c1 - d1 - e1
 | |
 b2d2 - d3
   |
   d4

is serialized to

a1 - b1 - b2 - c1 - d1 - d2 - d4 - d3 - e1

Operation
-
The TAB key is reserved to toggle the focus between menu and bottons.

When the focus is on the buttons, mconf operates as before with the
exception of the TAB key.

When the focus is on the menu, mconf operates in i-search mode and the
following input has special meaning:

* <\> (backslash) can be used to search for other occurences of an
  already entered string.  On empty search strings, nothing happens.

* Any other printable character than backslash is appended to the
  current search string and a match is searched for.

* BACKSPACE is used to remove the last character of the search string.

* DEL clears the search string.

* ENTER can be used to enter a submenu.

* ESC ESC exits the current isearch.

* Horizontal arrow keys still cycle between the buttons but also
  switch focus to the buttons.

* Vertical arroy keys navigate the menu items.

At any time, only one i-search is active and the navigation path to
the current menu is displayed in the subtitle, the second line in the
menu window.

Navigation example:

To navigate to options concerning NFS file systems, simply type 'n',
'f' and 's'.

Hint: use the 'z' key with focus on buttons to search for invisible
  prompts.

Signed-off-by: Dirk Gouders 
Suggested-by: Sam Ravnborg 
---
 scripts/kconfig/lxdialog/checklist.c |   2 +-
 scripts/kconfig/lxdialog/dialog.h|   3 +-
 scripts/kconfig/lxdialog/inputbox.c  |   2 +-
 scripts/kconfig/lxdialog/menubox.c   | 177 +-
 scripts/kconfig/lxdialog/util.c  |  37 ++-
 scripts/kconfig/lxdialog/yesno.c |   2 +-
 scripts/kconfig/mconf.c  | 181 +--
 7 files changed, 364 insertions(+), 40 deletions(-)

diff --git a/scripts/kconfig/lxdialog/checklist.c 
b/scripts/kconfig/lxdialog/checklist.c
index 2e96323ad11b..2a8bd877af72 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -160,7 +160,7 @@ int dialog_checklist(const char *title, const char *prompt, 
int height,
print_title(dialog, title, width);
 
wattrset(dialog, dlg.dialog.atr);
-   print_autowrap(dialog, prompt, width - 2, 1, 3);
+   print_autowrap(dialog, prompt, width - 2, 3, 1, 3);
 
list_width = width - 6;
box_y = height - list_height - 5;
diff --git a/scripts/kconfig/lxdialog/dialog.h 
b/scripts/kconfig/lxdialog/dialog.h
index 0b00be5abaa6..9396ed2122f9 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -214,7 +214,8 @@ void set_dialog_subtitles(struct subtitle_list *subtitles);
 void end_dialog(int x, int y);
 void attr_clear(WINDOW * win, int height, int width, chtype attr);
 void dialog_clear(void);
-void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_autowrap(WINDOW * win, const char *prompt,
+   int width, int height, int y, int x);
 void print_button(WINDOW * win, const char *label, int y, int x, int selected);
 void print_title(WINDOW *dialog, const char *title, int width);
 void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
diff --git a/scripts/kconfig/lxdialog/inputbox.c 
b/scripts/kconfig/lxdialog/inputbox.c
index fe82ff6d744e..121ac6b810f3 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -82,7 +82,7 @@ int dialog_inputbox(const char *title, const char *prompt, 
int height, int width
print_title(dialog, title, width);
 
wattrset(dialog, dlg.dialog.atr);
-   print_autowrap(dialog, prompt, width - 2, 1, 3);
+   print_autowrap(dialog, prompt, width - 2, 2, 1, 3);
 
/* Draw the input field box */
box_width = width - 6;
diff --git a/scripts/kconfig/lxdialog/menubox.c 
b/scripts/kconfig/lxdialog/menubox.c
index d70cab36137e..18de050a7dcc 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -58,21 +58,38 @@
 
 #include "dialog.h"
 
+#define ISEARCH_LEN 32
+char isearch_str[ISEARCH_LEN] = "";
+
 static int menu_width, item_x;
 
+int focus_on_buttons;
+
+static const char isearch_instructions[] =
+   "I-search: Arrow keys navigate the menu.  "
+   " selects submenus and/or clears i-search string.  "
+   "Type any character to search for