UserInterface: status line messages are now DisplayLines
This add color support for the status line
This commit is contained in:
parent
6ffdfd7735
commit
f540566b1b
|
@ -407,7 +407,10 @@ there are some builtins color aliases:
|
||||||
* +LineNumbers+: colors used by the number_lines highlighter
|
* +LineNumbers+: colors used by the number_lines highlighter
|
||||||
* +MenuForeground+: colors for the selected element in menus
|
* +MenuForeground+: colors for the selected element in menus
|
||||||
* +MenuBackground+: colors for the not selected elements in menus
|
* +MenuBackground+: colors for the not selected elements in menus
|
||||||
* +Information+: colors the informations windows
|
* +Information+: colors the informations windows and information messages
|
||||||
|
* +Error+: colors of error messages
|
||||||
|
* +StatusLine+: colors used for the status line
|
||||||
|
* +StatusCursor+: colors used for the status line cursor
|
||||||
|
|
||||||
Shell expansion
|
Shell expansion
|
||||||
---------------
|
---------------
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "buffer_manager.hh"
|
#include "buffer_manager.hh"
|
||||||
#include "command_manager.hh"
|
#include "command_manager.hh"
|
||||||
#include "file.hh"
|
#include "file.hh"
|
||||||
|
#include "color_registry.hh"
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
@ -64,7 +65,7 @@ void ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
|
||||||
}
|
}
|
||||||
catch (Kakoune::runtime_error& error)
|
catch (Kakoune::runtime_error& error)
|
||||||
{
|
{
|
||||||
context->print_status(error.description());
|
context->print_status({ error.description(), get_color("Error") });
|
||||||
context->hooks().run_hook("RuntimeError", error.description(), *context);
|
context->hooks().run_hook("RuntimeError", error.description(), *context);
|
||||||
}
|
}
|
||||||
catch (Kakoune::client_removed&)
|
catch (Kakoune::client_removed&)
|
||||||
|
@ -81,7 +82,7 @@ void ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
|
||||||
}
|
}
|
||||||
catch (Kakoune::runtime_error& error)
|
catch (Kakoune::runtime_error& error)
|
||||||
{
|
{
|
||||||
context->print_status(error.description());
|
context->print_status({ error.description(), get_color("Error") });
|
||||||
context->hooks().run_hook("RuntimeError", error.description(), *context);
|
context->hooks().run_hook("RuntimeError", error.description(), *context);
|
||||||
}
|
}
|
||||||
catch (Kakoune::client_removed&)
|
catch (Kakoune::client_removed&)
|
||||||
|
@ -191,7 +192,7 @@ Context& ClientManager::get_client_context(const String& name)
|
||||||
throw runtime_error("no client named: " + name);
|
throw runtime_error("no client named: " + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String generate_status_line(const Context& context)
|
static DisplayLine generate_status_line(const Context& context)
|
||||||
{
|
{
|
||||||
BufferCoord cursor = context.editor().main_selection().last().coord();
|
BufferCoord cursor = context.editor().main_selection().last().coord();
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
@ -207,7 +208,7 @@ static String generate_status_line(const Context& context)
|
||||||
oss << " [" << context.editor().selections().size() << " sel]";
|
oss << " [" << context.editor().selections().size() << " sel]";
|
||||||
if (context.editor().is_editing())
|
if (context.editor().is_editing())
|
||||||
oss << " [insert]";
|
oss << " [insert]";
|
||||||
return oss.str();
|
return { oss.str(), get_color("StatusLine") };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientManager::redraw_clients() const
|
void ClientManager::redraw_clients() const
|
||||||
|
|
|
@ -49,6 +49,9 @@ ColorRegistry::ColorRegistry()
|
||||||
{ "MenuForeground", { Color::Blue, Color::Cyan } },
|
{ "MenuForeground", { Color::Blue, Color::Cyan } },
|
||||||
{ "MenuBackground", { Color::Cyan, Color::Blue } },
|
{ "MenuBackground", { Color::Cyan, Color::Blue } },
|
||||||
{ "Information", { Color::Black, Color::Yellow } },
|
{ "Information", { Color::Black, Color::Yellow } },
|
||||||
|
{ "Error", { Color::Black, Color::Red } },
|
||||||
|
{ "StatusLine", { Color::Cyan, Color::Default } },
|
||||||
|
{ "StatusCursor", { Color::Black, Color::Cyan } },
|
||||||
}
|
}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ Buffer* open_or_create(const String& filename, Context& context)
|
||||||
Buffer* buffer = create_buffer_from_file(filename);
|
Buffer* buffer = create_buffer_from_file(filename);
|
||||||
if (not buffer)
|
if (not buffer)
|
||||||
{
|
{
|
||||||
context.print_status("new file " + filename);
|
context.print_status({ "new file " + filename, get_color("StatusLine") });
|
||||||
buffer = new Buffer(filename, Buffer::Flags::File | Buffer::Flags::New);
|
buffer = new Buffer(filename, Buffer::Flags::File | Buffer::Flags::New);
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer;
|
||||||
|
@ -424,7 +424,7 @@ void echo_message(const CommandParameters& params, Context& context)
|
||||||
String message;
|
String message;
|
||||||
for (auto& param : params)
|
for (auto& param : params)
|
||||||
message += param + " ";
|
message += param + " ";
|
||||||
context.print_status(message);
|
context.print_status({ std::move(message), get_color("StatusLine") } );
|
||||||
}
|
}
|
||||||
|
|
||||||
void exec_commands_in_file(const CommandParameters& params,
|
void exec_commands_in_file(const CommandParameters& params,
|
||||||
|
@ -803,8 +803,8 @@ public:
|
||||||
}
|
}
|
||||||
bool is_key_available() override { return m_pos < m_keys.size(); }
|
bool is_key_available() override { return m_pos < m_keys.size(); }
|
||||||
|
|
||||||
void print_status(const String& , CharCount) override {}
|
void print_status(const DisplayLine&) override {}
|
||||||
void draw(const DisplayBuffer&, const String&) override {}
|
void draw(const DisplayBuffer&, const DisplayLine&) override {}
|
||||||
void menu_show(const memoryview<String>&,
|
void menu_show(const memoryview<String>&,
|
||||||
DisplayCoord, ColorPair, ColorPair, MenuStyle) override {}
|
DisplayCoord, ColorPair, ColorPair, MenuStyle) override {}
|
||||||
void menu_select(int) override {}
|
void menu_select(int) override {}
|
||||||
|
|
|
@ -95,7 +95,7 @@ struct Context
|
||||||
return GlobalHooks::instance();
|
return GlobalHooks::instance();
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_status(const String& status) const
|
void print_status(const DisplayLine& status) const
|
||||||
{
|
{
|
||||||
if (has_ui())
|
if (has_ui())
|
||||||
ui().print_status(status);
|
ui().print_status(status);
|
||||||
|
|
|
@ -42,6 +42,14 @@ void DisplayLine::optimize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharCount DisplayLine::length() const
|
||||||
|
{
|
||||||
|
CharCount len = 0;
|
||||||
|
for (auto& atom : m_atoms)
|
||||||
|
len += atom.content.length();
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayBuffer::compute_range()
|
void DisplayBuffer::compute_range()
|
||||||
{
|
{
|
||||||
m_range.first = BufferIterator();
|
m_range.first = BufferIterator();
|
||||||
|
|
|
@ -112,12 +112,13 @@ struct DisplayAtom
|
||||||
{
|
{
|
||||||
ColorPair colors;
|
ColorPair colors;
|
||||||
Attribute attribute;
|
Attribute attribute;
|
||||||
|
|
||||||
AtomContent content;
|
AtomContent content;
|
||||||
|
|
||||||
DisplayAtom(AtomContent content)
|
DisplayAtom(AtomContent content,
|
||||||
: content{std::move(content)}, attribute{Normal},
|
ColorPair colors = {Color::Default, Color::Default},
|
||||||
colors{Color::Default, Color::Default} {}
|
Attribute attribute = Normal)
|
||||||
|
: content{std::move(content)}, colors{colors}, attribute{attribute}
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DisplayLine
|
class DisplayLine
|
||||||
|
@ -130,6 +131,8 @@ public:
|
||||||
explicit DisplayLine(LineCount buffer_line) : m_buffer_line(buffer_line) {}
|
explicit DisplayLine(LineCount buffer_line) : m_buffer_line(buffer_line) {}
|
||||||
DisplayLine(LineCount buffer_line, AtomList atoms)
|
DisplayLine(LineCount buffer_line, AtomList atoms)
|
||||||
: m_buffer_line(buffer_line), m_atoms(std::move(atoms)) {}
|
: m_buffer_line(buffer_line), m_atoms(std::move(atoms)) {}
|
||||||
|
DisplayLine(String str, ColorPair color)
|
||||||
|
: m_buffer_line(-1), m_atoms{ { std::move(str), color } } {}
|
||||||
|
|
||||||
LineCount buffer_line() const { return m_buffer_line; }
|
LineCount buffer_line() const { return m_buffer_line; }
|
||||||
|
|
||||||
|
@ -141,6 +144,8 @@ public:
|
||||||
|
|
||||||
const AtomList& atoms() const { return m_atoms; }
|
const AtomList& atoms() const { return m_atoms; }
|
||||||
|
|
||||||
|
CharCount length() const;
|
||||||
|
|
||||||
// Split atom pointed by it at pos, returns an iterator to the first atom
|
// Split atom pointed by it at pos, returns an iterator to the first atom
|
||||||
iterator split(iterator it, BufferIterator pos);
|
iterator split(iterator it, BufferIterator pos);
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,18 @@ private:
|
||||||
String m_line;
|
String m_line;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DisplayLine line_with_cursor(const String& str, CharCount cursor_pos)
|
||||||
|
{
|
||||||
|
assert(cursor_pos <= str.char_length());
|
||||||
|
if (cursor_pos == str.char_length())
|
||||||
|
return DisplayLine{-1, { {str, get_color("StatusLine")},
|
||||||
|
{" "_str, get_color("StatusCursor")} }};
|
||||||
|
else
|
||||||
|
return DisplayLine(-1, { DisplayAtom{ str.substr(0, cursor_pos), get_color("StatusLine") },
|
||||||
|
DisplayAtom{ str.substr(cursor_pos, 1), get_color("StatusCursor") },
|
||||||
|
DisplayAtom{ str.substr(cursor_pos+1), get_color("StatusLine") } });
|
||||||
|
}
|
||||||
|
|
||||||
class Menu : public InputMode
|
class Menu : public InputMode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -167,7 +179,7 @@ public:
|
||||||
if (key == Key(Key::Modifiers::Control, 'm'))
|
if (key == Key(Key::Modifiers::Control, 'm'))
|
||||||
{
|
{
|
||||||
context().ui().menu_hide();
|
context().ui().menu_hide();
|
||||||
context().ui().print_status("");
|
context().ui().print_status(DisplayLine{ -1 });
|
||||||
reset_normal_mode();
|
reset_normal_mode();
|
||||||
int selected = m_selected - m_choices.begin();
|
int selected = m_selected - m_choices.begin();
|
||||||
m_callback(selected, MenuEvent::Validate, context());
|
m_callback(selected, MenuEvent::Validate, context());
|
||||||
|
@ -180,7 +192,7 @@ public:
|
||||||
m_edit_filter = false;
|
m_edit_filter = false;
|
||||||
m_filter = boost::regex(".*");
|
m_filter = boost::regex(".*");
|
||||||
m_filter_editor.reset("");
|
m_filter_editor.reset("");
|
||||||
context().ui().print_status("");
|
context().ui().print_status(DisplayLine{ -1 });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -228,8 +240,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_edit_filter)
|
if (m_edit_filter)
|
||||||
context().ui().print_status("/" + m_filter_editor.line(),
|
context().ui().print_status(line_with_cursor("/" + m_filter_editor.line(),
|
||||||
m_filter_editor.cursor_pos() + 1);
|
m_filter_editor.cursor_pos() + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -279,7 +291,7 @@ public:
|
||||||
m_completer(completer), m_callback(callback)
|
m_completer(completer), m_callback(callback)
|
||||||
{
|
{
|
||||||
m_history_it = ms_history[m_prompt].end();
|
m_history_it = ms_history[m_prompt].end();
|
||||||
context().ui().print_status(m_prompt, m_prompt.char_length());
|
context().ui().print_status(line_with_cursor(m_prompt, m_prompt.char_length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_key(const Key& key) override
|
void on_key(const Key& key) override
|
||||||
|
@ -302,7 +314,7 @@ public:
|
||||||
history.erase(it);
|
history.erase(it);
|
||||||
history.push_back(line);
|
history.push_back(line);
|
||||||
}
|
}
|
||||||
context().ui().print_status("");
|
context().ui().print_status(DisplayLine{ -1 });
|
||||||
context().ui().menu_hide();
|
context().ui().menu_hide();
|
||||||
reset_normal_mode();
|
reset_normal_mode();
|
||||||
// call callback after reset_normal_mode so that callback
|
// call callback after reset_normal_mode so that callback
|
||||||
|
@ -312,7 +324,7 @@ public:
|
||||||
}
|
}
|
||||||
else if (key == Key::Escape or key == Key { Key::Modifiers::Control, 'c' })
|
else if (key == Key::Escape or key == Key { Key::Modifiers::Control, 'c' })
|
||||||
{
|
{
|
||||||
context().ui().print_status("");
|
context().ui().print_status(DisplayLine{ -1 });
|
||||||
context().ui().menu_hide();
|
context().ui().menu_hide();
|
||||||
reset_normal_mode();
|
reset_normal_mode();
|
||||||
m_callback(line, PromptEvent::Abort, context());
|
m_callback(line, PromptEvent::Abort, context());
|
||||||
|
@ -417,8 +429,8 @@ public:
|
||||||
m_current_completion = -1;
|
m_current_completion = -1;
|
||||||
m_line_editor.handle_key(key);
|
m_line_editor.handle_key(key);
|
||||||
}
|
}
|
||||||
context().ui().print_status(m_prompt + line,
|
auto curpos = m_prompt.char_length() + m_line_editor.cursor_pos();
|
||||||
m_prompt.char_length() + m_line_editor.cursor_pos());
|
context().ui().print_status(line_with_cursor(m_prompt + line, curpos));
|
||||||
m_callback(line, PromptEvent::Change, context());
|
m_callback(line, PromptEvent::Change, context());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/main.cc
12
src/main.cc
|
@ -223,7 +223,7 @@ void do_search_next(Context& context)
|
||||||
} while (--count > 0);
|
} while (--count > 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
context.print_status("no search pattern");
|
context.print_status({ "no search pattern", get_color("Error") });
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool smart>
|
template<bool smart>
|
||||||
|
@ -255,7 +255,7 @@ void use_selection_as_search_pattern(Context& context)
|
||||||
void do_yank(Context& context)
|
void do_yank(Context& context)
|
||||||
{
|
{
|
||||||
RegisterManager::instance()['"'] = context.editor().selections_content();
|
RegisterManager::instance()['"'] = context.editor().selections_content();
|
||||||
context.print_status("yanked " + int_to_str(context.editor().selections().size()) + " selections");
|
context.print_status({ "yanked " + int_to_str(context.editor().selections().size()) + " selections", get_color("Information") });
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_cat_yank(Context& context)
|
void do_cat_yank(Context& context)
|
||||||
|
@ -265,8 +265,8 @@ void do_cat_yank(Context& context)
|
||||||
for (auto& sel : sels)
|
for (auto& sel : sels)
|
||||||
str += sel;
|
str += sel;
|
||||||
RegisterManager::instance()['"'] = memoryview<String>(str);
|
RegisterManager::instance()['"'] = memoryview<String>(str);
|
||||||
context.print_status("concatenated and yanked " +
|
context.print_status({ "concatenated and yanked " +
|
||||||
int_to_str(sels.size()) + " selections");
|
int_to_str(sels.size()) + " selections", get_color("Information") });
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_erase(Context& context)
|
void do_erase(Context& context)
|
||||||
|
@ -716,8 +716,8 @@ std::unordered_map<Key, std::function<void (Context& context)>> keymap =
|
||||||
{ { Key::Modifiers::None, '*' }, use_selection_as_search_pattern<true> },
|
{ { Key::Modifiers::None, '*' }, use_selection_as_search_pattern<true> },
|
||||||
{ { Key::Modifiers::Alt, '*' }, use_selection_as_search_pattern<false> },
|
{ { Key::Modifiers::Alt, '*' }, use_selection_as_search_pattern<false> },
|
||||||
|
|
||||||
{ { Key::Modifiers::None, 'u' }, repeated([](Context& context) { if (not context.editor().undo()) { context.print_status("nothing left to undo"); } }) },
|
{ { Key::Modifiers::None, 'u' }, repeated([](Context& context) { if (not context.editor().undo()) { context.print_status({ "nothing left to undo", get_color("Information") }); } }) },
|
||||||
{ { Key::Modifiers::None, 'U' }, repeated([](Context& context) { if (not context.editor().redo()) { context.print_status("nothing left to redo"); } }) },
|
{ { Key::Modifiers::None, 'U' }, repeated([](Context& context) { if (not context.editor().redo()) { context.print_status({ "nothing left to redo", get_color("Information") }); } }) },
|
||||||
|
|
||||||
{ { Key::Modifiers::Alt, 'i' }, do_select_object<SurroundFlags::ToBegin | SurroundFlags::ToEnd | SurroundFlags::Inner> },
|
{ { Key::Modifiers::Alt, 'i' }, do_select_object<SurroundFlags::ToBegin | SurroundFlags::ToEnd | SurroundFlags::Inner> },
|
||||||
{ { Key::Modifiers::Alt, 'a' }, do_select_object<SurroundFlags::ToBegin | SurroundFlags::ToEnd> },
|
{ { Key::Modifiers::Alt, 'a' }, do_select_object<SurroundFlags::ToBegin | SurroundFlags::ToEnd> },
|
||||||
|
|
108
src/ncurses.cc
108
src/ncurses.cc
|
@ -86,7 +86,8 @@ void on_sigint(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
NCursesUI::NCursesUI()
|
NCursesUI::NCursesUI()
|
||||||
: m_stdin_watcher{0, [this](FDWatcher&){ if (m_input_callback) m_input_callback(); }}
|
: m_stdin_watcher{0, [this](FDWatcher&){ if (m_input_callback) m_input_callback(); }},
|
||||||
|
m_status_line{-1}
|
||||||
{
|
{
|
||||||
initscr();
|
initscr();
|
||||||
cbreak();
|
cbreak();
|
||||||
|
@ -154,40 +155,44 @@ void NCursesUI::update_dimensions()
|
||||||
--m_dimensions.line;
|
--m_dimensions.line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NCursesUI::draw_line(const DisplayLine& line, CharCount col_index) const
|
||||||
|
{
|
||||||
|
for (const DisplayAtom& atom : line)
|
||||||
|
{
|
||||||
|
set_attribute(A_UNDERLINE, atom.attribute & Underline);
|
||||||
|
set_attribute(A_REVERSE, atom.attribute & Reverse);
|
||||||
|
set_attribute(A_BLINK, atom.attribute & Blink);
|
||||||
|
set_attribute(A_BOLD, atom.attribute & Bold);
|
||||||
|
|
||||||
|
set_color(stdscr, atom.colors);
|
||||||
|
|
||||||
|
String content = atom.content.content();
|
||||||
|
if (content[content.length()-1] == '\n' and
|
||||||
|
content.char_length() - 1 < m_dimensions.column - col_index)
|
||||||
|
{
|
||||||
|
addutf8str(stdscr, Utf8Iterator(content.begin()), Utf8Iterator(content.end())-1);
|
||||||
|
addch(' ');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utf8Iterator begin(content.begin()), end(content.end());
|
||||||
|
if (end - begin > m_dimensions.column - col_index)
|
||||||
|
end = begin + (m_dimensions.column - col_index);
|
||||||
|
addutf8str(stdscr, begin, end);
|
||||||
|
col_index += end - begin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
||||||
const String& mode_line)
|
const DisplayLine& mode_line)
|
||||||
{
|
{
|
||||||
LineCount line_index = 0;
|
LineCount line_index = 0;
|
||||||
for (const DisplayLine& line : display_buffer.lines())
|
for (const DisplayLine& line : display_buffer.lines())
|
||||||
{
|
{
|
||||||
wmove(stdscr, (int)line_index, 0);
|
wmove(stdscr, (int)line_index, 0);
|
||||||
wclrtoeol(stdscr);
|
wclrtoeol(stdscr);
|
||||||
CharCount col_index = 0;
|
draw_line(line, 0);
|
||||||
for (const DisplayAtom& atom : line)
|
|
||||||
{
|
|
||||||
set_attribute(A_UNDERLINE, atom.attribute & Underline);
|
|
||||||
set_attribute(A_REVERSE, atom.attribute & Reverse);
|
|
||||||
set_attribute(A_BLINK, atom.attribute & Blink);
|
|
||||||
set_attribute(A_BOLD, atom.attribute & Bold);
|
|
||||||
|
|
||||||
set_color(stdscr, atom.colors);
|
|
||||||
|
|
||||||
String content = atom.content.content();
|
|
||||||
if (content[content.length()-1] == '\n' and
|
|
||||||
content.char_length() - 1 < m_dimensions.column - col_index)
|
|
||||||
{
|
|
||||||
addutf8str(stdscr, Utf8Iterator(content.begin()), Utf8Iterator(content.end())-1);
|
|
||||||
addch(' ');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Utf8Iterator begin(content.begin()), end(content.end());
|
|
||||||
if (end - begin > m_dimensions.column - col_index)
|
|
||||||
end = begin + (m_dimensions.column - col_index);
|
|
||||||
addutf8str(stdscr, begin, end);
|
|
||||||
col_index += end - begin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++line_index;
|
++line_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,15 +208,16 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
|
||||||
addch('~');
|
addch('~');
|
||||||
}
|
}
|
||||||
|
|
||||||
set_color(stdscr, { Color::Cyan, Color::Default });
|
move((int)m_dimensions.line, 0);
|
||||||
draw_status();
|
clrtoeol();
|
||||||
CharCount status_len = mode_line.char_length();
|
draw_line(m_status_line, 0);
|
||||||
|
CharCount status_len = mode_line.length();
|
||||||
// only draw mode_line if it does not overlap one status line
|
// only draw mode_line if it does not overlap one status line
|
||||||
if (m_dimensions.column - m_status_line.char_length() > status_len + 1)
|
if (m_dimensions.column - m_status_line.length() > status_len + 1)
|
||||||
{
|
{
|
||||||
move((int)m_dimensions.line, (int)(m_dimensions.column - status_len));
|
CharCount col = m_dimensions.column - status_len;
|
||||||
addutf8str(stdscr, Utf8Iterator(mode_line.begin()),
|
move((int)m_dimensions.line, (int)col);
|
||||||
Utf8Iterator(mode_line.end()));
|
draw_line(mode_line, col);
|
||||||
}
|
}
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
@ -285,36 +291,12 @@ Key NCursesUI::get_key()
|
||||||
return Key::Invalid;
|
return Key::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NCursesUI::draw_status()
|
void NCursesUI::print_status(const DisplayLine& status)
|
||||||
{
|
|
||||||
move((int)m_dimensions.line, 0);
|
|
||||||
clrtoeol();
|
|
||||||
if (m_status_cursor == -1)
|
|
||||||
addutf8str(stdscr, m_status_line.cbegin(), m_status_line.cend());
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Utf8Iterator begin{m_status_line.begin()};
|
|
||||||
Utf8Iterator end{m_status_line.end()};
|
|
||||||
Utf8Iterator cursor_it{begin};
|
|
||||||
cursor_it.advance(m_status_cursor, end);
|
|
||||||
|
|
||||||
addutf8str(stdscr, m_status_line.cbegin(), cursor_it);
|
|
||||||
set_attribute(A_REVERSE, 1);
|
|
||||||
if (cursor_it == end)
|
|
||||||
addch(' ');
|
|
||||||
else
|
|
||||||
addutf8str(stdscr, cursor_it, cursor_it+1);
|
|
||||||
set_attribute(A_REVERSE, 0);
|
|
||||||
if (cursor_it != end)
|
|
||||||
addutf8str(stdscr, cursor_it+1, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NCursesUI::print_status(const String& status, CharCount cursor_pos)
|
|
||||||
{
|
{
|
||||||
m_status_line = status;
|
m_status_line = status;
|
||||||
m_status_cursor = cursor_pos;
|
move((int)m_dimensions.line, 0);
|
||||||
draw_status();
|
clrtoeol();
|
||||||
|
draw_line(status, 0);
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ public:
|
||||||
NCursesUI& operator=(const NCursesUI&) = delete;
|
NCursesUI& operator=(const NCursesUI&) = delete;
|
||||||
|
|
||||||
void draw(const DisplayBuffer& display_buffer,
|
void draw(const DisplayBuffer& display_buffer,
|
||||||
const String& mode_line) override;
|
const DisplayLine& mode_line) override;
|
||||||
void print_status(const String& status, CharCount cursor_pos) override;
|
void print_status(const DisplayLine& status) override;
|
||||||
|
|
||||||
bool is_key_available() override;
|
bool is_key_available() override;
|
||||||
Key get_key() override;
|
Key get_key() override;
|
||||||
|
@ -42,13 +42,12 @@ public:
|
||||||
private:
|
private:
|
||||||
friend void on_term_resize(int);
|
friend void on_term_resize(int);
|
||||||
void redraw();
|
void redraw();
|
||||||
|
void draw_line(const DisplayLine& line, CharCount col_index) const;
|
||||||
|
|
||||||
DisplayCoord m_dimensions;
|
DisplayCoord m_dimensions;
|
||||||
void update_dimensions();
|
void update_dimensions();
|
||||||
|
|
||||||
String m_status_line;
|
DisplayLine m_status_line;
|
||||||
CharCount m_status_cursor = -1;
|
|
||||||
void draw_status();
|
|
||||||
|
|
||||||
WINDOW* m_menu_win = nullptr;
|
WINDOW* m_menu_win = nullptr;
|
||||||
std::vector<String> m_choices;
|
std::vector<String> m_choices;
|
||||||
|
|
|
@ -186,7 +186,7 @@ public:
|
||||||
RemoteUI(int socket);
|
RemoteUI(int socket);
|
||||||
~RemoteUI();
|
~RemoteUI();
|
||||||
|
|
||||||
void print_status(const String& status, CharCount cursor_pos) override;
|
void print_status(const DisplayLine& status) override;
|
||||||
|
|
||||||
void menu_show(const memoryview<String>& choices,
|
void menu_show(const memoryview<String>& choices,
|
||||||
DisplayCoord anchor, ColorPair fg, ColorPair bg,
|
DisplayCoord anchor, ColorPair fg, ColorPair bg,
|
||||||
|
@ -199,7 +199,7 @@ public:
|
||||||
void info_hide() override;
|
void info_hide() override;
|
||||||
|
|
||||||
void draw(const DisplayBuffer& display_buffer,
|
void draw(const DisplayBuffer& display_buffer,
|
||||||
const String& mode_line) override;
|
const DisplayLine& mode_line) override;
|
||||||
|
|
||||||
bool is_key_available() override;
|
bool is_key_available() override;
|
||||||
Key get_key() override;
|
Key get_key() override;
|
||||||
|
@ -226,12 +226,11 @@ RemoteUI::~RemoteUI()
|
||||||
close(m_socket_watcher.fd());
|
close(m_socket_watcher.fd());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteUI::print_status(const String& status, CharCount cursor_pos)
|
void RemoteUI::print_status(const DisplayLine& status)
|
||||||
{
|
{
|
||||||
Message msg(m_socket_watcher.fd());
|
Message msg(m_socket_watcher.fd());
|
||||||
msg.write(RemoteUIMsg::PrintStatus);
|
msg.write(RemoteUIMsg::PrintStatus);
|
||||||
msg.write(status);
|
msg.write(status);
|
||||||
msg.write(cursor_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteUI::menu_show(const memoryview<String>& choices,
|
void RemoteUI::menu_show(const memoryview<String>& choices,
|
||||||
|
@ -278,7 +277,7 @@ void RemoteUI::info_hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteUI::draw(const DisplayBuffer& display_buffer,
|
void RemoteUI::draw(const DisplayBuffer& display_buffer,
|
||||||
const String& mode_line)
|
const DisplayLine& mode_line)
|
||||||
{
|
{
|
||||||
Message msg(m_socket_watcher.fd());
|
Message msg(m_socket_watcher.fd());
|
||||||
msg.write(RemoteUIMsg::Draw);
|
msg.write(RemoteUIMsg::Draw);
|
||||||
|
@ -345,9 +344,8 @@ void RemoteClient::process_next_message()
|
||||||
{
|
{
|
||||||
case RemoteUIMsg::PrintStatus:
|
case RemoteUIMsg::PrintStatus:
|
||||||
{
|
{
|
||||||
auto status = read<String>(socket);
|
auto status = read<DisplayLine>(socket);
|
||||||
auto cursor_pos = read<CharCount>(socket);
|
m_ui->print_status(status);
|
||||||
m_ui->print_status(status, cursor_pos);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RemoteUIMsg::MenuShow:
|
case RemoteUIMsg::MenuShow:
|
||||||
|
@ -380,8 +378,8 @@ void RemoteClient::process_next_message()
|
||||||
break;
|
break;
|
||||||
case RemoteUIMsg::Draw:
|
case RemoteUIMsg::Draw:
|
||||||
{
|
{
|
||||||
DisplayBuffer display_buffer = read<DisplayBuffer>(socket);
|
auto display_buffer = read<DisplayBuffer>(socket);
|
||||||
String mode_line = read<String>(socket);
|
auto mode_line = read<DisplayLine>(socket);
|
||||||
m_ui->draw(display_buffer, mode_line);
|
m_ui->draw(display_buffer, mode_line);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace Kakoune
|
||||||
|
|
||||||
class String;
|
class String;
|
||||||
class DisplayBuffer;
|
class DisplayBuffer;
|
||||||
|
class DisplayLine;
|
||||||
struct DisplayCoord;
|
struct DisplayCoord;
|
||||||
|
|
||||||
enum class MenuStyle
|
enum class MenuStyle
|
||||||
|
@ -26,7 +27,7 @@ class UserInterface : public SafeCountable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~UserInterface() {}
|
virtual ~UserInterface() {}
|
||||||
virtual void print_status(const String& status, CharCount cursor_pos = -1) = 0;
|
virtual void print_status(const DisplayLine& status) = 0;
|
||||||
|
|
||||||
virtual void menu_show(const memoryview<String>& choices,
|
virtual void menu_show(const memoryview<String>& choices,
|
||||||
DisplayCoord anchor, ColorPair fg, ColorPair bg,
|
DisplayCoord anchor, ColorPair fg, ColorPair bg,
|
||||||
|
@ -39,7 +40,7 @@ public:
|
||||||
virtual void info_hide() = 0;
|
virtual void info_hide() = 0;
|
||||||
|
|
||||||
virtual void draw(const DisplayBuffer& display_buffer,
|
virtual void draw(const DisplayBuffer& display_buffer,
|
||||||
const String& mode_line) = 0;
|
const DisplayLine& mode_line) = 0;
|
||||||
virtual DisplayCoord dimensions() = 0;
|
virtual DisplayCoord dimensions() = 0;
|
||||||
virtual bool is_key_available() = 0;
|
virtual bool is_key_available() = 0;
|
||||||
virtual Key get_key() = 0;
|
virtual Key get_key() = 0;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user