Use DisplayLine for menu choices
This commit is contained in:
parent
27606f7a75
commit
c54e6738b9
|
@ -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]);
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user