Use DisplayLine for menu choices

This commit is contained in:
Maxime Coste 2015-10-05 01:25:23 +01:00
parent 27606f7a75
commit c54e6738b9
9 changed files with 54 additions and 43 deletions

View File

@ -1406,12 +1406,12 @@ const CommandDesc menu_cmd = {
return; return;
} }
Vector<String> choices; Vector<DisplayLine> choices;
Vector<String> commands; Vector<String> commands;
Vector<String> select_cmds; Vector<String> select_cmds;
for (int i = 0; i < count; i += modulo) for (int i = 0; i < count; i += modulo)
{ {
choices.push_back(parser[i]); choices.push_back({ parser[i], {} });
commands.push_back(parser[i+1]); commands.push_back(parser[i+1]);
if (with_select_cmds) if (with_select_cmds)
select_cmds.push_back(parser[i+2]); select_cmds.push_back(parser[i+2]);

View File

@ -464,7 +464,7 @@ private:
class Menu : public InputMode class Menu : public InputMode
{ {
public: public:
Menu(InputHandler& input_handler, ConstArrayView<String> choices, Menu(InputHandler& input_handler, ConstArrayView<DisplayLine> choices,
MenuCallback callback) MenuCallback callback)
: InputMode(input_handler), : InputMode(input_handler),
m_callback(callback), m_choices(choices.begin(), choices.end()), m_callback(callback), m_choices(choices.begin(), choices.end()),
@ -479,8 +479,14 @@ public:
void on_key(Key key, KeepAlive keep_alive) override void on_key(Key key, KeepAlive keep_alive) override
{ {
auto match_filter = [this](const String& str) { auto match_filter = [this](const DisplayLine& choice) {
return regex_match(str.begin(), str.end(), m_filter); for (auto& atom : choice)
{
const auto& contents = atom.content();
if (regex_match(contents.begin(), contents.end(), m_filter))
return true;
}
return false;
}; };
if (key == ctrl('m')) if (key == ctrl('m'))
@ -564,7 +570,7 @@ public:
private: private:
MenuCallback m_callback; MenuCallback m_callback;
using ChoiceList = Vector<String>; using ChoiceList = Vector<DisplayLine>;
const ChoiceList m_choices; const ChoiceList m_choices;
ChoiceList::const_iterator m_selected; ChoiceList::const_iterator m_selected;
@ -823,10 +829,16 @@ private:
const String& line = m_line_editor.line(); const String& line = m_line_editor.line();
m_completions = m_completer(context(), flags, line, m_completions = m_completer(context(), flags, line,
line.byte_count_to(m_line_editor.cursor_pos())); line.byte_count_to(m_line_editor.cursor_pos()));
CandidateList& candidates = m_completions.candidates; if (context().has_ui() and not m_completions.candidates.empty())
if (context().has_ui() and not candidates.empty()) {
context().ui().menu_show(candidates, CharCoord{}, get_face("MenuForeground"), Vector<DisplayLine> items;
get_face("MenuBackground"), MenuStyle::Prompt); for (auto& candidate : m_completions.candidates)
items.push_back({ candidate, {} });
context().ui().menu_show(items, CharCoord{},
get_face("MenuForeground"),
get_face("MenuBackground"),
MenuStyle::Prompt);
}
} catch (runtime_error&) {} } catch (runtime_error&) {}
} }
@ -1280,7 +1292,7 @@ void InputHandler::set_prompt_face(Face prompt_face)
prompt->set_prompt_face(prompt_face); prompt->set_prompt_face(prompt_face);
} }
void InputHandler::menu(ConstArrayView<String> choices, MenuCallback callback) void InputHandler::menu(ConstArrayView<DisplayLine> choices, MenuCallback callback)
{ {
push_mode(new InputModes::Menu(*this, choices, callback)); push_mode(new InputModes::Menu(*this, choices, callback));
} }

View File

@ -62,7 +62,7 @@ public:
// abort or validation with corresponding MenuEvent value // abort or validation with corresponding MenuEvent value
// returns to normal mode after validation if callback does // returns to normal mode after validation if callback does
// not change the mode itself // not change the mode itself
void menu(ArrayView<const String> choices, MenuCallback callback); void menu(ConstArrayView<DisplayLine> choices, MenuCallback callback);
// execute callback on next keypress and returns to normal mode // execute callback on next keypress and returns to normal mode
// if callback does not change the mode itself // if callback does not change the mode itself

View File

