Fix for Boost 1.78

New Boost does not revert iterators in some cases, so reverting must be
done manually.

About the command_completion change: I have no idea, but the 1.77 fix
works for 1.78.

This actually needs this patch
https://github.com/boostorg/spirit/pull/711. No idea how to inject that
to the CI.

Issue: https://github.com/boostorg/spirit/issues/703#issuecomment-1011021773
Change-Id: I2d1266b1f8b893f180ae36842bdfdb35c5629ea4
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 288801d..352824e 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -16,6 +16,9 @@
 #include "ast_commands.hpp"
 #include "parser_context.hpp"
 #include "schema.hpp"
+#if BOOST_VERSION >= 107800
+#include "UniqueResource.hpp"
+#endif
 #include "utils.hpp"
 namespace x3 = boost::spirit::x3;
 
@@ -153,10 +156,30 @@
     }
 };
 
+#if BOOST_VERSION >= 107800
+template <typename Iterator>
+[[nodiscard]] auto makeIteratorRollbacker(Iterator const& was, Iterator& will, bool& passFlag)
+{
+    return make_unique_resource([] {},
+    [&was, &will, &passFlag] {
+        if (!passFlag) {
+            will = was;
+        }
+    });
+}
+#endif
+
 struct presenceContainerPath_class {
     template <typename T, typename Iterator, typename Context>
+#if BOOST_VERSION >= 107800
+    void on_success(Iterator const& was, Iterator& will, T& ast, Context const& context)
+#else
     void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
+#endif
     {
+#if BOOST_VERSION >= 107800
+        auto rollback = makeIteratorRollbacker(was, will, _pass(context));
+#endif
         auto& parserContext = x3::get<parser_context_tag>(context);
         const auto& schema = parserContext.m_schema;
         if (ast.m_nodes.empty()) {
@@ -174,8 +197,15 @@
 
 struct listInstancePath_class {
     template <typename T, typename Iterator, typename Context>
+#if BOOST_VERSION >= 107800
+    void on_success(Iterator const& was, Iterator& will, T& ast, Context const& context)
+#else
     void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
+#endif
     {
+#if BOOST_VERSION >= 107800
+        auto rollback = makeIteratorRollbacker(was, will, _pass(context));
+#endif
         auto& parserContext = x3::get<parser_context_tag>(context);
         if (ast.m_nodes.empty() || !std::holds_alternative<listElement_>(ast.m_nodes.back().m_suffix)) {
             parserContext.m_errorMsg = "This is not a list instance.";
@@ -186,8 +216,15 @@
 
 struct leafListElementPath_class {
     template <typename T, typename Iterator, typename Context>
+#if BOOST_VERSION >= 107800
+    void on_success(Iterator const& was, Iterator& will, T& ast, Context const& context)
+#else
     void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
+#endif
     {
+#if BOOST_VERSION >= 107800
+        auto rollback = makeIteratorRollbacker(was, will, _pass(context));
+#endif
         auto& parserContext = x3::get<parser_context_tag>(context);
         if (ast.m_nodes.empty() || !std::holds_alternative<leafListElement_>(ast.m_nodes.back().m_suffix)) {
             parserContext.m_errorMsg = "This is not a leaf list element.";
@@ -379,10 +416,17 @@
 
 struct createCommandSuggestions_class {
     template <typename T, typename Iterator, typename Context>
-    void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
+#if BOOST_VERSION >= 107800
+    void on_success(Iterator const& was, Iterator& will, T&, Context const& context)
+#else
+    void on_success(Iterator const& was, Iterator const&, T&, Context const& context)
+#endif
     {
+#if BOOST_VERSION >= 107800
+        auto rollback = makeIteratorRollbacker(was, will, _pass(context));
+#endif
         auto& parserContext = x3::get<parser_context_tag>(context);
-        parserContext.m_completionIterator = begin;
+        parserContext.m_completionIterator = was;
 
         parserContext.m_suggestions.clear();
         boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([&parserContext](auto cmd) {
diff --git a/src/grammars.hpp b/src/grammars.hpp
index 6d7f11b..a6df5c9 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -346,7 +346,7 @@
     x3::eps;
 
 auto const command_def =
-#if BOOST_VERSION <= 107700
+#if BOOST_VERSION <= 107800
     x3::eps >>
 #endif
     createCommandSuggestions >> x3::expect[cd | copy | create | delete_rule | set | commit | get | ls | discard | describe | help | move | dump | prepare | exec | cancel | switch_rule];
diff --git a/tests/command_completion.cpp b/tests/command_completion.cpp
index 8e8570f..96b115b 100644
--- a/tests/command_completion.cpp
+++ b/tests/command_completion.cpp
@@ -19,6 +19,7 @@
     std::ostringstream errorStream;
     std::set<std::string> expectedCompletions;
     int expectedContextLength;
+
     SECTION("no prefix")
     {
         expectedCompletions = {"cd", "copy", "create", "delete", "set", "commit", "get", "ls", "discard", "help", "describe", "move", "dump", "prepare", "exec", "cancel", "switch"};