summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2012-10-15 01:46:52 +0200
committerMaxime Coste <frrrwww@gmail.com>2012-10-15 12:49:46 +0200
commit4be6882bd55a8042adf062cfad3c7c50e7b60e0b (patch)
treea7126a514365cbde8e6ddf9b867e08793714e78e /src
parent148466c659502bb4d57031bbd9ab7f88c4c83c9b (diff)
Menu: support searching through choices with /
when hitting / while in a menu, a regex filter can be entered so that only entries matching it are selectable, <esc> disable filtering while a second <esc> close the menu as usual.
Diffstat (limited to 'src')
-rw-r--r--src/client.cc103
1 files changed, 71 insertions, 32 deletions
diff --git a/src/client.cc b/src/client.cc
index eaa4774e..a40564a4 100644
--- a/src/client.cc
+++ b/src/client.cc
@@ -132,7 +132,8 @@ public:
Menu(Context& context, const memoryview<String>& choices,
MenuCallback callback)
: ClientMode(context.client()),
- m_callback(callback), m_choice_count(choices.size()), m_selected(0)
+ m_callback(callback), m_choices(choices.begin(), choices.end()),
+ m_selected(m_choices.begin())
{
DisplayCoord menu_pos{ context.window().dimensions().line, 0_char };
context.ui().menu_show(choices, menu_pos, MenuStyle::Prompt);
@@ -140,53 +141,91 @@ public:
void on_key(const Key& key, Context& context) override
{
- if (key == Key::Down or
- key == Key(Key::Modifiers::Control, 'i') or
- key == Key(Key::Modifiers::Control, 'n') or
- key == Key(Key::Modifiers::None, 'j'))
- {
- if (++m_selected >= m_choice_count)
- m_selected = 0;
- context.ui().menu_select(m_selected);
- }
- if (key == Key::Up or
- key == Key::BackTab or
- key == Key(Key::Modifiers::Control, 'p') or
- key == Key(Key::Modifiers::None, 'k'))
- {
- if (--m_selected < 0)
- m_selected = m_choice_count-1;
- context.ui().menu_select(m_selected);
- }
+ auto match_filter = [this](const String& str) {
+ return boost::regex_match(str.begin(), str.end(), m_filter);
+ };
+
if (key == Key(Key::Modifiers::Control, 'm'))
{
context.ui().menu_hide();
+ context.ui().print_status("");
// save callback as reset_normal_mode will delete this
MenuCallback callback = std::move(m_callback);
- int selected = m_selected;
+ int selected = m_selected - m_choices.begin();
reset_normal_mode();
callback(selected, context);
+ return;
}
- if (key == Key::Escape)
+ else if (key == Key::Escape)
{
- context.ui().menu_hide();
- reset_normal_mode();
+ if (m_edit_filter)
+ {
+ m_edit_filter = false;
+ m_filter = boost::regex(".*");
+ m_filter_editor.reset("");
+ context.ui().print_status("");
+ }
+ else
+ {
+ context.ui().menu_hide();
+ reset_normal_mode();
+ }
}
- if (key.modifiers == Key::Modifiers::None and
- key.key >= '0' and key.key <= '9')
+ else if (key == Key::Down or
+ key == Key(Key::Modifiers::Control, 'i') or
+ key == Key(Key::Modifiers::Control, 'n') or
+ key == Key(Key::Modifiers::None, 'j'))
{
- context.ui().menu_hide();
- // save callback as reset_normal_mode will delete this
- MenuCallback callback = std::move(m_callback);
- reset_normal_mode();
- callback(key.key - '0' - 1, context);
+ auto it = std::find_if(m_selected+1, m_choices.end(), match_filter);
+ if (it == m_choices.end())
+ it = std::find_if(m_choices.begin(), m_selected+1, match_filter);
+ m_selected = it;
+ context.ui().menu_select(m_selected - m_choices.begin());
+ }
+ else if (key == Key::Up or
+ key == Key::BackTab or
+ key == Key(Key::Modifiers::Control, 'p') or
+ key == Key(Key::Modifiers::None, 'k'))
+ {
+ ChoiceList::const_reverse_iterator selected(m_selected);
+ auto it = std::find_if(selected, m_choices.rend(), match_filter);
+ if (it == m_choices.rend())
+ it = std::find_if(m_choices.rbegin(), selected, match_filter);
+ m_selected = it.base()-1;
+ context.ui().menu_select(m_selected - m_choices.begin());
}
+ else if (key == '/' and not m_edit_filter)
+ {
+ m_edit_filter = true;
+ }
+ else if (m_edit_filter)
+ {
+ m_filter_editor.handle_key(key);
+
+ auto search = ".*" + m_filter_editor.line() + ".*";
+ m_filter = boost::regex(search.begin(), search.end());
+ auto it = std::find_if(m_selected, m_choices.end(), match_filter);
+ if (it == m_choices.end())
+ it = std::find_if(m_choices.begin(), m_selected, match_filter);
+ m_selected = it;
+ context.ui().menu_select(m_selected - m_choices.begin());
+ }
+
+ if (m_edit_filter)
+ context.ui().print_status("/" + m_filter_editor.line(),
+ m_filter_editor.cursor_pos() + 1);
}
private:
MenuCallback m_callback;
- int m_selected;
- int m_choice_count;
+
+ using ChoiceList = std::vector<String>;
+ const ChoiceList m_choices;
+ ChoiceList::const_iterator m_selected;
+
+ boost::regex m_filter = boost::regex(".*");
+ bool m_edit_filter = false;
+ LineEditor m_filter_editor;
};
class Prompt : public ClientMode