@ -421,13 +421,13 @@ void InsertCompleter::menu_show()
const CharCount tabstop = m_options["tabstop"].get<int>(); const CharCount tabstop = m_options["tabstop"].get<int>();
const CharCount column = get_column(m_context.buffer(), tabstop, const CharCount column = get_column(m_context.buffer(), tabstop,
m_completions.begin); m_completions.begin);
Vector<String> menu_entries; Vector<DisplayLine> menu_entries;
for (auto& candidate : m_matching_candidates) for (auto& candidate : m_matching_candidates)
{ {
const String& entry = candidate.menu_entry.empty() ? const String& entry = candidate.menu_entry.empty() ?
candidate.completion : candidate.menu_entry; candidate.completion : candidate.menu_entry;
menu_entries.push_back(expand_tabs(entry, tabstop, column)); menu_entries.push_back({ expand_tabs(entry, tabstop, column), {} });
} }
m_context.ui().menu_show(menu_entries, menu_pos, m_context.ui().menu_show(menu_entries, menu_pos,

View File

@ -246,7 +246,8 @@ std::unique_ptr<UserInterface> create_local_ui(bool dummy_ui)
{ {
struct DummyUI : UserInterface struct DummyUI : UserInterface
{ {
void menu_show(ConstArrayView<String>, CharCoord, Face, Face, MenuStyle) override {} void menu_show(ConstArrayView<DisplayLine>, CharCoord,
Face, Face, MenuStyle) override {}
void menu_select(int) override {} void menu_select(int) override {}
void menu_hide() override {} void menu_hide() override {}

View File

@ -338,28 +338,29 @@ void add_str(WINDOW* win, StringView str)
waddnstr(win, str.begin(), (int)str.length()); waddnstr(win, str.begin(), (int)str.length());
} }
void NCursesUI::draw_line(const DisplayLine& line, CharCount col_index, static void draw_line(NCursesWin* window, const DisplayLine& line,
const Face& default_face) const CharCount col_index, CharCount max_column,
const Face& default_face)
{ {
for (const DisplayAtom& atom : line) for (const DisplayAtom& atom : line)
{ {
set_face(m_window, atom.face, default_face); set_face(window, atom.face, default_face);
StringView content = atom.content(); StringView content = atom.content();
if (content.empty()) if (content.empty())
continue; continue;
const auto remaining_columns = m_dimensions.column - col_index; const auto remaining_columns = max_column - col_index;
if (content.back() == '\n' and if (content.back() == '\n' and
content.char_length() - 1 < remaining_columns) content.char_length() - 1 < remaining_columns)
{ {
add_str(m_window, content.substr(0, content.length()-1)); add_str(window, content.substr(0, content.length()-1));
waddch(m_window, ' '); waddch(window, ' ');
} }
else else
{ {
content = content.substr(0_char, remaining_columns); content = content.substr(0_char, remaining_columns);
add_str(m_window, content); add_str(window, content);
col_index += content.char_length(); col_index += content.char_length();
} }
} }
@ -377,7 +378,7 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
{ {
wmove(m_window, (int)line_index, 0); wmove(m_window, (int)line_index, 0);
wclrtoeol(m_window); wclrtoeol(m_window);
draw_line(line, 0, default_face); draw_line(m_window, line, 0, m_dimensions.column, default_face);
++line_index; ++line_index;
} }
@ -402,7 +403,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line,
wbkgdset(m_window, COLOR_PAIR(get_color_pair(default_face))); wbkgdset(m_window, COLOR_PAIR(get_color_pair(default_face)));
wclrtoeol(m_window); wclrtoeol(m_window);
draw_line(status_line, 0, default_face); draw_line(m_window, status_line, 0, m_dimensions.column, default_face);
const auto mode_len = mode_line.length(); const auto mode_len = mode_line.length();
const auto remaining = m_dimensions.column - status_line.length(); const auto remaining = m_dimensions.column - status_line.length();
@ -410,7 +411,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line,
{ {
CharCount col = m_dimensions.column - mode_len; CharCount col = m_dimensions.column - mode_len;
wmove(m_window, status_line_pos, (int)col); wmove(m_window, status_line_pos, (int)col);
draw_line(mode_line, col, default_face); draw_line(m_window, mode_line, col, m_dimensions.column, default_face);
} }
else if (remaining > 2) else if (remaining > 2)
{ {
@ -421,7 +422,7 @@ void NCursesUI::draw_status(const DisplayLine& status_line,
CharCount col = m_dimensions.column - remaining + 1; CharCount col = m_dimensions.column - remaining + 1;
wmove(m_window, status_line_pos, (int)col); wmove(m_window, status_line_pos, (int)col);
draw_line(trimmed_mode_line, col, default_face); draw_line(m_window, trimmed_mode_line, col, m_dimensions.column, default_face);
} }
if (m_set_title) if (m_set_title)
@ -620,14 +621,12 @@ void NCursesUI::draw_menu()
+ col; + col;
if (item_idx >= item_count) if (item_idx >= item_count)
break; break;
if (item_idx == m_selected_item)
wattron(m_menu.win, COLOR_PAIR(menu_fg));
StringView item = m_items[item_idx].substr(0_char, column_width); const DisplayLine& item = m_items[item_idx];
add_str(m_menu.win, item); draw_line(m_menu.win, item, 0, column_width,
const CharCount pad = column_width - item.char_length(); item_idx == m_selected_item ? m_menu_fg : m_menu_bg);
const CharCount pad = column_width - item.length();
add_str(m_menu.win, String{' ' COMMA pad}); add_str(m_menu.win, String{' ' COMMA pad});
wattron(m_menu.win, COLOR_PAIR(menu_bg));
} }
const bool is_mark = line >= mark_line and const bool is_mark = line >= mark_line and
line < mark_line + mark_height; line < mark_line + mark_height;
@ -639,7 +638,7 @@ void NCursesUI::draw_menu()
m_dirty = true; m_dirty = true;
} }
void NCursesUI::menu_show(ConstArrayView<String> items, void NCursesUI::menu_show(ConstArrayView<DisplayLine> items,
CharCoord anchor, Face fg, Face bg, CharCoord anchor, Face fg, Face bg,
MenuStyle style) MenuStyle style)
{ {
@ -664,8 +663,9 @@ void NCursesUI::menu_show(ConstArrayView<String> items,
const CharCount maxlen = min((int)maxsize.column-2, 200); const CharCount maxlen = min((int)maxsize.column-2, 200);
for (auto& item : items) for (auto& item : items)
{ {
m_items.push_back(item.substr(0_char, maxlen).str()); m_items.push_back(item);
longest = max(longest, m_items.back().char_length()); m_items.back().trim(0, maxlen, false);
longest = max(longest, m_items.back().length());
} }
longest += 1; longest += 1;

View File

@ -31,7 +31,7 @@ public:
bool is_key_available() override; bool is_key_available() override;
Key get_key() override; Key get_key() override;
void menu_show(ConstArrayView<String> items, void menu_show(ConstArrayView<DisplayLine> items,
CharCoord anchor, Face fg, Face bg, CharCoord anchor, Face fg, Face bg,
MenuStyle style) override; MenuStyle style) override;
void menu_select(int selected) override; void menu_select(int selected) override;
@ -54,8 +54,6 @@ public:
private: private:
void check_resize(bool force = false); void check_resize(bool force = false);
void redraw(); void redraw();
void draw_line(const DisplayLine& line, CharCount col_index,
const Face& default_face) const;
NCursesWin* m_window = nullptr; NCursesWin* m_window = nullptr;
@ -77,7 +75,7 @@ private:
void mark_dirty(const Window& win); void mark_dirty(const Window& win);
Window m_menu; Window m_menu;
Vector<String> m_items; Vector<DisplayLine> m_items;
Face m_menu_fg; Face m_menu_fg;
Face m_menu_bg; Face m_menu_bg;
int m_selected_item = 0; int m_selected_item = 0;

View File

@ -237,7 +237,7 @@ public:
RemoteUI(int socket); RemoteUI(int socket);
~RemoteUI(); ~RemoteUI();
void menu_show(ConstArrayView<String> choices, void menu_show(ConstArrayView<DisplayLine> choices,
CharCoord anchor, Face fg, Face bg, CharCoord anchor, Face fg, Face bg,
MenuStyle style) override; MenuStyle style) override;
void menu_select(int selected) override; void menu_select(int selected) override;
@ -287,7 +287,7 @@ RemoteUI::~RemoteUI()
m_socket_watcher.close_fd(); m_socket_watcher.close_fd();
} }
void RemoteUI::menu_show(ConstArrayView<String> choices, void RemoteUI::menu_show(ConstArrayView<DisplayLine> choices,
CharCoord anchor, Face fg, Face bg, CharCoord anchor, Face fg, Face bg,
MenuStyle style) MenuStyle style)
{ {
@ -468,7 +468,7 @@ void RemoteClient::process_next_message()
{ {
case RemoteUIMsg::MenuShow: case RemoteUIMsg::MenuShow:
{ {
auto choices = read_vector<String>(socket); auto choices = read_vector<DisplayLine>(socket);
auto anchor = read<CharCoord>(socket); auto anchor = read<CharCoord>(socket);
auto fg = read<Face>(socket); auto fg = read<Face>(socket);
auto bg = read<Face>(socket); auto bg = read<Face>(socket);

View File

@ -41,7 +41,7 @@ class UserInterface : public SafeCountable
public: public:
virtual ~UserInterface() {} virtual ~UserInterface() {}
virtual void menu_show(ConstArrayView<String> choices, virtual void menu_show(ConstArrayView<DisplayLine> choices,
CharCoord anchor, Face fg, Face bg, CharCoord anchor, Face fg, Face bg,
MenuStyle style) = 0; MenuStyle style) = 0;
virtual void menu_select(int selected) = 0; virtual void menu_select(int selected) = 0;