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;
}
Vector<String> choices;
Vector<DisplayLine> choices;
Vector<String> commands;
Vector<String> select_cmds;
for (int i = 0; i < count; i += modulo)
{
choices.push_back(parser[i]);
choices.push_back({ parser[i], {} });
commands.push_back(parser[i+1]);
if (with_select_cmds)
select_cmds.push_back(parser[i+2]);

View File

@ -464,7 +464,7 @@ private:
class Menu : public InputMode
{
public:
Menu(InputHandler& input_handler, ConstArrayView<String> choices,
Menu(InputHandler& input_handler, ConstArrayView<DisplayLine> choices,
MenuCallback callback)
: InputMode(input_handler),
m_callback(callback), m_choices(choices.begin(), choices.end()),
@ -479,8 +479,14 @@ public:
void on_key(Key key, KeepAlive keep_alive) override
{
auto match_filter = [this](const String& str) {
return regex_match(str.begin(), str.end(), m_filter);
auto match_filter = [this](const DisplayLine& choice) {
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'))
@ -564,7 +570,7 @@ public:
private:
MenuCallback m_callback;
using ChoiceList = Vector<String>;
using ChoiceList = Vector<DisplayLine>;
const ChoiceList m_choices;
ChoiceList::const_iterator m_selected;
@ -823,10 +829,16 @@ private:
const String& line = m_line_editor.line();
m_completions = m_completer(context(), flags, line,
line.byte_count_to(m_line_editor.cursor_pos()));
CandidateList& candidates = m_completions.candidates;
if (context().has_ui() and not candidates.empty())
context().ui().menu_show(candidates, CharCoord{}, get_face("MenuForeground"),
get_face("MenuBackground"), MenuStyle::Prompt);
if (context().has_ui() and not m_completions.candidates.empty())
{
Vector<DisplayLine> items;
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&) {}
}
@ -1280,7 +1292,7 @@ void InputHandler::set_prompt_face(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));
}

View File

@ -62,7 +62,7 @@ public:
// abort or validation with corresponding MenuEvent value
// returns to normal mode after validation if callback does
// 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
// 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 column = get_column(m_context.buffer(), tabstop,
m_completions.begin);
Vector<String> menu_entries;
Vector<DisplayLine> menu_entries;
for (auto& candidate : m_matching_candidates)
{
const String& entry = candidate.menu_entry.empty() ?
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,

View File

@ -246,7 +246,8 @@ std::unique_ptr<UserInterface> create_local_ui(bool dummy_ui)
{
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_hide() override {}

View File

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

View File

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

View File

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

View File

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