From d470bd2cc9d5fb4081f998c752b8207deef857f8 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 14 Feb 2017 00:02:01 +0000 Subject: [PATCH] Make numeric registers setable Fixes #1214 --- src/commands.cc | 21 ++++++------------ src/context.cc | 2 +- src/input_handler.cc | 5 +++-- src/main.cc | 13 ++++++++++++ src/normal.cc | 40 +++++++++++++++++------------------ src/register_manager.hh | 47 +++++++++++++++++++++++------------------ 6 files changed, 71 insertions(+), 57 deletions(-) diff --git a/src/commands.cc b/src/commands.cc index 65a0b752..8d98e1e0 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -1487,32 +1487,24 @@ private: class RegisterRestorer { public: - RegisterRestorer(char name, const Context& context) - : m_name(name) + RegisterRestorer(char name, Context& context) + : m_context{context}, m_name{name} { - ConstArrayView save = RegisterManager::instance()[name].values(context); + ConstArrayView save = RegisterManager::instance()[name].get(context); m_save = Vector(save.begin(), save.end()); } RegisterRestorer(RegisterRestorer&& other) noexcept - : m_save(std::move(other.m_save)), m_name(other.m_name) + : m_context{other.m_context}, m_save{std::move(other.m_save)}, m_name{other.m_name} { other.m_name = 0; } - RegisterRestorer& operator=(RegisterRestorer&& other) noexcept - { - m_save = std::move(other.m_save); - m_name = other.m_name; - other.m_name = 0; - return *this; - } - ~RegisterRestorer() { if (m_name != 0) try { - RegisterManager::instance()[m_name] = m_save; + RegisterManager::instance()[m_name].set(m_context, m_save); } catch (runtime_error& e) { @@ -1523,6 +1515,7 @@ public: private: Vector m_save; + Context& m_context; char m_name; }; @@ -2012,7 +2005,7 @@ const CommandDesc set_register_cmd = { CommandCompleter{}, [](const ParametersParser& parser, Context& context, const ShellContext&) { - RegisterManager::instance()[parser[0]] = ConstArrayView(parser[1]); + RegisterManager::instance()[parser[0]].set(context, {parser[1]}); } }; diff --git a/src/context.cc b/src/context.cc index dc8086fa..8d225052 100644 --- a/src/context.cc +++ b/src/context.cc @@ -211,7 +211,7 @@ void Context::end_edition() StringView Context::main_sel_register_value(StringView reg) const { - auto strings = RegisterManager::instance()[reg].values(*this); + auto strings = RegisterManager::instance()[reg].get(*this); size_t index = m_selections ? (*m_selections).main_index() : 0; if (strings.size() <= index) index = strings.size() - 1; diff --git a/src/input_handler.cc b/src/input_handler.cc index b112f7ad..3c72e66d 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1124,7 +1124,7 @@ public: on_next_key_with_autoinfo(context(), KeymapMode::None, [this](Key key, Context&) { if (auto cp = key.codepoint()) - insert(RegisterManager::instance()[*cp].values(context())); + insert(RegisterManager::instance()[*cp].get(context())); }, "Enter register name", register_doc); update_completions = false; } @@ -1491,7 +1491,8 @@ void InputHandler::stop_recording() kak_assert(m_recording_reg != 0); if (not m_recorded_keys.empty()) - RegisterManager::instance()[m_recording_reg] = {m_recorded_keys}; + RegisterManager::instance()[m_recording_reg].set( + context(), {m_recorded_keys}); m_recording_reg = 0; m_recording_level = -1; diff --git a/src/main.cc b/src/main.cc index 7aba8f26..09902b5d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -186,6 +186,19 @@ void register_registers() for (auto& sel : context.selections()) result.emplace_back(i < sel.captures().size() ? sel.captures()[i] : ""); return result; + }, + [i](Context& context, ConstArrayView values) { + if (values.empty()) + return; + + auto& sels = context.selections(); + for (size_t sel_index = 0; sel_index < sels.size(); ++sel_index) + { + auto& sel = sels[sel_index]; + if (sel.captures().size() < i+1) + sel.captures().resize(i+1); + sel.captures()[i] = values[std::min(sel_index, values.size()-1)]; + } })); } diff --git a/src/normal.cc b/src/normal.cc index 6a34f6ac..3f816b02 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -417,7 +417,7 @@ void pipe(Context& context, NormalParams) real_cmd = context.main_sel_register_value("|"); else { - RegisterManager::instance()['|'] = cmdline.str(); + RegisterManager::instance()['|'].set(context, cmdline.str()); real_cmd = cmdline; } @@ -479,7 +479,7 @@ void insert_output(Context& context, NormalParams) real_cmd = context.main_sel_register_value("|"); else { - RegisterManager::instance()['|'] = cmdline.str(); + RegisterManager::instance()['|'].set(context, cmdline.str()); real_cmd = cmdline; } @@ -496,7 +496,7 @@ void insert_output(Context& context, NormalParams) void yank(Context& context, NormalParams params) { const char reg = params.reg ? params.reg : '"'; - RegisterManager::instance()[reg] = context.selections_content(); + RegisterManager::instance()[reg].set(context, context.selections_content()); context.print_status({ format("yanked {} selections to register {}", context.selections().size(), reg), get_face("Information") }); @@ -505,7 +505,7 @@ void yank(Context& context, NormalParams params) void erase_selections(Context& context, NormalParams params) { const char reg = params.reg ? params.reg : '"'; - RegisterManager::instance()[reg] = context.selections_content(); + RegisterManager::instance()[reg].set(context, context.selections_content()); ScopedEdition edition(context); context.selections().erase(); context.selections().avoid_eol(); @@ -514,7 +514,7 @@ void erase_selections(Context& context, NormalParams params) void change(Context& context, NormalParams params) { const char reg = params.reg ? params.reg : '"'; - RegisterManager::instance()[reg] = context.selections_content(); + RegisterManager::instance()[reg].set(context, context.selections_content()); enter_insert_mode(context, params); } @@ -533,7 +533,7 @@ template void paste(Context& context, NormalParams params) { const char reg = params.reg ? params.reg : '"'; - auto strings = RegisterManager::instance()[reg].values(context); + auto strings = RegisterManager::instance()[reg].get(context); const bool linewise = contains_that(strings, [](StringView str) { return not str.empty() and str.back() == '\n'; }); @@ -547,7 +547,7 @@ template void paste_all(Context& context, NormalParams params) { const char reg = params.reg ? params.reg : '"'; - auto strings = RegisterManager::instance()[reg].values(context); + auto strings = RegisterManager::instance()[reg].get(context); InsertMode effective_mode = mode; String all; Vector offsets; @@ -645,7 +645,7 @@ void search(Context& context, NormalParams params) const char reg = to_lower(params.reg ? params.reg : '/'); const int count = params.count; - auto reg_content = RegisterManager::instance()[reg].values(context); + auto reg_content = RegisterManager::instance()[reg].get(context); Vector saved_reg{reg_content.begin(), reg_content.end()}; const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1); @@ -654,13 +654,13 @@ void search(Context& context, NormalParams params) (Regex regex, PromptEvent event, Context& context) { if (event == PromptEvent::Abort) { - RegisterManager::instance()[reg] = saved_reg; + RegisterManager::instance()[reg].set(context, saved_reg); return; } if (regex.empty()) regex = Regex{saved_reg[main_index]}; - RegisterManager::instance()[reg] = regex.str(); + RegisterManager::instance()[reg].set(context, regex.str()); if (not regex.empty() and not regex.str().empty()) { @@ -741,7 +741,7 @@ void use_selection_as_search_pattern(Context& context, NormalParams params) format("register '{}' set to '{}'", reg, patterns[sels.main_index()]), get_face("Information") }); - RegisterManager::instance()[reg] = patterns; + RegisterManager::instance()[reg].set(context, patterns); // Hack, as Window do not take register state into account if (context.has_window()) @@ -754,7 +754,7 @@ void select_regex(Context& context, NormalParams params) const int capture = params.count; auto prompt = capture ? format("select (capture {}):", capture) : "select:"_str; - auto reg_content = RegisterManager::instance()[reg].values(context); + auto reg_content = RegisterManager::instance()[reg].get(context); Vector saved_reg{reg_content.begin(), reg_content.end()}; const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1); @@ -762,13 +762,13 @@ void select_regex(Context& context, NormalParams params) [reg, capture, saved_reg, main_index](Regex ex, PromptEvent event, Context& context) { if (event == PromptEvent::Abort) { - RegisterManager::instance()[reg] = saved_reg; + RegisterManager::instance()[reg].set(context, saved_reg); return; } if (ex.empty()) ex = Regex{saved_reg[main_index]}; - RegisterManager::instance()[reg] = ex.str(); + RegisterManager::instance()[reg].set(context, ex.str()); if (not ex.empty() and not ex.str().empty()) select_all_matches(context.selections(), ex, capture); @@ -781,7 +781,7 @@ void split_regex(Context& context, NormalParams params) const int capture = params.count; auto prompt = capture ? format("split (on capture {}):", (int)capture) : "split:"_str; - auto reg_content = RegisterManager::instance()[reg].values(context); + auto reg_content = RegisterManager::instance()[reg].get(context); Vector saved_reg{reg_content.begin(), reg_content.end()}; const int main_index = std::min(context.selections().main_index(), saved_reg.size()-1); @@ -789,13 +789,13 @@ void split_regex(Context& context, NormalParams params) [reg, capture, saved_reg, main_index](Regex ex, PromptEvent event, Context& context) { if (event == PromptEvent::Abort) { - RegisterManager::instance()[reg] = saved_reg; + RegisterManager::instance()[reg].set(context, saved_reg); return; } if (ex.empty()) ex = Regex{saved_reg[main_index]}; - RegisterManager::instance()[reg] = ex.str(); + RegisterManager::instance()[reg].set(context, ex.str()); if (not ex.empty() and not ex.str().empty()) split_selections(context.selections(), ex, capture); @@ -1254,7 +1254,7 @@ void replay_macro(Context& context, NormalParams params) if (running_macros[idx]) throw runtime_error("recursive macros call detected"); - ConstArrayView reg_val = RegisterManager::instance()[reg].values(context); + ConstArrayView reg_val = RegisterManager::instance()[reg].get(context); if (reg_val.empty() or reg_val[0].empty()) throw runtime_error(format("Register '{}' is empty", reg)); @@ -1445,7 +1445,7 @@ SelectionList read_selections_from_register(char reg, Context& context) if (not is_basic_alpha(reg) and reg != '^') throw runtime_error("selections can only be saved to the '^' and alphabetic registers"); - auto content = RegisterManager::instance()[reg].values(context); + auto content = RegisterManager::instance()[reg].get(context); if (content.size() != 1) throw runtime_error(format("Register {} does not contain a selections desc", reg)); @@ -1496,7 +1496,7 @@ void save_selections(Context& context, NormalParams params) context.buffer().name(), context.buffer().timestamp()); - RegisterManager::instance()[reg] = desc; + RegisterManager::instance()[reg].set(context, desc); context.print_status({format("{} selections to register '{}'", add ? "Added" : "Saved", reg), get_face("Information")}); } diff --git a/src/register_manager.hh b/src/register_manager.hh index d5bc1ec3..4a8e7f2c 100644 --- a/src/register_manager.hh +++ b/src/register_manager.hh @@ -17,9 +17,9 @@ class Register { public: virtual ~Register() = default; - virtual Register& operator=(ConstArrayView values) = 0; - virtual ConstArrayView values(const Context& context) = 0; + virtual void set(Context& context, ConstArrayView values) = 0; + virtual ConstArrayView get(const Context& context) = 0; }; // static value register, which can be modified @@ -27,13 +27,12 @@ public: class StaticRegister : public Register { public: - Register& operator=(ConstArrayView values) override + void set(Context&, ConstArrayView values) override { m_content = Vector(values.begin(), values.end()); - return *this; } - ConstArrayView values(const Context&) override + ConstArrayView get(const Context&) override { if (m_content.empty()) return ConstArrayView(String::ms_empty); @@ -46,43 +45,51 @@ protected: // Dynamic value register, use it's RegisterRetriever // to get it's value when needed. -template +template class DynamicRegister : public StaticRegister { public: - DynamicRegister(Func function) - : m_function(std::move(function)) {} + DynamicRegister(Getter getter, Setter setter) + : m_getter{std::move(getter)}, m_setter{std::move(setter)} {} - Register& operator=(ConstArrayView values) override + void set(Context& context, ConstArrayView values) override { - throw runtime_error("this register is not assignable"); + m_setter(context, values); } - ConstArrayView values(const Context& context) override + ConstArrayView get(const Context& context) override { - m_content = m_function(context); - return StaticRegister::values(context); + m_content = m_getter(context); + return StaticRegister::get(context); } private: - Func m_function; + Getter m_getter; + Setter m_setter; }; template std::unique_ptr make_dyn_reg(Func func) { - return make_unique>(std::move(func)); + auto setter = [](Context&, ConstArrayView) + { + throw runtime_error("this register is not assignable"); + }; + return make_unique>(std::move(func), setter); +} + +template +std::unique_ptr make_dyn_reg(Getter getter, Setter setter) +{ + return make_unique>(std::move(getter), std::move(setter)); } class NullRegister : public Register { public: - Register& operator=(ConstArrayView values) override - { - return *this; - } + void set(Context&, ConstArrayView) override {} - ConstArrayView values(const Context& context) override + ConstArrayView get(const Context&) override { return ConstArrayView(String::ms_empty); }