summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2019-05-13 17:33:18 +1000
committerMaxime Coste <mawww@kakoune.org>2019-05-13 17:34:43 +1000
commit91386a535ccecc1d5d9b0fc27223f8d9006750e3 (patch)
tree3c63d1a2788373174cc120467fed52f1684906cb /src
parent3114995857d9ca8a255e04f0dd3582f93e547eeb (diff)
Support discarding selections in exec/eval -itersel
Only fail if all selections are discarded. Fixes #2841
Diffstat (limited to 'src')
-rw-r--r--src/commands.cc30
-rw-r--r--src/normal.cc8
-rw-r--r--src/normal.hh6
3 files changed, 31 insertions, 13 deletions
diff --git a/src/commands.cc b/src/commands.cc
index 51adb80c..b1fe3580 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -1782,26 +1782,38 @@ void context_wrap(const ParametersParser& parser, Context& context, StringView d
Vector<Selection> new_sels;
size_t main = 0;
size_t timestamp = c.buffer().timestamp();
+ bool one_selection_succeeded = false;
for (auto& sel : sels)
{
c.selections_write_only() = SelectionList{sels.buffer(), sel, sels.timestamp()};
c.selections().update();
- func(parser, c);
-
- if (not draft)
+ try
{
+ func(parser, c);
+ one_selection_succeeded = true;
+
if (&sels.buffer() != &c.buffer())
throw runtime_error("buffer has changed while iterating on selections");
- update_selections(new_sels, main, c.buffer(), timestamp);
- timestamp = c.buffer().timestamp();
- if (&sel == &sels.main())
- main = new_sels.size() + c.selections().main_index();
+ if (not draft)
+ {
+ update_selections(new_sels, main, c.buffer(), timestamp);
+ timestamp = c.buffer().timestamp();
+ if (&sel == &sels.main())
+ main = new_sels.size() + c.selections().main_index();
- const auto middle = new_sels.insert(new_sels.end(), c.selections().begin(), c.selections().end());
- std::inplace_merge(new_sels.begin(), middle, new_sels.end(), compare_selections);
+ const auto middle = new_sels.insert(new_sels.end(), c.selections().begin(), c.selections().end());
+ std::inplace_merge(new_sels.begin(), middle, new_sels.end(), compare_selections);
+ }
}
+ catch (no_selections_remaining&) {}
+ }
+
+ if (not one_selection_succeeded)
+ {
+ c.selections_write_only() = std::move(sels);
+ throw no_selections_remaining{};
}
if (not draft)
diff --git a/src/normal.cc b/src/normal.cc
index 1101302b..565f0472 100644
--- a/src/normal.cc
+++ b/src/normal.cc
@@ -113,7 +113,7 @@ void select(Context& context, T func)
}
if (to_remove.size() == selections.size())
- throw runtime_error{"no selections remaining"};
+ throw no_selections_remaining{};
for (auto& i : to_remove | reverse())
selections.remove(i);
}
@@ -1135,7 +1135,7 @@ void keep(Context& context, NormalParams params)
keep.push_back(sel);
}
if (keep.empty())
- throw runtime_error("no selections remaining");
+ throw no_selections_remaining{};
context.selections_write_only() = std::move(keep);
});
}
@@ -1168,7 +1168,7 @@ void keep_pipe(Context& context, NormalParams)
}
}
if (keep.empty())
- throw runtime_error("no selections remaining");
+ throw no_selections_remaining{};
if (new_main == -1)
new_main = keep.size() - 1;
context.selections_write_only().set(std::move(keep), new_main);
@@ -1775,7 +1775,7 @@ void trim_selections(Context& context, NormalParams)
}
if (to_remove.size() == selections.size())
- throw runtime_error{"no selections remaining"};
+ throw no_selections_remaining{};
for (auto& i : to_remove | reverse())
selections.remove(i);
}
diff --git a/src/normal.hh b/src/normal.hh
index 10ee5ffa..e0eb8477 100644
--- a/src/normal.hh
+++ b/src/normal.hh
@@ -5,12 +5,18 @@
#include "keys.hh"
#include "keymap_manager.hh"
#include "string.hh"
+#include "exception.hh"
namespace Kakoune
{
class Context;
+struct no_selections_remaining : runtime_error
+{
+ no_selections_remaining() : runtime_error("no selections remaining") {}
+};
+
struct NormalParams
{
int count;