Pass title to UserInterface::info_show
Move unicode box generation and assistant code as a NcursesUI implementation detail.
This commit is contained in:
parent
93f6a2ee43
commit
3c959cee99
|
@ -543,7 +543,7 @@ public:
|
|||
void menu_select(int) override {}
|
||||
void menu_hide() override {}
|
||||
|
||||
void info_show(const String&, DisplayCoord, ColorPair, MenuStyle) override {}
|
||||
void info_show(const String&, const String&, DisplayCoord, ColorPair, MenuStyle) override {}
|
||||
void info_hide() override {}
|
||||
|
||||
void draw(const DisplayBuffer&, const DisplayLine&, const DisplayLine&) override {}
|
||||
|
@ -642,88 +642,17 @@ void menu(CommandParameters params, Context& context)
|
|||
});
|
||||
}
|
||||
|
||||
static String assist(String message, CharCount maxWidth)
|
||||
{
|
||||
static const std::vector<String> assistant =
|
||||
{ " ╭──╮ ",
|
||||
" │ │ ",
|
||||
" @ @ ╭",
|
||||
" ││ ││ │",
|
||||
" ││ ││ ╯",
|
||||
" │╰─╯│ ",
|
||||
" ╰───╯ ",
|
||||
" " };
|
||||
|
||||
const CharCount maxBubbleWidth = maxWidth - assistant[0].char_length() - 6;
|
||||
CharCount bubbleWidth = 0;
|
||||
std::vector<String> lines;
|
||||
{
|
||||
using Utf8It = utf8::utf8_iterator<String::iterator>;
|
||||
Utf8It word_begin{message.begin()};
|
||||
Utf8It word_end{word_begin};
|
||||
Utf8It end{message.end()};
|
||||
CharCount col = 0;
|
||||
String line;
|
||||
while (word_begin != end)
|
||||
{
|
||||
do
|
||||
{
|
||||
++word_end;
|
||||
} while (word_end != end and not is_blank(*word_end) and not is_eol(*word_end));
|
||||
|
||||
col += word_end - word_begin;
|
||||
if (col > maxBubbleWidth or *word_begin == '\n')
|
||||
{
|
||||
bubbleWidth = std::max(bubbleWidth, line.char_length());
|
||||
lines.push_back(std::move(line));
|
||||
line = "";
|
||||
col = 0;
|
||||
}
|
||||
if (*word_begin != '\n')
|
||||
line += String{word_begin.base(), word_end.base()};
|
||||
word_begin = word_end;
|
||||
}
|
||||
if (not line.empty())
|
||||
{
|
||||
bubbleWidth = std::max(bubbleWidth, line.char_length());
|
||||
lines.push_back(std::move(line));
|
||||
}
|
||||
}
|
||||
|
||||
String result;
|
||||
LineCount lineCount{std::max<int>(assistant.size()-1, lines.size() + 2)};
|
||||
for (LineCount i = 0; i < lineCount; ++i)
|
||||
{
|
||||
|
||||
result += assistant[std::min((int)i, (int)assistant.size()-1)];
|
||||
if (i == 0)
|
||||
result += "╭─" + String(Codepoint{L'─'}, bubbleWidth) + "─╮";
|
||||
else if (i < lines.size() + 1)
|
||||
{
|
||||
auto& line = lines[(int)i - 1];
|
||||
const CharCount padding = std::max(bubbleWidth - line.char_length(), 0_char);
|
||||
result += "│ " + line + String(' ', padding) + " │";
|
||||
}
|
||||
else if (i == lines.size() + 1)
|
||||
result += "╰─" + String(Codepoint{L'─'}, bubbleWidth) + "─╯";
|
||||
|
||||
result += "\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void info(CommandParameters params, Context& context)
|
||||
{
|
||||
ParametersParser parser(params, { { "anchor", true }, { "assist", false } },
|
||||
ParametersParser parser(params, { { "anchor", true }, { "title", true } },
|
||||
ParametersParser::Flags::None, 0, 1);
|
||||
|
||||
context.ui().info_hide();
|
||||
if (parser.positional_count() > 0)
|
||||
{
|
||||
MenuStyle style = MenuStyle::Prompt;
|
||||
DisplayCoord dimensions = context.ui().dimensions();
|
||||
DisplayCoord pos = { dimensions.line, 0 };
|
||||
DisplayCoord pos = context.ui().dimensions();
|
||||
pos.column -= 1;
|
||||
if (parser.has_option("anchor"))
|
||||
{
|
||||
style = MenuStyle::Inline;
|
||||
|
@ -738,8 +667,8 @@ void info(CommandParameters params, Context& context)
|
|||
throw runtime_error("anchor param must be one of [left, right, cursor]");
|
||||
pos = context.window().display_position(it);
|
||||
}
|
||||
const String& message = parser.has_option("assist") ? assist(parser[0], dimensions.column) : parser[0];
|
||||
context.ui().info_show(message, pos, get_color("Information"), style);
|
||||
const String& title = parser.has_option("title") ? parser.option_value("title") : "";
|
||||
context.ui().info_show(title, parser[0], pos, get_color("Information"), style);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
110
src/ncurses.cc
110
src/ncurses.cc
|
@ -534,14 +534,112 @@ static DisplayCoord compute_pos(DisplayCoord anchor,
|
|||
return pos;
|
||||
}
|
||||
|
||||
void NCursesUI::info_show(const String& content, DisplayCoord anchor,
|
||||
ColorPair colors, MenuStyle style)
|
||||
static std::vector<String> wrap_lines(const String& text, CharCount max_width)
|
||||
{
|
||||
enum CharCategory { Word, Blank, Eol };
|
||||
static const auto categorize = [](Codepoint c) {
|
||||
return is_blank(c) ? Blank
|
||||
: is_eol(c) ? Eol : Word;
|
||||
};
|
||||
|
||||
using Utf8It = utf8::utf8_iterator<String::const_iterator>;
|
||||
Utf8It word_begin{text.begin()};
|
||||
Utf8It word_end{word_begin};
|
||||
Utf8It end{text.end()};
|
||||
CharCount col = 0;
|
||||
std::vector<String> lines;
|
||||
String line;
|
||||
while (word_begin != end)
|
||||
{
|
||||
CharCategory cat = categorize(*word_begin);
|
||||
do
|
||||
{
|
||||
++word_end;
|
||||
} while (word_end != end and categorize(*word_end) == cat);
|
||||
|
||||
col += word_end - word_begin;
|
||||
if (col > max_width or *word_begin == '\n')
|
||||
{
|
||||
lines.push_back(std::move(line));
|
||||
line = "";
|
||||
col = 0;
|
||||
}
|
||||
if (*word_begin != '\n')
|
||||
line += String{word_begin.base(), word_end.base()};
|
||||
word_begin = word_end;
|
||||
}
|
||||
if (not line.empty())
|
||||
lines.push_back(std::move(line));
|
||||
return lines;
|
||||
}
|
||||
|
||||
template<bool assist = true>
|
||||
static String make_info_box(const String& title, const String& message,
|
||||
CharCount max_width)
|
||||
{
|
||||
static const std::vector<String> assistant =
|
||||
{ " ╭──╮ ",
|
||||
" │ │ ",
|
||||
" @ @ ╭",
|
||||
" ││ ││ │",
|
||||
" ││ ││ ╯",
|
||||
" │╰─╯│ ",
|
||||
" ╰───╯ ",
|
||||
" " };
|
||||
DisplayCoord assistant_size;
|
||||
if (assist)
|
||||
assistant_size = { (int)assistant.size(), assistant[0].char_length() };
|
||||
|
||||
const CharCount max_bubble_width = max_width - assistant_size.column - 6;
|
||||
std::vector<String> lines = wrap_lines(message, max_bubble_width);
|
||||
|
||||
CharCount bubble_width = title.char_length() + 2;
|
||||
for (auto& line : lines)
|
||||
bubble_width = std::max(bubble_width, line.char_length());
|
||||
|
||||
String result;
|
||||
auto lineCount = std::max<LineCount>(assistant_size.line-1, (int)lines.size() + 2);
|
||||
for (LineCount i = 0; i < lineCount; ++i)
|
||||
{
|
||||
constexpr Codepoint dash{L'─'};
|
||||
if (assist)
|
||||
result += assistant[std::min((int)i, (int)assistant_size.line-1)];
|
||||
if (i == 0)
|
||||
{
|
||||
if (title.empty())
|
||||
result += "╭─" + String(dash, bubble_width) + "─╮";
|
||||
else
|
||||
{
|
||||
CharCount dashCount = bubble_width - title.char_length() - 2_char;
|
||||
CharCount leftCount = dashCount / 2;
|
||||
CharCount rightCount= dashCount - leftCount;
|
||||
result += "╭─" + String(dash, leftCount) + "┤" + title +"├" + String(dash, rightCount) +"─╮";
|
||||
}
|
||||
}
|
||||
else if (i < lines.size() + 1)
|
||||
{
|
||||
auto& line = lines[(int)i - 1];
|
||||
const CharCount padding = std::max(bubble_width - line.char_length(), 0_char);
|
||||
result += "│ " + line + String(' ', padding) + " │";
|
||||
}
|
||||
else if (i == lines.size() + 1)
|
||||
result += "╰─" + String(dash, bubble_width) + "─╯";
|
||||
|
||||
result += "\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void NCursesUI::info_show(const String& title, const String& content,
|
||||
DisplayCoord anchor, ColorPair colors,
|
||||
MenuStyle style)
|
||||
{
|
||||
kak_assert(m_info_win == nullptr);
|
||||
|
||||
DisplayCoord size = compute_needed_size(content);
|
||||
if (style == MenuStyle::Prompt)
|
||||
size.column = window_size(stdscr).column - anchor.column;
|
||||
const String& info_box = style == MenuStyle::Inline ?
|
||||
content : make_info_box(title, content, m_dimensions.column);
|
||||
|
||||
DisplayCoord size = compute_needed_size(info_box);
|
||||
|
||||
DisplayCoord pos = compute_pos(anchor, size, m_menu_win);
|
||||
|
||||
|
@ -550,7 +648,7 @@ void NCursesUI::info_show(const String& content, DisplayCoord anchor,
|
|||
|
||||
wbkgd(m_info_win, COLOR_PAIR(get_color_pair(colors)));
|
||||
int line = 0;
|
||||
auto it = content.begin(), end = content.end();
|
||||
auto it = info_box.begin(), end = info_box.end();
|
||||
while (true)
|
||||
{
|
||||
wmove(m_info_win, line++, 0);
|
||||
|
|
|
@ -32,8 +32,9 @@ public:
|
|||
void menu_select(int selected) override;
|
||||
void menu_hide() override;
|
||||
|
||||
void info_show(const String& content, DisplayCoord anchor,
|
||||
ColorPair colors, MenuStyle style) override;
|
||||
void info_show(const String& title, const String& content,
|
||||
DisplayCoord anchor, ColorPair colors,
|
||||
MenuStyle style) override;
|
||||
void info_hide() override;
|
||||
|
||||
void set_input_callback(InputCallback callback) override;
|
||||
|
|
|
@ -33,21 +33,23 @@ void repeat_insert(Context& context, int)
|
|||
context.client().repeat_last_insert();
|
||||
}
|
||||
|
||||
bool show_auto_info_ifn(const String& info, const Context& context)
|
||||
bool show_auto_info_ifn(const String& title, const String& info,
|
||||
const Context& context)
|
||||
{
|
||||
if (not context.options()["autoinfo"].get<bool>() or not context.has_ui())
|
||||
return false;
|
||||
ColorPair col = get_color("Information");
|
||||
DisplayCoord pos = context.window().dimensions();
|
||||
pos.column -= 1;
|
||||
context.ui().info_show(info, pos , col, MenuStyle::Inline);
|
||||
context.ui().info_show(title, info, pos , col, MenuStyle::Prompt);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Cmd>
|
||||
void on_next_key_with_autoinfo(const Context& context, Cmd cmd, const std::string& info)
|
||||
void on_next_key_with_autoinfo(const Context& context, Cmd cmd,
|
||||
const String& title, const String& info)
|
||||
{
|
||||
const bool hide = show_auto_info_ifn(info, context);
|
||||
const bool hide = show_auto_info_ifn(title, info, context);
|
||||
context.client().on_next_key([hide,cmd](Key key, Context& context) mutable {
|
||||
if (hide)
|
||||
context.ui().info_hide();
|
||||
|
@ -152,19 +154,17 @@ void goto_commands(Context& context, int line)
|
|||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"╭────────┤goto├───────╮\n"
|
||||
"│ g,k: buffer top │\n"
|
||||
"│ l: line end │\n"
|
||||
"│ h: line begin │\n"
|
||||
"│ j: buffer bottom │\n"
|
||||
"│ e: buffer end │\n"
|
||||
"│ t: window top │\n"
|
||||
"│ b: window bottom │\n"
|
||||
"│ c: window center │\n"
|
||||
"│ a: last buffer │\n"
|
||||
"│ f: file │\n"
|
||||
"╰─────────────────────╯\n");
|
||||
}, "goto",
|
||||
"g,k: buffer top \n"
|
||||
"l: line end \n"
|
||||
"h: line begin \n"
|
||||
"j: buffer bottom\n"
|
||||
"e: buffer end \n"
|
||||
"t: window top \n"
|
||||
"b: window bottom\n"
|
||||
"c: window center\n"
|
||||
"a: last buffer \n"
|
||||
"f: file \n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,16 +200,14 @@ void view_commands(Context& context, int param)
|
|||
context.window().scroll( std::max<CharCount>(1, param));
|
||||
break;
|
||||
}
|
||||
},
|
||||
"╭─────────┤view├─────────╮\n"
|
||||
"│ v,c: center cursor │\n"
|
||||
"│ t: cursor on top │\n"
|
||||
"│ b: cursor on bottom │\n"
|
||||
"│ h: scroll left │\n"
|
||||
"│ j: scroll down │\n"
|
||||
"│ k: scroll up │\n"
|
||||
"│ l: scroll right │\n"
|
||||
"╰────────────────────────╯\n");
|
||||
}, "view",
|
||||
"v,c: center cursor \n"
|
||||
"t: cursor on top \n"
|
||||
"b: cursor on bottom\n"
|
||||
"h: scroll left \n"
|
||||
"j: scroll down \n"
|
||||
"k: scroll up \n"
|
||||
"l: scroll right \n");
|
||||
}
|
||||
|
||||
void replace_with_char(Context& context, int)
|
||||
|
@ -222,10 +220,7 @@ void replace_with_char(Context& context, int)
|
|||
auto restore_sels = on_scope_end([&]{ editor.select(std::move(sels)); });
|
||||
editor.multi_select(std::bind(select_all_matches, _1, _2, Regex{"."}));
|
||||
editor.insert(codepoint_to_str(key.key), InsertMode::Replace);
|
||||
},
|
||||
"╭────┤replace with char├─────╮\n"
|
||||
"│ enter char to replace with │\n"
|
||||
"╰────────────────────────────╯\n");
|
||||
}, "replace with char", "enter char to replace with\n");
|
||||
}
|
||||
|
||||
Codepoint to_lower(Codepoint cp) { return tolower(cp); }
|
||||
|
@ -620,20 +615,18 @@ void select_object(Context& context, int param)
|
|||
return context.editor().select(std::bind(select_surrounding, _1, _2,
|
||||
sur.pair, level, flags));
|
||||
}
|
||||
},
|
||||
"╭──────┤select object├───────╮\n"
|
||||
"│ b,(,): parenthesis block │\n"
|
||||
"│ B,{,}: braces block │\n"
|
||||
"│ r,[,]: brackets block │\n"
|
||||
"│ <,>: angle block │\n"
|
||||
"│ \": double quote string │\n"
|
||||
"│ ': single quote string │\n"
|
||||
"│ w: word │\n"
|
||||
"│ W: WORD │\n"
|
||||
"│ s: sentence │\n"
|
||||
"│ p: paragraph │\n"
|
||||
"│ i: indent │\n"
|
||||
"╰────────────────────────────╯\n");
|
||||
}, "select object",
|
||||
"b,(,): parenthesis block\n"
|
||||
"B,{,}: braces block \n"
|
||||
"r,[,]: brackets block \n"
|
||||
"<,>: angle block \n"
|
||||
"\": double quote string\n"
|
||||
"': single quote string\n"
|
||||
"w: word \n"
|
||||
"W: WORD \n"
|
||||
"s: sentence \n"
|
||||
"p: paragraph \n"
|
||||
"i: indent \n");
|
||||
}
|
||||
|
||||
template<Key::NamedKey key>
|
||||
|
@ -704,10 +697,7 @@ void select_to_next_char(Context& context, int param)
|
|||
std::bind(flags & SelectFlags::Reverse ? select_to_reverse : select_to,
|
||||
_1, _2, key.key, param, flags & SelectFlags::Inclusive),
|
||||
flags & SelectFlags::Extend ? SelectMode::Extend : SelectMode::Replace);
|
||||
},
|
||||
"╭──┤select to next char├──╮\n"
|
||||
"│ enter char to select to │\n"
|
||||
"╰─────────────────────────╯\n");
|
||||
}, "select to next char","enter char to select to");
|
||||
}
|
||||
|
||||
void start_or_end_macro_recording(Context& context, int)
|
||||
|
@ -719,10 +709,7 @@ void start_or_end_macro_recording(Context& context, int)
|
|||
if (key.modifiers == Key::Modifiers::None and
|
||||
key.key >= 'a' and key.key <= 'z')
|
||||
context.client().start_recording(key.key);
|
||||
},
|
||||
"╭──┤record macro├──╮\n"
|
||||
"│ enter macro name │\n"
|
||||
"╰──────────────────╯\n");
|
||||
}, "record macro", "enter macro name ");
|
||||
}
|
||||
|
||||
void replay_macro(Context& context, int count)
|
||||
|
@ -745,10 +732,7 @@ void replay_macro(Context& context, int count)
|
|||
do { exec_keys(keys, context); } while (--count > 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
"╭──┤replay macro├──╮\n"
|
||||
"│ enter macro name │\n"
|
||||
"╰──────────────────╯\n");
|
||||
}, "replay macro", "enter macro name");
|
||||
}
|
||||
|
||||
template<Direction direction>
|
||||
|
|
|
@ -222,8 +222,9 @@ public:
|
|||
void menu_select(int selected) override;
|
||||
void menu_hide() override;
|
||||
|
||||
void info_show(const String& content, DisplayCoord anchor,
|
||||
ColorPair colors, MenuStyle style) override;
|
||||
void info_show(const String& title, const String& content,
|
||||
DisplayCoord anchor, ColorPair colors,
|
||||
MenuStyle style) override;
|
||||
void info_hide() override;
|
||||
|
||||
void draw(const DisplayBuffer& display_buffer,
|
||||
|
@ -281,11 +282,13 @@ void RemoteUI::menu_hide()
|
|||
msg.write(RemoteUIMsg::MenuHide);
|
||||
}
|
||||
|
||||
void RemoteUI::info_show(const String& content, DisplayCoord anchor,
|
||||
ColorPair colors, MenuStyle style)
|
||||
void RemoteUI::info_show(const String& title, const String& content,
|
||||
DisplayCoord anchor, ColorPair colors,
|
||||
MenuStyle style)
|
||||
{
|
||||
Message msg(m_socket_watcher.fd());
|
||||
msg.write(RemoteUIMsg::InfoShow);
|
||||
msg.write(title);
|
||||
msg.write(content);
|
||||
msg.write(anchor);
|
||||
msg.write(colors);
|
||||
|
@ -396,11 +399,12 @@ void RemoteClient::process_next_message()
|
|||
break;
|
||||
case RemoteUIMsg::InfoShow:
|
||||
{
|
||||
auto choices = read<String>(socket);
|
||||
auto title = read<String>(socket);
|
||||
auto content = read<String>(socket);
|
||||
auto anchor = read<DisplayCoord>(socket);
|
||||
auto colors = read<ColorPair>(socket);
|
||||
auto style = read<MenuStyle>(socket);
|
||||
m_ui->info_show(choices, anchor, colors, style);
|
||||
m_ui->info_show(title, content, anchor, colors, style);
|
||||
break;
|
||||
}
|
||||
case RemoteUIMsg::InfoHide:
|
||||
|
|
|
@ -33,8 +33,9 @@ public:
|
|||
virtual void menu_select(int selected) = 0;
|
||||
virtual void menu_hide() = 0;
|
||||
|
||||
virtual void info_show(const String& content, DisplayCoord anchor,
|
||||
ColorPair colors, MenuStyle style) = 0;
|
||||
virtual void info_show(const String& title, const String& content,
|
||||
DisplayCoord anchor, ColorPair colors,
|
||||
MenuStyle style) = 0;
|
||||
virtual void info_hide() = 0;
|
||||
|
||||
virtual void draw(const DisplayBuffer& display_buffer,
|
||||
|
|
Loading…
Reference in New Issue
Block a user