diff --git a/src/commands.cc b/src/commands.cc index 3aea2c11..29cd9312 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -7,7 +7,7 @@ #include "buffer.hh" #include "window.hh" #include "file.hh" -#include "ncurses.hh" +#include "ui.hh" #include "regex.hh" #include "highlighter_registry.hh" #include "filter_registry.hh" @@ -29,8 +29,6 @@ extern Context main_context; extern bool quit_requested; extern std::unordered_map> keymap; -extern PromptFunc prompt_func; -extern GetKeyFunc get_key_func; namespace { @@ -220,7 +218,7 @@ Buffer* open_or_create(const String& filename) } catch (file_not_found& what) { - NCurses::print_status("new file " + filename); + print_status("new file " + filename); buffer = new Buffer(filename, Buffer::Type::NewFile); } return buffer; @@ -291,7 +289,7 @@ void quit(const CommandParameters& params, const Context& context) message += *it; } message += "]"; - NCurses::print_status(message); + print_status(message); return; } } @@ -369,7 +367,7 @@ void add_highlighter(const CommandParameters& params, const Context& context) } catch (runtime_error& err) { - NCurses::print_status("error: " + err.description()); + print_status("error: " + err.description()); } } @@ -389,7 +387,7 @@ void rm_highlighter(const CommandParameters& params, const Context& context) } catch (runtime_error& err) { - NCurses::print_status("error: " + err.description()); + print_status("error: " + err.description()); } } @@ -407,7 +405,7 @@ void add_filter(const CommandParameters& params, const Context& context) } catch (runtime_error& err) { - NCurses::print_status("error: " + err.description()); + print_status("error: " + err.description()); } } @@ -438,7 +436,7 @@ void add_hook(const CommandParameters& params, const Context& context) else if (params[0] == "window") context.window().hook_manager().add_hook(params[1], hook_func); else - NCurses::print_status("error: no such hook container " + params[0]); + print_status("error: no such hook container " + params[0]); } EnvVarMap params_to_env_var_map(const CommandParameters& params) @@ -523,7 +521,7 @@ void echo_message(const CommandParameters& params, const Context& context) String message; for (auto& param : params) message += param + " "; - NCurses::print_status(message); + print_status(message); } void exec_commands_in_file(const CommandParameters& params, @@ -559,7 +557,7 @@ void exec_commands_in_file(const CommandParameters& params, if (end_pos == length) { - NCurses::print_status(String("unterminated '") + delimiter + "' string"); + print_status(String("unterminated '") + delimiter + "' string"); return; } @@ -584,7 +582,7 @@ void exec_commands_in_file(const CommandParameters& params, if (end_pos == length) { if (cat_with_previous) - NCurses::print_status("while executing commands in \"" + params[0] + + print_status("while executing commands in \"" + params[0] + "\": last command not complete"); break; } @@ -645,37 +643,64 @@ private: char m_name; }; +class BatchUI : public UI +{ +public: + BatchUI(const KeyList& keys) + : m_keys(keys), m_pos(0) + { + m_previous_ui = current_ui; + current_ui = this; + } + + ~BatchUI() + { + current_ui = m_previous_ui; + } + + String prompt(const String&, 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() + { + 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_ui->print_status(status); + } + + void draw_window(Window& window) + { + m_previous_ui->draw_window(window); + } + + bool has_key_left() const { return m_pos < m_keys.size(); } + +private: + const KeyList& m_keys; + size_t m_pos; + UI* m_previous_ui; +}; + void exec_keys(const KeyList& keys, const Context& context) { - auto prompt_save = prompt_func; - auto get_key_save = get_key_func; - - auto restore_funcs = on_scope_end([&]() { - prompt_func = prompt_save; - get_key_func = get_key_save; - }); - - size_t pos = 0; - - prompt_func = [&](const String&, Completer) { - size_t begin = pos; - while (pos < keys.size() and keys[pos].key != '\n') - ++pos; - - String result; - for (size_t i = begin; i < pos; ++i) - result += String() + keys[i].key; - ++pos; - - return result; - }; - - get_key_func = [&]() { - if (pos >= keys.size()) - throw runtime_error("no more characters"); - return keys[pos++]; - }; + BatchUI batch_ui(keys); RegisterRestorer quote('"'); RegisterRestorer slash('/'); @@ -687,9 +712,9 @@ void exec_keys(const KeyList& keys, scoped_edition edition(editor); int count = 0; - while(pos < keys.size()) + while (batch_ui.has_key_left()) { - const Key& key = keys[pos++]; + Key key = batch_ui.get_key(); if (key.modifiers == Key::Modifiers::None and isdigit(key.key)) count = count * 10 + key.key - '0'; @@ -742,7 +767,7 @@ void menu(const CommandParameters& params, } oss << "(empty cancels): "; - String choice = prompt_func(oss.str(), complete_nothing); + String choice = prompt(oss.str(), complete_nothing); int i = atoi(choice.c_str()); if (i > 0 and i < (count / 2) + 1) diff --git a/src/main.cc b/src/main.cc index 641196a8..c133dd91 100644 --- a/src/main.cc +++ b/src/main.cc @@ -31,24 +31,6 @@ namespace Kakoune Context main_context; bool quit_requested = false; -void draw_editor_ifn(Editor& editor) -{ - Window* window = dynamic_cast(&editor); - if (window) - NCurses::draw_window(*window); -} - -PromptFunc prompt_func; -String prompt(const String& text, Completer completer = complete_nothing) -{ - return prompt_func(text, completer); -} - -GetKeyFunc get_key_func; -Key get_key() -{ - return get_key_func(); -} struct InsertSequence { @@ -243,7 +225,7 @@ void do_search_next(Editor& editor) if (not ex.empty()) editor.select(std::bind(select_next_match, _1, ex), append); else - NCurses::print_status("no search pattern"); + print_status("no search pattern"); } void do_yank(Editor& editor, int count) @@ -401,8 +383,8 @@ std::unordered_map> keymap { { Key::Modifiers::None, 'n' }, [](Editor& editor, int count) { do_search_next(editor); } }, { { Key::Modifiers::None, 'N' }, [](Editor& editor, int count) { do_search_next(editor); } }, - { { Key::Modifiers::None, 'u' }, [](Editor& editor, int count) { do { if (not editor.undo()) { NCurses::print_status("nothing left to undo"); break; } } while(--count > 0); } }, - { { Key::Modifiers::None, 'U' }, [](Editor& editor, int count) { do { if (not editor.redo()) { NCurses::print_status("nothing left to redo"); break; } } while(--count > 0); } }, + { { Key::Modifiers::None, 'u' }, [](Editor& editor, int count) { do { if (not editor.undo()) { print_status("nothing left to undo"); break; } } while(--count > 0); } }, + { { Key::Modifiers::None, 'U' }, [](Editor& editor, int count) { do { if (not editor.redo()) { print_status("nothing left to redo"); break; } } while(--count > 0); } }, { { Key::Modifiers::Alt, 'i' }, do_select_object }, { { Key::Modifiers::Alt, 'a' }, do_select_object }, @@ -437,8 +419,6 @@ void run_unit_tests(); int main(int argc, char* argv[]) { - NCurses::init(prompt_func, get_key_func); - ShellManager shell_manager; CommandManager command_manager; BufferManager buffer_manager; @@ -466,11 +446,14 @@ int main(int argc, char* argv[]) } catch (Kakoune::runtime_error& error) { - NCurses::print_status(error.description()); + print_status(error.description()); } try { + NCursesUI ui; + current_ui = &ui; + write_debug("*** This is the debug buffer, where debug info will be written ***\n"); write_debug("utf-8 test: é á ï"); @@ -482,7 +465,7 @@ int main(int argc, char* argv[]) main_context = Context(*buffer->get_or_create_window()); } - NCurses::draw_window(main_context.window()); + current_ui->draw_window(main_context.window()); int count = 0; while(not quit_requested) { @@ -497,29 +480,22 @@ int main(int argc, char* argv[]) if (it != keymap.end()) { it->second(main_context.window(), count); - NCurses::draw_window(main_context.window()); + current_ui->draw_window(main_context.window()); } count = 0; } } catch (Kakoune::runtime_error& error) { - NCurses::print_status(error.description()); + print_status(error.description()); } } - NCurses::deinit(); } catch (Kakoune::exception& error) { - NCurses::deinit(); puts("uncaught exception:\n"); puts(error.description().c_str()); return -1; } - catch (...) - { - NCurses::deinit(); - throw; - } return 0; } diff --git a/src/ncurses.cc b/src/ncurses.cc index 177530b7..791b72b4 100644 --- a/src/ncurses.cc +++ b/src/ncurses.cc @@ -10,8 +10,26 @@ namespace Kakoune { -namespace NCurses + +NCursesUI::NCursesUI() { + // setlocale(LC_ALL, ""); + initscr(); + cbreak(); + noecho(); + nonl(); + intrflush(stdscr, false); + keypad(stdscr, true); + curs_set(0); + start_color(); + use_default_colors(); + ESCDELAY=25; +} + +NCursesUI::~NCursesUI() +{ + endwin(); +} static void set_attribute(int attribute, bool on) { @@ -69,7 +87,7 @@ static void set_color(Color fg_color, Color bg_color) } } -void draw_window(Window& window) +void NCursesUI::draw_window(Window& window) { int max_x,max_y; getmaxyx(stdscr, max_y, max_x); @@ -142,7 +160,7 @@ void draw_window(Window& window) last_status_length = status_line.length(); } -static Key get_key() +Key NCursesUI::get_key() { char c = getch(); @@ -166,7 +184,7 @@ static Key get_key() return Key(modifiers, c); } -static String prompt(const String& text, Completer completer) +String NCursesUI::prompt(const String& text, Completer completer) { curs_set(2); auto restore_cursor = on_scope_end([]() { curs_set(0); }); @@ -303,7 +321,7 @@ static String prompt(const String& text, Completer completer) return result; } -void print_status(const String& status) +void NCursesUI::print_status(const String& status) { int x,y; getmaxyx(stdscr, y, x); @@ -312,29 +330,4 @@ void print_status(const String& status) addstr(status.c_str()); } -void init(PromptFunc& prompt_func, GetKeyFunc& get_key_func) -{ - // setlocale(LC_ALL, ""); - initscr(); - cbreak(); - noecho(); - nonl(); - intrflush(stdscr, false); - keypad(stdscr, true); - curs_set(0); - start_color(); - use_default_colors(); - ESCDELAY=25; - - prompt_func = prompt; - get_key_func = get_key; -} - -void deinit() -{ - endwin(); -} - -} - } diff --git a/src/ncurses.hh b/src/ncurses.hh index a262f6a2..640b0fd5 100644 --- a/src/ncurses.hh +++ b/src/ncurses.hh @@ -1,30 +1,26 @@ #ifndef ncurses_hh_INCLUDED #define ncurses_hh_INCLUDED -#include - -#include "keys.hh" -#include "completion.hh" +#include "ui.hh" namespace Kakoune { -class Window; - -typedef std::function PromptFunc; -typedef std::function GetKeyFunc; - -struct prompt_aborted {}; - -namespace NCurses +class NCursesUI : public UI { +public: + NCursesUI(); + ~NCursesUI(); -void init(PromptFunc& prompt_func, GetKeyFunc& get_key_func); -void deinit(); -void draw_window(Window& window); -void print_status(const String& status); + NCursesUI(const NCursesUI&) = delete; + NCursesUI& operator=(const NCursesUI&) = delete; -} + void draw_window(Window& window); + void print_status(const String& status); + + String prompt(const String& prompt, Completer completer); + Key get_key(); +}; } diff --git a/src/ui.cc b/src/ui.cc new file mode 100644 index 00000000..319c9a35 --- /dev/null +++ b/src/ui.cc @@ -0,0 +1,35 @@ +#include "ui.hh" + +#include "window.hh" + +namespace Kakoune +{ + +UI* current_ui = nullptr; + +void draw_editor_ifn(Editor& editor) +{ + Window* window = dynamic_cast(&editor); + if (current_ui and window) + current_ui->draw_window(*window); +} + +String prompt(const String& text, Completer completer) +{ + assert(current_ui); + return current_ui->prompt(text, completer); +} + +Key get_key() +{ + assert(current_ui); + return current_ui->get_key(); +} + +void print_status(const String& status) +{ + assert(current_ui); + return current_ui->print_status(status); +} + +} diff --git a/src/ui.hh b/src/ui.hh new file mode 100644 index 00000000..d7ca510a --- /dev/null +++ b/src/ui.hh @@ -0,0 +1,37 @@ +#ifndef ui_hh_INCLUDED +#define ui_hh_INCLUDED + +#include "keys.hh" +#include "completion.hh" + +namespace Kakoune +{ + +class Editor; +class Window; +class String; + +class UI +{ +public: + virtual ~UI() {} + + virtual void draw_window(Window& window) = 0; + virtual void print_status(const String& status) = 0; + virtual String prompt(const String& prompt, Completer completer) = 0; + virtual Key get_key() = 0; +}; + +struct prompt_aborted {}; + +extern UI* current_ui; + +void draw_editor_ifn(Editor& editor); +String prompt(const String& text, Completer completer = complete_nothing); +Key get_key(); +void print_status(const String& status); + +} + +#endif // ui_hh_INCLUDED +