From 8b6eba82088b64d8685afd4bfc0722d8a3b1d617 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 11 Oct 2016 00:20:36 +0100 Subject: [PATCH] Add support for repeating the last object/char find command This is a potential solution for #794. --- src/context.hh | 9 +++++++ src/normal.cc | 69 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/context.hh b/src/context.hh index a0fec133..f2dfe4d5 100644 --- a/src/context.hh +++ b/src/context.hh @@ -70,6 +70,8 @@ private: size_t m_current = 0; }; +using LastSelectFunc = std::function; + // A Context is used to access non singleton objects for various services // in commands. // @@ -150,6 +152,11 @@ public: JumpList& jump_list() { return m_jump_list; } void push_jump() { m_jump_list.push(selections()); } + template + void set_last_select(Func&& last_select) { m_last_select = std::forward(last_select); } + + void repeat_last_select() { if (m_last_select) m_last_select(*this); } + private: void begin_edition(); void end_edition(); @@ -169,6 +176,8 @@ private: JumpList m_jump_list; + LastSelectFunc m_last_select; + NestedBool m_hooks_disabled; NestedBool m_keymaps_disabled; NestedBool m_history_disabled; diff --git a/src/normal.cc b/src/normal.cc index e9c37f14..a22a4c91 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -70,6 +70,14 @@ void select(Context& context, NormalParams) select(context, func); } +template +void select_and_set_last(Context& context, Func&& func) +{ + context.set_last_select( + [func](Context& context){ select(context, func); }); + return select(context, func); +} + template void select_coord(Buffer& buffer, BufferCoord coord, SelectionList& selections) { @@ -95,6 +103,11 @@ void repeat_last_insert(Context& context, NormalParams) context.input_handler().repeat_last_insert(); } +void repeat_last_select(Context& context, NormalParams) +{ + context.repeat_last_select(); +} + template void goto_commands(Context& context, NormalParams params) { @@ -432,7 +445,7 @@ void insert_output(Context& context, NormalParams) { const char* prompt = mode == InsertMode::Insert ? "insert-output:" : "append-output:"; context.input_handler().prompt( - prompt, "", get_face("Prompt"), + prompt, "", get_face("Prompt"), PromptFlags::DropHistoryEntriesWithBlankPrefix, shell_complete, [](StringView cmdline, PromptEvent event, Context& context) { @@ -944,7 +957,7 @@ void select_object(Context& context, NormalParams params) if (cp == -1) return; - static constexpr struct + static constexpr struct ObjectType { Codepoint key; Selection (*func)(const Buffer&, const Selection&, int, ObjectFlags); @@ -958,11 +971,10 @@ void select_object(Context& context, NormalParams params) { 'n', select_number }, { 'u', select_argument }, }; - for (auto& sel : selectors) - { - if (cp == sel.key) - return select(context, std::bind(sel.func, _1, _2, count, flags)); - } + auto obj_it = find(selectors | transform(std::mem_fn(&ObjectType::key)), cp).base(); + if (obj_it != std::end(selectors)) + return select_and_set_last( + context, std::bind(obj_it->func, _1, _2, count, flags)); if (cp == ':') { @@ -983,13 +995,15 @@ void select_object(Context& context, NormalParams params) if (params.size() != 2) throw runtime_error{"desc parsing failed, expected ,"}; - return select(context, std::bind(select_surrounding, _1, _2, - params[0], params[1], count, flags)); + select_and_set_last( + context, std::bind(select_surrounding, _1, _2, + params[0], params[1], + count, flags)); }); return; } - static constexpr struct + static constexpr struct SurroundingPair { StringView opening; StringView closing; @@ -1003,22 +1017,24 @@ void select_object(Context& context, NormalParams params) { "'", "'", 'q' }, { "`", "`", 'g' }, }; - for (auto& sur : surrounding_pairs) - { - if (sur.opening[0_char] == cp or - sur.closing[0_char] == cp or - (sur.name != 0 and sur.name == cp)) - return select(context, std::bind(select_surrounding, _1, _2, - sur.opening, sur.closing, - count, flags)); - } + auto pair_it = find_if(surrounding_pairs, + [cp](const SurroundingPair& s) { + return s.opening[0_char] == cp or + s.closing[0_char] == cp or + (s.name != 0 and s.name == cp); + }); + if (pair_it != std::end(surrounding_pairs)) + return select_and_set_last( + context, std::bind(select_surrounding, _1, _2, + pair_it->opening, pair_it->closing, + count, flags)); if (is_punctuation(cp)) { auto utf8cp = to_string(cp); - return select(context, std::bind(select_surrounding, _1, _2, - utf8cp, utf8cp, - count, flags)); + return select_and_set_last( + context, std::bind(select_surrounding, _1, _2, + utf8cp, utf8cp, count, flags)); } }, get_title(), "b,(,): parenthesis block\n" @@ -1133,10 +1149,12 @@ void select_to_next_char(Context& context, NormalParams params) constexpr auto new_flags = flags & SelectFlags::Extend ? SelectMode::Extend : SelectMode::Replace; if (auto cp = key.codepoint()) - select( + select_and_set_last( context, - std::bind(flags & SelectFlags::Reverse ? select_to_reverse : select_to, - _1, _2, *cp, params.count, flags & SelectFlags::Inclusive)); + std::bind(flags & SelectFlags::Reverse ? select_to_reverse + : select_to, + _1, _2, *cp, params.count, + flags & SelectFlags::Inclusive)); }, get_title(),"enter char to select to"); } @@ -1658,6 +1676,7 @@ static NormalCmdDesc cmds[] = { alt('s'), "split selected text on line ends", split_lines }, { '.', "repeat last insert command", repeat_last_insert }, + { alt('.'), "repeat last object select/character find", repeat_last_select }, { '%', "select whole buffer", select_whole_buffer },