summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2013-04-04 18:50:00 +0200
committerMaxime Coste <frrrwww@gmail.com>2013-04-04 18:50:00 +0200
commitf540566b1b4565f9306101c67fa51776ff7dc0dc (patch)
tree32a3ea1e476cfb8b8572a6460645b5c7f937681a
parent6ffdfd77353748f855b1528cdc6ca44b7154bfe3 (diff)
UserInterface: status line messages are now DisplayLines
This add color support for the status line
-rw-r--r--README.asciidoc5
-rw-r--r--src/client_manager.cc9
-rw-r--r--src/color_registry.cc3
-rw-r--r--src/commands.cc8
-rw-r--r--src/context.hh2
-rw-r--r--src/display_buffer.cc8
-rw-r--r--src/display_buffer.hh13
-rw-r--r--src/input_handler.cc30
-rw-r--r--src/main.cc12
-rw-r--r--src/ncurses.cc106
-rw-r--r--src/ncurses.hh9
-rw-r--r--src/remote.cc18
-rw-r--r--src/user_interface.hh5
13 files changed, 120 insertions, 108 deletions
diff --git a/README.asciidoc b/README.asciidoc
index 99075ad6..b446bf7b 100644
--- a/README.asciidoc
+++ b/README.asciidoc
@@ -407,7 +407,10 @@ there are some builtins color aliases:
* +LineNumbers+: colors used by the number_lines highlighter
* +MenuForeground+: colors for the selected element 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
---------------
diff --git a/src/client_manager.cc b/src/client_manager.cc
index a7919cf1..fc95c118 100644
--- a/src/client_manager.cc
+++ b/src/client_manager.cc
@@ -4,6 +4,7 @@
#include "buffer_manager.hh"
#include "command_manager.hh"
#include "file.hh"
+#include "color_registry.hh"
namespace Kakoune
{
@@ -64,7 +65,7 @@ void ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
}
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);
}
catch (Kakoune::client_removed&)
@@ -81,7 +82,7 @@ void ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
}
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);
}
catch (Kakoune::client_removed&)
@@ -191,7 +192,7 @@ Context& ClientManager::get_client_context(const String& 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();
std::ostringstream oss;
@@ -207,7 +208,7 @@ static String generate_status_line(const Context& context)
oss << " [" << context.editor().selections().size() << " sel]";
if (context.editor().is_editing())
oss << " [insert]";
- return oss.str();
+ return { oss.str(), get_color("StatusLine") };
}
void ClientManager::redraw_clients() const
diff --git a/src/color_registry.cc b/src/color_registry.cc
index c7684691..b30afb28 100644
--- a/src/color_registry.cc
+++ b/src/color_registry.cc
@@ -49,6 +49,9 @@ ColorRegistry::ColorRegistry()
{ "MenuForeground", { Color::Blue, Color::Cyan } },
{ "MenuBackground", { Color::Cyan, Color::Blue } },
{ "Information", { Color::Black, Color::Yellow } },
+ { "Error", { Color::Black, Color::Red } },
+ { "StatusLine", { Color::Cyan, Color::Default } },
+ { "StatusCursor", { Color::Black, Color::Cyan } },
}
{}
diff --git a/src/commands.cc b/src/commands.cc
index 819cebb7..706a4dfd 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -37,7 +37,7 @@ Buffer* open_or_create(const String& filename, Context& context)
Buffer* buffer = create_buffer_from_file(filename);
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);
}
return buffer;
@@ -424,7 +424,7 @@ void echo_message(const CommandParameters& params, Context& context)
String message;
for (auto& param : params)
message += param + " ";
- context.print_status(message);
+ context.print_status({ std::move(message), get_color("StatusLine") } );
}
void exec_commands_in_file(const CommandParameters& params,
@@ -803,8 +803,8 @@ public:
}
bool is_key_available() override { return m_pos < m_keys.size(); }
- void print_status(const String& , CharCount) override {}
- void draw(const DisplayBuffer&, const String&) override {}
+ void print_status(const DisplayLine&) override {}
+ void draw(const DisplayBuffer&, const DisplayLine&) override {}
void menu_show(const memoryview<String>&,
DisplayCoord, ColorPair, ColorPair, MenuStyle) override {}
void menu_select(int) override {}
diff --git a/src/context.hh b/src/context.hh
index bfbc6c6d..c6c7abc2 100644
--- a/src/context.hh
+++ b/src/context.hh
@@ -95,7 +95,7 @@ struct Context
return GlobalHooks::instance();
}
- void print_status(const String& status) const
+ void print_status(const DisplayLine& status) const
{
if (has_ui())
ui().print_status(status);
diff --git a/src/display_buffer.cc b/src/display_buffer.cc
index d9ab9609..f518ab50 100644
--- a/src/display_buffer.cc
+++ b/src/display_buffer.cc
@@ -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()
{
m_range.first = BufferIterator();
diff --git a/src/display_buffer.hh b/src/display_buffer.hh
index 3879a31e..49bf67cb 100644
--- a/src/display_buffer.hh
+++ b/src/display_buffer.hh
@@ -112,12 +112,13 @@ struct DisplayAtom
{
ColorPair colors;
Attribute attribute;
-
AtomContent content;
- DisplayAtom(AtomContent content)
- : content{std::move(content)}, attribute{Normal},
- colors{Color::Default, Color::Default} {}
+ DisplayAtom(AtomContent content,
+ ColorPair colors = {Color::Default, Color::Default},
+ Attribute attribute = Normal)
+ : content{std::move(content)}, colors{colors}, attribute{attribute}
+ {}
};
class DisplayLine
@@ -130,6 +131,8 @@ public:
explicit DisplayLine(LineCount buffer_line) : m_buffer_line(buffer_line) {}
DisplayLine(LineCount buffer_line, AtomList 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; }
@@ -141,6 +144,8 @@ public:
const AtomList& atoms() const { return m_atoms; }
+ CharCount length() const;
+
// Split atom pointed by it at pos, returns an iterator to the first atom
iterator split(iterator it, BufferIterator pos);
diff --git a/src/input_handler.cc b/src/input_handler.cc
index f8a2fc64..cb9cabbf 100644
--- a/src/input_handler.cc
+++ b/src/input_handler.cc
@@ -144,6 +144,18 @@ private:
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
{
public:
@@ -167,7 +179,7 @@ public:
if (key == Key(Key::Modifiers::Control, 'm'))
{
context().ui().menu_hide();
- context().ui().print_status("");
+ context().ui().print_status(DisplayLine{ -1 });
reset_normal_mode();
int selected = m_selected - m_choices.begin();
m_callback(selected, MenuEvent::Validate, context());
@@ -180,7 +192,7 @@ public:
m_edit_filter = false;
m_filter = boost::regex(".*");
m_filter_editor.reset("");
- context().ui().print_status("");
+ context().ui().print_status(DisplayLine{ -1 });
}
else
{
@@ -228,8 +240,8 @@ public:
}
if (m_edit_filter)
- context().ui().print_status("/" + m_filter_editor.line(),
- m_filter_editor.cursor_pos() + 1);
+ context().ui().print_status(line_with_cursor("/" + m_filter_editor.line(),
+ m_filter_editor.cursor_pos() + 1));
}
private:
@@ -279,7 +291,7 @@ public:
m_completer(completer), m_callback(callback)
{
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
@@ -302,7 +314,7 @@ public:
history.erase(it);
history.push_back(line);
}
- context().ui().print_status("");
+ context().ui().print_status(DisplayLine{ -1 });
context().ui().menu_hide();
reset_normal_mode();
// 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' })
{
- context().ui().print_status("");
+ context().ui().print_status(DisplayLine{ -1 });
context().ui().menu_hide();
reset_normal_mode();
m_callback(line, PromptEvent::Abort, context());
@@ -417,8 +429,8 @@ public:
m_current_completion = -1;
m_line_editor.handle_key(key);
}
- context().ui().print_status(m_prompt + line,
- m_prompt.char_length() + m_line_editor.cursor_pos());
+ auto curpos = 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());
}
diff --git a/src/main.cc b/src/main.cc
index bb63be0e..932fad61 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -223,7 +223,7 @@ void do_search_next(Context& context)
} while (--count > 0);
}
else
- context.print_status("no search pattern");
+ context.print_status({ "no search pattern", get_color("Error") });
}
template<bool smart>
@@ -255,7 +255,7 @@ void use_selection_as_search_pattern(Context& context)
void do_yank(Context& context)
{
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)
@@ -265,8 +265,8 @@ void do_cat_yank(Context& context)
for (auto& sel : sels)
str += sel;
RegisterManager::instance()['"'] = memoryview<String>(str);
- context.print_status("concatenated and yanked " +
- int_to_str(sels.size()) + " selections");
+ context.print_status({ "concatenated and yanked " +
+ int_to_str(sels.size()) + " selections", get_color("Information") });
}
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::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().redo()) { context.print_status("nothing left to redo"); } }) },
+ { { 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", get_color("Information") }); } }) },
{ { Key::Modifiers::Alt, 'i' }, do_select_object<SurroundFlags::ToBegin | SurroundFlags::ToEnd | SurroundFlags::Inner> },
{ { Key::Modifiers::Alt, 'a' }, do_select_object<SurroundFlags::ToBegin | SurroundFlags::ToEnd> },
diff --git a/src/ncurses.cc b/src/ncurses.cc
index 120b9876..1425c47c 100644
--- a/src/ncurses.cc
+++ b/src/ncurses.cc
@@ -86,7 +86,8 @@ void on_sigint(int)
}
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();
cbreak();
@@ -154,40 +155,44 @@ void NCursesUI::update_dimensions()
--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,
- const String& mode_line)
+ const DisplayLine& mode_line)
{
LineCount line_index = 0;
for (const DisplayLine& line : display_buffer.lines())
{
wmove(stdscr, (int)line_index, 0);
wclrtoeol(stdscr);
- CharCount col_index = 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;
- }
- }
+ draw_line(line, 0);
++line_index;
}
@@ -203,15 +208,16 @@ void NCursesUI::draw(const DisplayBuffer& display_buffer,
addch('~');
}
- set_color(stdscr, { Color::Cyan, Color::Default });
- draw_status();
- CharCount status_len = mode_line.char_length();
+ move((int)m_dimensions.line, 0);
+ clrtoeol();
+ draw_line(m_status_line, 0);
+ CharCount status_len = mode_line.length();
// 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));
- addutf8str(stdscr, Utf8Iterator(mode_line.begin()),
- Utf8Iterator(mode_line.end()));
+ CharCount col = m_dimensions.column - status_len;
+ move((int)m_dimensions.line, (int)col);
+ draw_line(mode_line, col);
}
redraw();
}
@@ -285,36 +291,12 @@ Key NCursesUI::get_key()
return Key::Invalid;
}
-void NCursesUI::draw_status()
+void NCursesUI::print_status(const DisplayLine& status)
{
+ m_status_line = 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_cursor = cursor_pos;
- draw_status();
+ draw_line(status, 0);
redraw();
}
diff --git a/src/ncurses.hh b/src/ncurses.hh
index 633ff110..de4f1dc6 100644
--- a/src/ncurses.hh
+++ b/src/ncurses.hh
@@ -20,8 +20,8 @@ public:
NCursesUI& operator=(const NCursesUI&) = delete;
void draw(const DisplayBuffer& display_buffer,
- const String& mode_line) override;
- void print_status(const String& status, CharCount cursor_pos) override;
+ const DisplayLine& mode_line) override;
+ void print_status(const DisplayLine& status) override;
bool is_key_available() override;
Key get_key() override;
@@ -42,13 +42,12 @@ public:
private:
friend void on_term_resize(int);
void redraw();
+ void draw_line(const DisplayLine& line, CharCount col_index) const;
DisplayCoord m_dimensions;
void update_dimensions();
- String m_status_line;
- CharCount m_status_cursor = -1;
- void draw_status();
+ DisplayLine m_status_line;
WINDOW* m_menu_win = nullptr;
std::vector<String> m_choices;
diff --git a/src/remote.cc b/src/remote.cc
index 8c14420e..01b6760b 100644
--- a/src/remote.cc
+++ b/src/remote.cc
@@ -186,7 +186,7 @@ public:
RemoteUI(int socket);
~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,
DisplayCoord anchor, ColorPair fg, ColorPair bg,
@@ -199,7 +199,7 @@ public:
void info_hide() override;
void draw(const DisplayBuffer& display_buffer,
- const String& mode_line) override;
+ const DisplayLine& mode_line) override;
bool is_key_available() override;
Key get_key() override;
@@ -226,12 +226,11 @@ RemoteUI::~RemoteUI()
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());
msg.write(RemoteUIMsg::PrintStatus);
msg.write(status);
- msg.write(cursor_pos);
}
void RemoteUI::menu_show(const memoryview<String>& choices,
@@ -278,7 +277,7 @@ void RemoteUI::info_hide()
}
void RemoteUI::draw(const DisplayBuffer& display_buffer,
- const String& mode_line)
+ const DisplayLine& mode_line)
{
Message msg(m_socket_watcher.fd());
msg.write(RemoteUIMsg::Draw);
@@ -345,9 +344,8 @@ void RemoteClient::process_next_message()
{
case RemoteUIMsg::PrintStatus:
{
- auto status = read<String>(socket);
- auto cursor_pos = read<CharCount>(socket);
- m_ui->print_status(status, cursor_pos);
+ auto status = read<DisplayLine>(socket);
+ m_ui->print_status(status);
break;
}
case RemoteUIMsg::MenuShow:
@@ -380,8 +378,8 @@ void RemoteClient::process_next_message()
break;
case RemoteUIMsg::Draw:
{
- DisplayBuffer display_buffer = read<DisplayBuffer>(socket);
- String mode_line = read<String>(socket);
+ auto display_buffer = read<DisplayBuffer>(socket);
+ auto mode_line = read<DisplayLine>(socket);
m_ui->draw(display_buffer, mode_line);
break;
}
diff --git a/src/user_interface.hh b/src/user_interface.hh
index 8fa99c4a..522357ab 100644
--- a/src/user_interface.hh
+++ b/src/user_interface.hh
@@ -12,6 +12,7 @@ namespace Kakoune
class String;
class DisplayBuffer;
+class DisplayLine;
struct DisplayCoord;
enum class MenuStyle
@@ -26,7 +27,7 @@ class UserInterface : public SafeCountable
{
public:
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,
DisplayCoord anchor, ColorPair fg, ColorPair bg,
@@ -39,7 +40,7 @@ public:
virtual void info_hide() = 0;
virtual void draw(const DisplayBuffer& display_buffer,
- const String& mode_line) = 0;
+ const DisplayLine& mode_line) = 0;
virtual DisplayCoord dimensions() = 0;
virtual bool is_key_available() = 0;
virtual Key get_key() = 0;