diff --git a/src/normal.cc b/src/normal.cc index 42214a6e..f8097645 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -414,13 +414,10 @@ void replace_with_char(Context& context, NormalParams) ScopedEdition edition(context); Buffer& buffer = context.buffer(); SelectionList& selections = context.selections(); - Vector strings; - for (auto& sel : selections) - { - CharCount count = char_length(buffer, sel); - strings.emplace_back(*cp, count); - } - selections.insert(strings, InsertMode::Replace); + selections.insert([&](size_t index, BufferCoord) { + CharCount count = char_length(buffer, selections[index]); + return String{*cp, count}; + }, InsertMode::Replace); }, "replace with char", "enter char to replace with\n"); } @@ -438,18 +435,16 @@ void for_each_codepoint(Context& context, NormalParams) ScopedEdition edition(context); Buffer& buffer = context.buffer(); SelectionList& selections = context.selections(); - Vector strings; - for (auto& sel : selections) - { + + selections.insert([&](size_t index, BufferCoord) { + auto& sel = selections[index]; String str; for (auto begin = Utf8It{buffer.iterator_at(sel.min()), buffer}, end = Utf8It{buffer.iterator_at(sel.max()), buffer}+1; begin != end; ++begin) utf8::dump(std::back_inserter(str), func(*begin)); - - strings.push_back(std::move(str)); - } - selections.insert(strings, InsertMode::Replace); + return str; + }, InsertMode::Replace); } void command(const Context& context, EnvVarMap env_vars, char reg = 0) @@ -649,15 +644,15 @@ void insert_output(Context& context, NormalParams params) auto& selections = context.selections(); const size_t old_main = selections.main_index(); - auto ins = selections | transform([&, i=0](auto& sel) mutable { - selections.set_main_index(i++); - return ShellManager::instance().eval( - cmdline, context, content(context.buffer(), sel), - ShellManager::Flags::WaitForStdout).first; - }) | gather(); + selections.insert([&](size_t index, BufferCoord) { + selections.set_main_index(index); + auto [out, status] = ShellManager::instance().eval( + cmdline, context, content(context.buffer(), selections[index]), + ShellManager::Flags::WaitForStdout); + return out; + }, mode); selections.set_main_index(old_main); - selections.insert(ins, mode); }); } @@ -741,7 +736,10 @@ void paste_all(Context& context, NormalParams params) auto& selections = context.selections(); { ScopedEdition edition(context); - selections.insert(all, effective_mode, &insert_pos); + selections.insert([&](size_t, BufferCoord pos) { + insert_pos.push_back(pos); + return String::no_copy(all); + }, effective_mode); } const Buffer& buffer = context.buffer(); diff --git a/src/selection.cc b/src/selection.cc index 350b3acc..a552526d 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -385,12 +385,18 @@ static void fix_overflowing_selections(Vector& selections, } } -void SelectionList::insert(ConstArrayView strings, InsertMode mode, - Vector* out_insert_pos) +void SelectionList::insert(ConstArrayView strings, InsertMode mode) { if (strings.empty()) return; + insert([&](size_t index, BufferCoord) { + return String::no_copy(strings[std::min(strings.size()-1, index)]); + }, mode); +} + +void SelectionList::insert(ContentFunc get_content, InsertMode mode) +{ update(); Vector insert_pos; @@ -410,11 +416,11 @@ void SelectionList::insert(ConstArrayView strings, InsertMode mode, kak_assert(m_buffer->is_valid(sel.anchor()) and m_buffer->is_valid(sel.cursor())); - const String& str = strings[std::min(index, strings.size()-1)]; - const auto pos = (mode == InsertMode::Replace) ? sel.min() : changes_tracker.get_new_coord(insert_pos[index]); + String str = get_content(index, pos); + if (mode == InsertMode::Replace) { auto range = replace(*m_buffer, sel, str); @@ -432,8 +438,6 @@ void SelectionList::insert(ConstArrayView strings, InsertMode mode, } changes_tracker.update(*m_buffer, m_timestamp); - if (out_insert_pos) - out_insert_pos->push_back(pos); } // We might just have been deleting text if strings were empty, diff --git a/src/selection.hh b/src/selection.hh index c880aaf7..3c6d879d 100644 --- a/src/selection.hh +++ b/src/selection.hh @@ -145,8 +145,9 @@ struct SelectionList size_t timestamp() const { return m_timestamp; } void force_timestamp(size_t timestamp) { m_timestamp = timestamp; } - void insert(ConstArrayView strings, InsertMode mode, - Vector* out_insert_pos = nullptr); + void insert(ConstArrayView strings, InsertMode mode); + using ContentFunc = FunctionRef; + void insert(ContentFunc get_content, InsertMode mode); void erase(); private: diff --git a/src/string.hh b/src/string.hh index 6fa425e5..d14929f4 100644 --- a/src/string.hh +++ b/src/string.hh @@ -124,6 +124,8 @@ public: struct NoCopy{}; String(NoCopy, StringView str); + static String no_copy(StringView str); + [[gnu::always_inline]] char* data() { return m_data.data(); } @@ -274,6 +276,7 @@ template<> struct HashCompatible : std::true_type {}; inline String::String(StringView str) : String{str.begin(), str.length()} {} inline String::String(NoCopy, StringView str) : m_data{NoCopy{}, str.begin(), (size_t)str.length()} {} +inline String String::no_copy(StringView str) { return {NoCopy{}, str}; } template inline StringView StringOps::substr(ByteCount from, ByteCount length) const diff --git a/src/utils.hh b/src/utils.hh index 31781907..8dffa9ac 100644 --- a/src/utils.hh +++ b/src/utils.hh @@ -173,7 +173,11 @@ public: }} {} - template>>> + template> and + std::is_convertible_v()(std::declval()...)), Res> + >> FunctionRef(Target&& target) : m_target{&target}, m_invoker{[](void* target, Args... args) {