summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2012-09-03 14:22:02 +0200
committerMaxime Coste <frrrwww@gmail.com>2012-09-03 14:22:02 +0200
commitb08d8719e6a5b6cee67f93a9c62117b747ae4430 (patch)
tree44c255b6f2415563c35b2ba1c79c91056a3fc2b9 /src
parentd5f5f0989d516a3954876272b496c5e9b628c66a (diff)
move input handling, including menu and prompt, to the Client class
Diffstat (limited to 'src')
-rw-r--r--src/client.cc279
-rw-r--r--src/client.hh39
-rw-r--r--src/commands.cc107
-rw-r--r--src/main.cc114
-rw-r--r--src/ncurses.cc166
-rw-r--r--src/ncurses.hh11
6 files changed, 394 insertions, 322 deletions
diff --git a/src/client.cc b/src/client.cc
new file mode 100644
index 00000000..dffd3986
--- /dev/null
+++ b/src/client.cc
@@ -0,0 +1,279 @@
+#include "client.hh"
+
+#include "context.hh"
+#include "register_manager.hh"
+
+#include <unordered_map>
+
+namespace Kakoune
+{
+
+extern std::unordered_map<Key, std::function<void (Context& context)>> keymap;
+
+class Client::NormalMode : public Client::Mode
+{
+public:
+ NormalMode(Client& client)
+ : Client::Mode(client)
+ {
+ }
+
+ void on_key(const Key& key, Context& context) override
+ {
+ if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
+ m_count = m_count * 10 + key.key - '0';
+ else
+ {
+ auto it = keymap.find(key);
+ if (it != keymap.end())
+ {
+ context.numeric_param(m_count);
+ // it's important to do that before calling the command,
+ // as we may die during the command execution.
+ m_count = 0;
+ it->second(context);
+ }
+ else
+ m_count = 0;
+ }
+ }
+
+private:
+ int m_count = 0;
+};
+
+
+class Client::MenuMode : public Client::Mode
+{
+public:
+ MenuMode(Client& client, const memoryview<String>& choices, MenuCallback callback)
+ : Client::Mode(client),
+ m_callback(callback), m_choice_count(choices.size()), m_selected(0)
+ {
+ client.show_menu(choices);
+ }
+
+ void on_key(const Key& key, Context& context) override
+ {
+ if (key == Key(Key::Modifiers::Control, 'n') or
+ key == Key(Key::Modifiers::None, 'j'))
+ {
+ m_client.menu_ctrl(MenuCommand::SelectNext);
+ m_selected = std::min(m_selected+1, m_choice_count-1);
+ }
+ if (key == Key(Key::Modifiers::Control, 'p') or
+ key == Key(Key::Modifiers::None, 'k'))
+ {
+ m_client.menu_ctrl(MenuCommand::SelectPrev);
+ m_selected = std::max(m_selected-1, 0);
+ }
+ if (key == Key(Key::Modifiers::Control, 'm'))
+ {
+ // save callback as reset_normal_mode will delete this
+ MenuCallback callback = std::move(m_callback);
+ int selected = m_selected;
+ m_client.reset_normal_mode();
+ callback(selected, context);
+ }
+ if (key == Key(Key::Modifiers::None, 27))
+ {
+ m_client.reset_normal_mode();
+ }
+ if (key.modifiers == Key::Modifiers::None and
+ key.key >= '0' and key.key <= '9')
+ {
+ m_client.menu_ctrl(MenuCommand::Close);
+ // save callback as reset_normal_mode will delete this
+ MenuCallback callback = std::move(m_callback);
+ m_client.reset_normal_mode();
+ callback(key.key - '0' - 1, context);
+ }
+ }
+
+private:
+ MenuCallback m_callback;
+ int m_selected;
+ int m_choice_count;
+};
+
+class Client::PromptMode : public Client::Mode
+{
+public:
+ PromptMode(Client& client, const String& prompt, Completer completer, PromptCallback callback)
+ : Client::Mode(client),
+ m_prompt(prompt), m_completer(completer), m_callback(callback), m_cursor_pos(0)
+ {
+ m_history_it = ms_history[m_prompt].end();
+ m_client.print_status(m_prompt, m_prompt.length());
+ }
+
+ void on_key(const Key& key, Context& context) override
+ {
+ std::vector<String>& history = ms_history[m_prompt];
+ if (key == Key(Key::Modifiers::Control, 'm')) // enter
+ {
+ std::vector<String>::iterator it;
+ while ((it = find(history, m_result)) != history.end())
+ history.erase(it);
+
+ history.push_back(m_result);
+ m_client.print_status("");
+ // save callback as reset_normal_mode will delete this
+ PromptCallback callback = std::move(m_callback);
+ String result = std::move(m_result);
+ m_client.reset_normal_mode();
+ callback(result, context);
+ return;
+ }
+ else if (key == Key(Key::Modifiers::None, 27))
+ {
+ m_client.print_status("");
+ m_client.reset_normal_mode();
+ return;
+ }
+ else if (key == Key(Key::Modifiers::Control, 'p'))
+ {
+ if (m_history_it != history.begin())
+ {
+ if (m_history_it == history.end())
+ m_saved_result = m_result;
+ --m_history_it;
+ m_result = *m_history_it;
+ m_cursor_pos = m_result.length();
+ }
+ }
+ else if (key == Key(Key::Modifiers::Control, 'n'))
+ {
+ if (m_history_it != history.end())
+ {
+ ++m_history_it;
+ if (m_history_it != history.end())
+ m_result = *m_history_it;
+ else
+ m_result = m_saved_result;
+ m_cursor_pos = m_result.length();
+ }
+ }
+ else if (key == Key(Key::Modifiers::Control, 'b'))
+ {
+ if (m_cursor_pos > 0)
+ --m_cursor_pos;
+ }
+ else if (key == Key(Key::Modifiers::Control, 'f'))
+ {
+ if (m_cursor_pos < m_result.length())
+ ++m_cursor_pos;
+ }
+ else if (key == Key(Key::Modifiers::Control, 'g')) // backspace
+ {
+ if (m_cursor_pos != 0)
+ {
+ m_result = m_result.substr(0, m_cursor_pos - 1)
+ + m_result.substr(m_cursor_pos, String::npos);
+
+ --m_cursor_pos;
+ }
+
+ m_client.menu_ctrl(MenuCommand::Close);
+ m_current_completion = -1;
+ }
+ else if (key == Key(Key::Modifiers::Control, 'r'))
+ {
+ Key k = m_client.get_key();
+ String reg = RegisterManager::instance()[k.key].values(context)[0];
+ m_client.menu_ctrl(MenuCommand::Close);
+ m_current_completion = -1;
+ m_result = m_result.substr(0, m_cursor_pos) + reg + m_result.substr(m_cursor_pos, String::npos);
+ m_cursor_pos += reg.length();
+ }
+ else if (key == Key(Key::Modifiers::Control, 'i')) // tab
+ {
+ if (m_current_completion == -1)
+ {
+ m_completions = m_completer(context, m_result, m_cursor_pos);
+ if (m_completions.candidates.empty())
+ return;
+
+ m_client.menu_ctrl(MenuCommand::Close);
+ m_client.show_menu(m_completions.candidates);
+ m_text_before_completion = m_result.substr(m_completions.start,
+ m_completions.end - m_completions.start);
+ }
+ else
+ m_client.menu_ctrl(MenuCommand::SelectNext);
+ ++m_current_completion;
+
+ String completion;
+ if (m_current_completion >= m_completions.candidates.size())
+ {
+ if (m_current_completion == m_completions.candidates.size() and
+ std::find(m_completions.candidates.begin(), m_completions.candidates.end(), m_text_before_completion) == m_completions.candidates.end())
+ completion = m_text_before_completion;
+ else
+ {
+ m_current_completion = 0;
+ completion = m_completions.candidates[0];
+ m_client.menu_ctrl(MenuCommand::SelectFirst);
+ }
+ }
+ else
+ completion = m_completions.candidates[m_current_completion];
+
+ m_result = m_result.substr(0, m_completions.start) + completion;
+ m_cursor_pos = m_completions.start + completion.length();
+ }
+ else
+ {
+ m_client.menu_ctrl(MenuCommand::Close);
+ m_current_completion = -1;
+ m_result = m_result.substr(0, m_cursor_pos) + key.key + m_result.substr(m_cursor_pos, String::npos);
+ ++m_cursor_pos;
+ }
+ m_client.print_status(m_prompt + m_result, m_prompt.length() + m_cursor_pos);
+ }
+
+private:
+ PromptCallback m_callback;
+ Completer m_completer;
+ const String m_prompt;
+ CharCount m_cursor_pos;
+ Completions m_completions;
+ int m_current_completion = -1;
+ String m_text_before_completion;
+ String m_result;
+ String m_saved_result;
+
+ static std::unordered_map<String, std::vector<String>> ms_history;
+ std::vector<String>::iterator m_history_it;
+};
+std::unordered_map<String, std::vector<String>> Client::PromptMode::ms_history;
+
+Client::Client()
+ : m_mode(new NormalMode(*this))
+{
+}
+
+void Client::prompt(const String& prompt, Completer completer,
+ PromptCallback callback)
+{
+ m_mode.reset(new PromptMode(*this, prompt, completer, callback));
+}
+
+void Client::menu(const memoryview<String>& choices,
+ MenuCallback callback)
+{
+ m_mode.reset(new MenuMode(*this, choices, callback));
+}
+
+void Client::handle_next_input(Context& context)
+{
+ m_mode->on_key(get_key(), context);
+ context.draw_ifn();
+}
+
+void Client::reset_normal_mode()
+{
+ m_mode.reset(new NormalMode(*this));
+}
+
+}
diff --git a/src/client.hh b/src/client.hh
index ea2d6e0a..dc830577 100644
--- a/src/client.hh
+++ b/src/client.hh
@@ -4,13 +4,13 @@
#include "keys.hh"
#include "completion.hh"
#include "utils.hh"
+#include "string.hh"
namespace Kakoune
{
class Editor;
class Window;
-class String;
class Context;
enum class MenuCommand
@@ -21,19 +21,48 @@ enum class MenuCommand
Close,
};
+using MenuCallback = std::function<void (int, Context&)>;
+using PromptCallback = std::function<void (const String&, Context&)>;
+
class Client : public SafeCountable
{
public:
+ Client();
virtual ~Client() {}
+ virtual void draw_window(Window& window) = 0;
+ virtual void print_status(const String& status,
+ CharCount cursor_pos = -1) = 0;
+
+ void prompt(const String& prompt, Completer completer,
+ PromptCallback callback);
- virtual void draw_window(Window& window) = 0;
- virtual void print_status(const String& status) = 0;
- virtual String prompt(const String& prompt, const Context& context,
- Completer completer = complete_nothing) = 0;
+ void menu(const memoryview<String>& choices,
+ MenuCallback callback);
+
+ void handle_next_input(Context& context);
virtual Key get_key() = 0;
+private:
+
virtual void show_menu(const memoryview<String>& choices) = 0;
virtual void menu_ctrl(MenuCommand command) = 0;
+
+
+ void reset_normal_mode();
+ class Mode
+ {
+ public:
+ Mode(Client& client) : m_client(client) {}
+ virtual ~Mode() {}
+ virtual void on_key(const Key& key, Context& context) = 0;
+ protected:
+ Client& m_client;
+ };
+ std::unique_ptr<Mode> m_mode;
+
+ class NormalMode;
+ class MenuMode;
+ class PromptMode;
};
struct prompt_aborted {};
diff --git a/src/commands.cc b/src/commands.cc
index f26e5ac8..a01cf8fe 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -660,84 +660,44 @@ private:
class BatchClient : public Client
{
public:
- BatchClient(const KeyList& keys, Client* previous_client)
+ BatchClient(const KeyList& keys)
: m_keys(keys), m_pos(0)
{
- m_previous_client = previous_client;
}
- String prompt(const String&, const Context&, Completer)
- {
- size_t begin = m_pos;
- while (m_pos < m_keys.size() and m_keys[m_pos].key != '\n')
- ++m_pos;
-
- String result;
- for (size_t i = begin; i < m_pos; ++i)
- result += String() + m_keys[i].key;
- ++m_pos;
-
- return result;
- }
-
- Key get_key()
+ Key get_key() override
{
if (m_pos >= m_keys.size())
throw runtime_error("no more characters");
return m_keys[m_pos++];
}
- void print_status(const String& status)
- {
- m_previous_client->print_status(status);
- }
+ void print_status(const String& status, CharCount cursor_pos) override {}
+ void draw_window(Window& window) override {}
- void draw_window(Window& window)
- {
- m_previous_client->draw_window(window);
- }
+ void show_menu(const memoryview<String>&) override {}
+ void menu_ctrl(MenuCommand) override {}
bool has_key_left() const { return m_pos < m_keys.size(); }
- void show_menu(const memoryview<String>&) {}
- void menu_ctrl(MenuCommand) {}
-
private:
const KeyList& m_keys;
size_t m_pos;
- Client* m_previous_client;
};
void exec_keys(const KeyList& keys, Context& context)
{
- BatchClient batch_client(keys, context.has_client() ? &context.client()
- : nullptr);
+ BatchClient batch_client(keys);
RegisterRestorer quote('"', context);
RegisterRestorer slash('/', context);
scoped_edition edition(context.editor());
- int count = 0;
Context new_context(batch_client);
new_context.change_editor(context.editor());
while (batch_client.has_key_left())
- {
- Key key = batch_client.get_key();
-
- if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
- count = count * 10 + key.key - '0';
- else
- {
- auto it = keymap.find(key);
- if (it != keymap.end())
- {
- new_context.numeric_param(count);
- it->second(new_context);
- }
- count = 0;
- }
- }
+ batch_client.handle_next_input(new_context);
}
void exec_string(const CommandParameters& params, Context& context)
@@ -750,45 +710,6 @@ void exec_string(const CommandParameters& params, Context& context)
exec_keys(keys, context);
}
-int menu_select(const memoryview<String>& choices, Client& client)
-{
- int selected = 0;
- client.show_menu(choices);
- while (true)
- {
- Key key = client.get_key();
- if (key == Key(Key::Modifiers::Control, 'n') or
- key == Key(Key::Modifiers::None, 'j'))
- {
- client.menu_ctrl(MenuCommand::SelectNext);
- selected = std::min(selected+1, (int)choices.size()-1);
- }
- if (key == Key(Key::Modifiers::Control, 'p') or
- key == Key(Key::Modifiers::None, 'k'))
- {
- client.menu_ctrl(MenuCommand::SelectPrev);
- selected = std::max(selected-1, 0);
- }
- if (key == Key(Key::Modifiers::Control, 'm'))
- {
- client.menu_ctrl(MenuCommand::Close);
- return selected;
- }
- if (key == Key(Key::Modifiers::None, 27))
- {
- client.menu_ctrl(MenuCommand::Close);
- return -1;
- }
- if (key.modifiers == Key::Modifiers::None and
- key.key >= '0' and key.key <= '9')
- {
- client.menu_ctrl(MenuCommand::Close);
- return key.key - '0' - 1;
- }
- }
- return 0;
-}
-
void menu(const CommandParameters& params, Context& context)
{
ParametersParser parser(params, { { "auto-single", false } });
@@ -804,12 +725,18 @@ void menu(const CommandParameters& params, Context& context)
}
std::vector<String> choices;
+ std::vector<String> commands;
for (int i = 0; i < count; i += 2)
+ {
choices.push_back(parser[i]);
+ commands.push_back(parser[i+1]);
+ }
- int i = menu_select(choices, context.client()) + 1;
- if (i > 0 and i < (count / 2) + 1)
- CommandManager::instance().execute(parser[(i-1)*2+1], context);
+ context.client().menu(choices,
+ [=](int choice, Context& context) {
+ if (choice >= 0 and choice < commands.size())
+ CommandManager::instance().execute(commands[choice], context);
+ });
}
void try_catch(const CommandParameters& params, Context& context)
diff --git a/src/main.cc b/src/main.cc
index abdb245f..54bffad0 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -165,48 +165,39 @@ void do_go(Context& context)
void do_command(Context& context)
{
- try
- {
- auto cmdline = context.client().prompt(
- ":", context, std::bind(&CommandManager::complete,
- &CommandManager::instance(),
- _1, _2, _3));
-
- CommandManager::instance().execute(cmdline, context);
- }
- catch (prompt_aborted&) {}
+ context.client().prompt(
+ ":", std::bind(&CommandManager::complete, &CommandManager::instance(), _1, _2, _3),
+ [](const String& cmdline, Context& context) { CommandManager::instance().execute(cmdline, context); });
}
void do_pipe(Context& context)
{
- try
- {
- auto cmdline = context.client().prompt("|", context, complete_nothing);
-
- Editor& editor = context.editor();
- std::vector<String> strings;
- for (auto& sel : const_cast<const Editor&>(context.editor()).selections())
- strings.push_back(ShellManager::instance().pipe(String(sel.begin(), sel.end()),
- cmdline, context, {}));
- editor.replace(strings);
- }
- catch (prompt_aborted&) {}
+ context.client().prompt("|", complete_nothing,
+ [](const String& cmdline, Context& context)
+ {
+ Editor& editor = context.editor();
+ std::vector<String> strings;
+ for (auto& sel : const_cast<const Editor&>(context.editor()).selections())
+ strings.push_back(ShellManager::instance().pipe(String(sel.begin(), sel.end()),
+ cmdline, context, {}));
+ editor.replace(strings);
+ });
+
}
template<bool append>
void do_search(Context& context)
{
- try
- {
- String ex = context.client().prompt("/", context);
- if (ex.empty())
- ex = RegisterManager::instance()['/'].values(context)[0];
- else
- RegisterManager::instance()['/'] = ex;
-
- context.editor().select(std::bind(select_next_match, _1, ex), append);
- }
- catch (prompt_aborted&) {}
+ context.client().prompt("/", complete_nothing,
+ [](const String& str, Context& context) {
+ String ex = str;
+ if (ex.empty())
+ ex = RegisterManager::instance()['/'].values(context)[0];
+ else
+ RegisterManager::instance()['/'] = ex;
+
+ context.editor().select(std::bind(select_next_match, _1, ex), append);
+ });
}
template<bool append>
@@ -271,22 +262,16 @@ void do_paste(Context& context)
void do_select_regex(Context& context)
{
- try
- {
- String ex = context.client().prompt("select: ", context);
- context.editor().multi_select(std::bind(select_all_matches, _1, ex));
- }
- catch (prompt_aborted&) {}
+ context.client().prompt("select: ", complete_nothing,
+ [](const String& ex, Context& context)
+ { context.editor().multi_select(std::bind(select_all_matches, _1, ex)); });
}
void do_split_regex(Context& context)
{
- try
- {
- String ex = context.client().prompt("split: ", context);
- context.editor().multi_select(std::bind(split_selection, _1, ex));
- }
- catch (prompt_aborted&) {}
+ context.client().prompt("select: ", complete_nothing,
+ [](const String& ex, Context& context)
+ { context.editor().multi_select(std::bind(split_selection, _1, ex)); });
}
void do_join(Context& context)
@@ -444,32 +429,6 @@ std::unordered_map<Key, std::function<void (Context& context)>> keymap =
void run_unit_tests();
-void manage_next_keypress(Context& context)
-{
- static int count = 0;
- try
- {
- Key key = context.client().get_key();
- if (key.modifiers == Key::Modifiers::None and isdigit(key.key))
- count = count * 10 + key.key - '0';
- else
- {
- auto it = keymap.find(key);
- if (it != keymap.end())
- {
- context.numeric_param(count);
- it->second(context);
- context.draw_ifn();
- }
- count = 0;
- }
- }
- catch (Kakoune::runtime_error& error)
- {
- context.print_status(error.description());
- }
-}
-
int main(int argc, char* argv[])
{
EventManager event_manager;
@@ -536,11 +495,20 @@ int main(int argc, char* argv[])
context.change_editor(*buffer->get_or_create_window());
}
- event_manager.watch(0, [&](int) { manage_next_keypress(context); });
+ event_manager.watch(0, [&](int) { client.handle_next_input(context); });
context.draw_ifn();
while(not quit_requested)
- event_manager.handle_next_events();
+ {
+ try
+ {
+ event_manager.handle_next_events();
+ }
+ catch (Kakoune::runtime_error& error)
+ {
+ context.print_status(error.description());
+ }
+ }
}
catch (Kakoune::exception& error)
{
diff --git a/src/ncurses.cc b/src/ncurses.cc
index a2e273cc..2f420a8d 100644
--- a/src/ncurses.cc
+++ b/src/ncurses.cc
@@ -169,159 +169,29 @@ Key NCursesClient::get_key()
return Key(modifiers, c);
}
-String NCursesClient::prompt(const String& text, const Context& context, Completer completer)
-{
- curs_set(2);
- auto restore_cursor = on_scope_end([]() { curs_set(0); });
-
- int max_x, max_y;
- getmaxyx(stdscr, max_y, max_x);
- move(max_y-1, 0);
- addstr(text.c_str());
- clrtoeol();
-
- CharCount cursor_pos = 0;
-
- Completions completions;
- int current_completion = -1;
- String text_before_completion;
-
- String result;
- String saved_result;
-
- static std::unordered_map<String, std::vector<String>> history_per_prompt;
- std::vector<String>& history = history_per_prompt[text];
- auto history_it = history.end();
-
- while (true)
- {
- int c = getch();
- switch (c)
- {
- case '\r':
- {
- std::vector<String>::iterator it;
- while ((it = find(history, result)) != history.end())
- history.erase(it);
-
- history.push_back(result);
- return result;
- }
- case KEY_UP:
- if (history_it != history.begin())
- {
- if (history_it == history.end())
- saved_result = result;
- --history_it;
- result = *history_it;
- cursor_pos = result.length();
- }
- break;
- case KEY_DOWN:
- if (history_it != history.end())
- {
- ++history_it;
- if (history_it != history.end())
- result = *history_it;
- else
- result = saved_result;
- cursor_pos = result.length();
- }
- break;
- case KEY_LEFT:
- if (cursor_pos > 0)
- --cursor_pos;
- break;
- case KEY_RIGHT:
- if (cursor_pos < result.length())
- ++cursor_pos;
- break;
- case KEY_BACKSPACE:
- if (cursor_pos != 0)
- {
- result = result.substr(0, cursor_pos - 1)
- + result.substr(cursor_pos, String::npos);
-
- --cursor_pos;
- }
-
- menu_ctrl(MenuCommand::Close);
- current_completion = -1;
- break;
- case CTRL('r'):
- {
- c = getch();
- String reg = RegisterManager::instance()[c].values(context)[0];
- menu_ctrl(MenuCommand::Close);
- current_completion = -1;
- result = result.substr(0, cursor_pos) + reg + result.substr(cursor_pos, String::npos);
- cursor_pos += reg.length();
- }
- break;
- case 27:
- throw prompt_aborted();
- case '\t':
- {
- if (current_completion == -1)
- {
- completions = completer(context, result, cursor_pos);
- if (completions.candidates.empty())
- break;
-
- menu_ctrl(MenuCommand::Close);
- show_menu(completions.candidates);
- text_before_completion = result.substr(completions.start,
- completions.end - completions.start);
- }
- else
- menu_ctrl(MenuCommand::SelectNext);
- ++current_completion;
-
- String completion;
- if (current_completion >= completions.candidates.size())
- {
- if (current_completion == completions.candidates.size() and
- std::find(completions.candidates.begin(), completions.candidates.end(), text_before_completion) == completions.candidates.end())
- completion = text_before_completion;
- else
- {
- current_completion = 0;
- completion = completions.candidates[0];
- menu_ctrl(MenuCommand::SelectFirst);
- }
- }
- else
- completion = completions.candidates[current_completion];
-
- move(max_y-1, (int)text.length());
- result = result.substr(0, completions.start) + completion;
- cursor_pos = completions.start + completion.length();
- break;
- }
- default:
- menu_ctrl(MenuCommand::Close);
- current_completion = -1;
- result = result.substr(0, cursor_pos) + (char)c + result.substr(cursor_pos, String::npos);
- ++cursor_pos;
- }
-
- move(max_y - 1, (int)text.length());
- clrtoeol();
- addstr(result.c_str());
- move(max_y - 1, (int)(text.length() + cursor_pos));
- refresh();
- }
- menu_ctrl(MenuCommand::Close);
- return result;
-}
-
-void NCursesClient::print_status(const String& status)
+void NCursesClient::print_status(const String& status, CharCount cursor_pos)
{
int x,y;
getmaxyx(stdscr, y, x);
move(y-1, 0);
clrtoeol();
- addstr(status.c_str());
+ if (cursor_pos == -1)
+ addstr(status.c_str());
+ else if (cursor_pos < status.length())
+ {
+ addstr(status.substr(0, cursor_pos).c_str());
+ set_attribute(A_REVERSE, 1);
+ addch(status[cursor_pos]);
+ set_attribute(A_REVERSE, 0);
+ addstr(status.substr(cursor_pos+1, -1).c_str());
+ }
+ else
+ {
+ addstr(status.c_str());
+ set_attribute(A_REVERSE, 1);
+ addch(' ');
+ set_attribute(A_REVERSE, 0);
+ }
refresh();
}
diff --git a/src/ncurses.hh b/src/ncurses.hh
index 61e140d8..69ddd30a 100644
--- a/src/ncurses.hh
+++ b/src/ncurses.hh
@@ -18,14 +18,13 @@ public:
NCursesClient(const NCursesClient&) = delete;
NCursesClient& operator=(const NCursesClient&) = delete;
- void draw_window(Window& window);
- void print_status(const String& status);
+ void draw_window(Window& window) override;
+ void print_status(const String& status, CharCount cursor_pos) override;
- String prompt(const String& prompt, const Context& context, Completer completer);
- Key get_key();
+ Key get_key() override;
- void show_menu(const memoryview<String>& choices);
- void menu_ctrl(MenuCommand command);
+ void show_menu(const memoryview<String>& choices) override;
+ void menu_ctrl(MenuCommand command) override;
private:
MENU* m_menu;
std::vector<ITEM*> m_items;