Merge "Fix some namespace formatting"
diff --git a/src/ast_commands.cpp b/src/ast_commands.cpp
index 74aefd5..aa4756a 100644
--- a/src/ast_commands.cpp
+++ b/src/ast_commands.cpp
@@ -14,7 +14,7 @@
 
 bool get_::operator==(const get_& b) const
 {
-    return this->m_path == b.m_path;
+    return this->m_path == b.m_path && this->m_dsTarget == b.m_dsTarget;
 }
 
 bool cd_::operator==(const cd_& b) const
diff --git a/src/ast_commands.hpp b/src/ast_commands.hpp
index 0d7a476..0a474f0 100644
--- a/src/ast_commands.hpp
+++ b/src/ast_commands.hpp
@@ -152,6 +152,7 @@
         /> get
         /> get /module:path)";
     bool operator==(const get_& b) const;
+    boost::optional<DatastoreTarget> m_dsTarget;
     boost::optional<boost::variant<dataPath_, module_>> m_path;
 };
 
@@ -360,7 +361,7 @@
 BOOST_FUSION_ADAPT_STRUCT(describe_, m_path)
 BOOST_FUSION_ADAPT_STRUCT(help_, m_cmd)
 BOOST_FUSION_ADAPT_STRUCT(discard_)
-BOOST_FUSION_ADAPT_STRUCT(get_, m_path)
+BOOST_FUSION_ADAPT_STRUCT(get_, m_dsTarget, m_path)
 BOOST_FUSION_ADAPT_STRUCT(copy_, m_source, m_destination)
 BOOST_FUSION_ADAPT_STRUCT(move_, m_source, m_destination)
 BOOST_FUSION_ADAPT_STRUCT(dump_, m_format)
diff --git a/src/datastore_access.cpp b/src/datastore_access.cpp
index eba90e0..e421274 100644
--- a/src/datastore_access.cpp
+++ b/src/datastore_access.cpp
@@ -31,6 +31,11 @@
     }
 }
 
+DatastoreTarget DatastoreAccess::target() const
+{
+    return m_target;
+}
+
 void DatastoreAccess::setTarget(const DatastoreTarget target)
 {
     m_target = target;
diff --git a/src/datastore_access.hpp b/src/datastore_access.hpp
index 3012a7e..a718f14 100644
--- a/src/datastore_access.hpp
+++ b/src/datastore_access.hpp
@@ -57,6 +57,7 @@
     virtual void deleteItem(const std::string& path) = 0;
     virtual void moveItem(const std::string& path, std::variant<yang::move::Absolute, yang::move::Relative> move) = 0;
     virtual Tree execute(const std::string& path, const Tree& input) = 0;
+    DatastoreTarget target() const;
     void setTarget(const DatastoreTarget target);
 
     virtual std::shared_ptr<Schema> schema() = 0;
diff --git a/src/grammars.hpp b/src/grammars.hpp
index fd01b5b..4e3b97c 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -15,6 +15,25 @@
 #include "leaf_data.hpp"
 #include "path_parser.hpp"
 
+/**
+ * Returns a parser that generates suggestions based on a Completion set.
+ * Usage:
+ * const auto suggestSomeStuff = staticSuggestions({"some", "stuff", "yay"});
+ *
+ * You can use this as a standard parser in a Spirit grammar.
+ */
+auto staticSuggestions(const std::initializer_list<std::string>& strings)
+{
+    std::set<Completion> completions;
+    std::transform(begin(strings), end(strings), std::inserter(completions, completions.end()),
+            [](const auto s) { return Completion{s, " "}; });
+    return as<x3::unused_type>[x3::eps[([completions](auto& ctx) {
+        auto& parserContext = x3::get<parser_context_tag>(ctx);
+        parserContext.m_suggestions = completions;
+        parserContext.m_completionIterator = _where(ctx).begin();
+    })]];
+}
+
 #if BOOST_VERSION <= 107700
 namespace boost::spirit::x3::traits {
     // Backport https://github.com/boostorg/spirit/pull/702
@@ -111,8 +130,22 @@
     delete_::name >> space_separator > (presenceContainerPath | listInstancePath | leafListElementPath | writableLeafPath);
 #endif
 
+const auto dsTargetSuggestions = staticSuggestions({"running", "startup", "operational"});
+
+struct ds_target_table : x3::symbols<DatastoreTarget> {
+    ds_target_table()
+    {
+        add
+            ("operational", DatastoreTarget::Operational)
+            ("startup", DatastoreTarget::Startup)
+            ("running", DatastoreTarget::Running);
+    }
+} const ds_target_table;
+
 auto const get_def =
-    get_::name >> -(space_separator >> getPath);
+    get_::name
+    >> -(space_separator >> "-" > staticSuggestions({"-datastore"}) > "-datastore" > space_separator > dsTargetSuggestions > ds_target_table)
+    >> -(space_separator >> getPath);
 
 auto const set_def =
     set_::name >> space_separator > writableLeafPath > space_separator > leaf_data;
@@ -147,11 +180,7 @@
 const auto copy_source = x3::rule<class source, Datastore>{"source datastore"} = datastore;
 const auto copy_destination = x3::rule<class source, Datastore>{"destination datastore"} = datastore;
 
-const auto datastoreSuggestions = x3::eps[([](auto& ctx) {
-    auto& parserContext = x3::get<parser_context_tag>(ctx);
-    parserContext.m_suggestions = {Completion{"running", " "}, Completion{"startup", " "}};
-    parserContext.m_completionIterator = _where(ctx).begin();
-})];
+const auto datastoreSuggestions = staticSuggestions({"running", "startup"});
 
 struct copy_args : x3::parser<copy_args> {
     using attribute_type = copy_;
@@ -316,24 +345,8 @@
 auto const exec_def =
     exec_::name > -(space_separator > -as<dataPath_>[RpcActionPath<AllowInput::No>{}]);
 
-const auto dsTargetSuggestions = x3::eps[([](auto& ctx) {
-    auto& parserContext = x3::get<parser_context_tag>(ctx);
-    parserContext.m_suggestions = {Completion{"running", " "}, Completion{"startup", " "}, Completion{"operational", " "}};
-    parserContext.m_completionIterator = _where(ctx).begin();
-})];
-
-struct ds_target_table : x3::symbols<DatastoreTarget> {
-    ds_target_table()
-    {
-        add
-            ("operational", DatastoreTarget::Operational)
-            ("startup", DatastoreTarget::Startup)
-            ("running", DatastoreTarget::Running);
-    }
-} const ds_target_table;
-
 auto const switch_rule_def =
-    switch_::name > space_separator > as<x3::unused_type>[dsTargetSuggestions] > ds_target_table;
+    switch_::name > space_separator > dsTargetSuggestions > ds_target_table;
 
 auto const cancel_def =
     cancel_::name >> x3::attr(cancel_{});
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 8030f3f..0fe96da 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -10,6 +10,7 @@
 #include <boost/mpl/for_each.hpp>
 #include <iostream>
 #include <sstream>
+#include "UniqueResource.hpp"
 #include "datastore_access.hpp"
 #include "interpreter.hpp"
 #include "utils.hpp"
@@ -83,6 +84,14 @@
 
 void Interpreter::operator()(const get_& get) const
 {
+    auto targetSwitcher = make_unique_resource([] {}, [this, oldTarget = m_datastore.target()] {
+        m_datastore.setTarget(oldTarget);
+    });
+
+    if (get.m_dsTarget) {
+        m_datastore.setTarget(*get.m_dsTarget);
+    }
+
     auto items = m_datastore.getItems(pathToString(toCanonicalPath(get.m_path)));
     printTree(items);
 }
diff --git a/src/proxy_datastore.cpp b/src/proxy_datastore.cpp
index 3bd6719..67a3cb3 100644
--- a/src/proxy_datastore.cpp
+++ b/src/proxy_datastore.cpp
@@ -108,6 +108,11 @@
     }
 }
 
+DatastoreTarget ProxyDatastore::target() const
+{
+    return m_datastore->target();
+}
+
 void ProxyDatastore::setTarget(const DatastoreTarget target)
 {
     m_datastore->setTarget(target);
diff --git a/src/proxy_datastore.hpp b/src/proxy_datastore.hpp
index 21fbfc5..20a877d 100644
--- a/src/proxy_datastore.hpp
+++ b/src/proxy_datastore.hpp
@@ -28,6 +28,7 @@
     void discardChanges();
     void copyConfig(const Datastore source, const Datastore destination);
     [[nodiscard]] std::string dump(const DataFormat format) const;
+    DatastoreTarget target() const;
     void setTarget(const DatastoreTarget target);
 
     void initiate(const std::string& path);
diff --git a/tests/init_datastore.bash.in b/tests/init_datastore.bash.in
index d8eb2c3..1e01346 100755
--- a/tests/init_datastore.bash.in
+++ b/tests/init_datastore.bash.in
@@ -21,6 +21,9 @@
 YANG_DIR=$(dirname "$1")
 shift
 
+# Uninstall the module
+"$SYSREPOCTL" --uninstall "$(basename "$MODULE" ".yang")" -v3 || true
+
 # Install the module
 "$SYSREPOCTL" --search-dirs "$YANG_DIR" --install "$MODULE" -v3
 
diff --git a/tests/path_completion.cpp b/tests/path_completion.cpp
index 511d922..be676c9 100644
--- a/tests/path_completion.cpp
+++ b/tests/path_completion.cpp
@@ -213,6 +213,27 @@
             // The expectedContextLength is 13, because the completion isn't actually generated after the slash.
             expectedContextLength = 13;
         }
+
+        SECTION("get -")
+        {
+            input = "get -";
+            expectedCompletions = {"-datastore "};
+            expectedContextLength = 0;
+        }
+
+        SECTION("get --datastore ")
+        {
+            input = "get --datastore ";
+            expectedCompletions = {"operational", "running", "startup"};
+            expectedContextLength = 0;
+        }
+
+        SECTION("get --datastore running /second")
+        {
+            input = "get --datastore running /second";
+            expectedCompletions = {"second:amelie/"};
+            expectedContextLength = 6;
+        }
     }
 
     SECTION("describe completion")